2019년 11월 3일 일요일

Today expression

It's a little boring here
=> 여긴 조금 지루한 것 같아

How about we go to shopping?
=> 우리 쇼핑 하는 거 어떨까

While you guys do whatever you're doing that I don't know about
=> 너희들이 내가 모르는 무언가를 하는 동안 말이야

Stay in there
=> 거기 계세요 

That could work out perfectly
=> 그거 정말 괜찮겠다. 

We could use the extra time
=> 시간을 벌 수 있겠어?

i'm gonna blindfold her
=> 그녀의 눈을 가릴게요 

Doing good
=> 잘하고 있어요

Little to the left
=> 왼쪽으로 조금만 더 가세요 

And we're here
=> 다왔어요 

Why'd i have to be blindfolded
=> 왜 눈을 가려야 했니?

Hey, Take time 
=> 천천히 와

2019년 10월 28일 월요일

ansible roles 작성

처음 ansible 시작은 
누가 하라고해서 한게 아니다. 
내가 해야할 작업량이 많고, 반복적인 작업을 
각각 서버마다 하려다 보면 시간도 많이 소비되고, 
그것만큼 흔히 말하는 노가다(?) 작업이 따로 없다. 

그래서 나는 기존에 ansible을 약간 알고 있었지만, 써야 할 필요성을 느꼈다.
왜냐면, 컴퓨터는 나보다 더 일을 잘하기 때문에!!!

무작정 시작하였다. 지금 보면 너무 무식한 방법이였던 것 같다. 
ex) 톰캣을 설치하는 playbook 

---
- hosts: localhost
remote_user: root
vars_prompt:
- name: version
prompt: "Please select Tomcat connector Version Default="
private: no
default: 1.2.46

tasks:
- name: download archive
get_url:
url: http://mirror.apache-kr.org/tomcat/tomcat-connectors/jk/tomcat-connectors-{{ version }}-src.tar.gz
dest: /tmp/tomcat-connectors-{{ version }}-src.tar.gz

- name: Unarchive tomcat-connectors-{{ version }}-src.tar.gz
unarchive:
src: /tmp/tomcat-connectors-{{ version }}-src.tar.gz
dest: /tmp/
- name: find apxs
command: find /home/ansible/ -name apxs -exec readlink -f {} \;
register: find_contents
- name: Tomcat Connector Source Compile
command: "{{ item }} chdir=/tmp/tomcat-connectors-{{ version }}-src/native"
with_items:
- ./configure --with-apxs={{ find_contents.stdout }}
- /bin/make
- /bin/make install




위와 같은 yaml 파일을 매번 만들어야 했고 
나중엔 파일이름이 헛갈리고 관리가 안되었기 때문에 
재사용성과 관리를 고려해 

roles 기반으로 작성하기로 하였다.
이름대로 roles(역할) 기반으로 바꾸는 작업이다. 

동일한 소스는 아니지만 다음과 같이 변경하였다.

roles
└── installation
    ├── files
    │   ├── catalina.properties
    │   ├── server.xml
    │   ├── shutdown.sh
    │   └── start.sh
    ├── tasks
    │   ├── init_dir.yml
    │   ├── main.yml
    │   ├── rm_dir.yml
    ├── templates
    │   └── env.sh
    └── vars
        └── main.yml

위에는 files, tasks, templates, vars 밖에 없지만 기본적인 roles로 작성시 아래와 같은 구조를 가진다.

default: 기본 변수 설정
files: 노드에 배포할 파일 위치
handlers: service module 을 처리하며 notify와 함께 사용 가능
meta: roles에 대한 정보, 호환버전 등 메타 데이터 정의
tasks: 수행할 작업의 목록 (각 노드에 처리해야할 작업들)
templates: 노드에 배포할 템플릿 파일 위치 (jinja2 사용하지만 다른 것도 가능한 거 같음)
vars: 작업 수행 시 사용할 변수들에 대한 정의

main.yml 파일을 호출하여 사용되며, 

roles
└── installation <-- 여기에 제품이름을 넣는 것이 편함 (개인차이있음)


roles을 처음에 사용할 때는 더 어려웠다. 
하지만 지금은 roles 로만 테스트한다. 

처음 접근이 어려워도 한번 해보는것을 추천

끝 감사합니다. 



Today expression

I arrive at my office at around 9 am.
=> 나는 사무실에 9시쯤 도착한다.

I really dont feel hungry.
=> 나는 정말 배고프지 않다.

I know what these words mean.
=> 나는 그 단어들을 안다.

I am always work hard.
=> 나는 항상 일을 열심히 한다.

early bird / a lark = a morning person.
=> 아침형 인간

hit the sack = to go to bed.
=> 잠자리에 들다, 잠을 청하다.

They often make me laugh out loud.
=> 그들은 나를 웃게 만든다.

2019년 10월 1일 화요일

jenkins 설치 및 기동 종료 스크립트

jenkins는 오픈소스 application을 빌드하기 위한 툴이다.
jenkins를 잘 활용 한다면 자동화 및 Continuous Integration (CI) / Continuous Delivery (CD)를 유용하게 사용할 수 있다. (지속적인 통합, 자동 배포 의미)

설치는 상당히 쉽다
https://jenkins.io/doc/pipeline/tour/getting-started/

문서의 내용을 살펴보면

하드웨어는 램 256mb, 디스크 10gb 정도이,
java 8 이상 버전, 컨테이너로 만드려면 docker가 필요하다

난 java로 띄워서 사용할 것이기 때문에 docker는 스킵한다.

1. http://mirrors.jenkins.io/war-stable/latest/jenkins.war 파일을 다운로드 받는다. wget으로 받는 방법, ftp로 업로드 하는 방법 선택하면 된다.
2. jenkins를 기동할 서버에 접속하여 jenkins.war 파일을 올려둔 경로로 이동한다.
3. java는 설치 했다 가정하고 아래의 명령어를 실행한다. (나같은 경우 openjdk 8설치)
   java -jar jenkins.war --httpPort=8080
4. 브라우저 열어서 http://serverip:8080 접속한다.
5. 브라우저 시키는대로 하면 끝

위와 같이 설치가 끝났다.
jenkins는 재기동 할일이 거의 없다. 하지만 하다보면 재기동할 경우도 많기 때문에 매번 java -jar ..... 이렇게 실행 시킬순 없다. 또한 종료는 어떻게 해야하는건지 내용은 안보인다.
사실 jenkins wiki에 있지만, 잘안된다. (jenkins wiki: https://wiki.jenkins.io/display/JENKINS/Administering+Jenkins)

그래서 기동 스크립트를 만들고 종료의 경우에는 jenkins-cli.jar 를 사용 해보려고 한다.
 jenkins-cli.jar 파일은 $JENKINS_HOME/war/WEB-INF 경로에 있다.

java -jar jenkins-cli.jar -s http://localhost:8080/ help
위와 같이 실행하면 옵션들이 보인다.
Options:
 -s URL              : the server URL (defaults to the JENKINS_URL env var)
 -http               : use a plain CLI protocol over HTTP(S) (the default; mutually exclusive with -ssh)
 -ssh                : use SSH protocol (requires -user; SSH port must be open on server, and user must have registered a public key)
 -i KEY              : SSH private key file used for authentication (for use with -ssh)
 -noCertificateCheck : bypass HTTPS certificate check entirely. Use with caution
 -noKeyAuth          : don't try to load the SSH authentication private key. Conflicts with -i
 -user               : specify user (for use with -ssh)
 -strictHostKey      : request strict host key checking (for use with -ssh)
 -logger FINE        : enable detailed logging from the client
 -auth [ USER:SECRET | @FILE ] : specify username and either password or API token (or load from them both from a file);
                                 for use with -http.
                                 Passing credentials by file is recommended.
                                 See https://jenkins.io/redirect/cli-http-connection-mode for more info and options.

난 -auth 를 사용했다.
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth admin:admin 

위와 같이 하게 되면 명령어 리스트가 보인다 여기서 shutdown이 있기 때문에 이걸 사용한다.
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth admin:******** shutdown 

명령어 실행시 정상적으로 종료가 되는 것을 확인 할 수 있다.

그럼 이것을 토대로 쉘스크립트를 작성하겠다.

start.sh 스크립트

nohup java -jar -Xms2048m -Xmx2048m  /opt/jenkins/bin/jenkins.war --httpPort=8080 >> jenkins.out 2>&1 &


shutdown 스크립트

java -jar /opt/jenkins/war/WEB-INF/jenkins-cli.jar -s http://localhost:8080/ -auth admin:******** shutdown

잘 동작하는 것 같다.



2019년 9월 3일 화요일

bash script + expect script 연결 스크립트

bash 와 expect는 문법도 다르고 방식도 다르다.

bash 는 스크립트 기반으로 명령을 실행한다면 expect의 경우에는 리모트 서버에 접속하여prompt를 통해서 명령을 실행 할 수 있다.
예를 들면 ssh를 통해서 명령어를 실행할 경우 

bash: ssh 계정@서버:명령어
expect: ssh 계정@서버 접속 후 prompt에서 명령어 실행 후 exit

이번에 bash 와 expect를 동시에 사용하기 위해서 스크립트를 만들었다.

#!/bin/bash

DEPLOY_BASE=/home/ansible/expect
DOMAIN="$1"
SERVICE="$2"

LIST="$DOMAIN"_"$SERVICE"_serverlist
USER=root
PASSWD=root

if [ -e "$LIST" ]; then
  for hostip in `cat $DEPLOY_BASE/$LIST`; do
  echo -e "\\n able to connect $hostip \\n"


# 여기서 부터 expect 를 실행한다. EOF는 end of file
expect << EOF
  spawn ssh -o StrictHostKeyChecking=no $USER@$hostip
  expect -re "password:"
  send "$PASSWD\r"

  expect -re "Last login:"
  send "exit \r"


# expect  종료.
EOF

  done
else
  echo -e "\\n # [ERROR] Can not found $LIST file \\n"
fi


단순 ssh 접속 테스트를 하기 위한 스크립트 이고 serverlist 파일에는 접속하려는 ip가 있어야 한다. 

이 스크립트 기반으로 응용하면 다른 명령어들도 실행이 가능하다.








2019년 9월 2일 월요일

이클립스 + git 연동 방법

java 개발할 때, 아마 이클립스를 가장 많이 사용 할 것이다. 
장소와 상관없이 작업해야 하는 일도 많고, 내가 만든 소스 버전관리도 해야한다.
이를 형상관리(Software Configuration Management라고 하는데, 나는 깃을 사용하고 있다.

이클립스와 깃을 연동하기 위해서 당연히 이클립스와 깃이 설치 되어야 한다. 
이클립스 설치는 워낙 쉽기 때문에 스킵하고 깃 연동 하는 부분을 해보도록 하겠다. 

- 이클립스 메인화면 우측 상단 Quick Access 에서 git 을 검색한다.



- 검색 리스트에서 git repository 를 클릭해서 하단에 git repository 가 보이는 지 확인한다. 
- 3가지 메뉴가 있다.
   1. Add an existing local git repository 로컬에 있는 레포지토리로 할 것인지 
   2.  Clone a git repository                       깃 레포지토리를 복지할 것인지
   3.  Create a new local git repository      새로운 깃 레포지토리를 만들 것인지

2번을 통해서 깃을 복제해보도록 한다. 



Clone a git repository 클릭한다.



깃 정보를 입력한다. 



Next 눌러서 다음으로 이동한다. 여기선 master만 있다. 



로컬 PC에 저장할 것인지를 확인 한다. 만약 project explorer에 추가 하려면 import all exising eclipse projects .... 를 체크한다. 



이 후 프로젝트에도 깃에서 받아온 소스를 확인 할 수 있다. 
모바일이든 PC든 빨간 x 표시는 참을 수가 없다. 



해당 에러를 빌드 패스(path) 문제다. PC 환경에 패스를 맞춰주면 된다. 

- 끝 -

2019년 8월 6일 화요일

Apache web 다운로드 스크립트

 Apache web 서버를 설치 하기 위해선 먼저 설치 파일을 다운로드한다.
pc에서 다운받은 후 FTP를 이용해 파일을 업로드 할 수 있지만 웹이 연결된 서버내에서는 OS command를 통해서 파일을 다운로드 받을 수 있다.
 다운로드 후 archive 파일을 unarchive 파일까지 실행하는 스크립트를 작성하였다.

스크립트에 내용을 보면 명령어 실행 후 $? 변수의 경우 성공과 실패를 체크한다.
0 성공, 0이 아닌 경우 실패


#!/bin/bash

DIR=$(pwd)
# VERSION은 마이너버전까지 필수로 입력
VERSION=2.4.39
INSTALL_FILE="httpd-$VERSION.tar.gz"
INSTALL_DIR="$DIR/installFiles"
# 다운로드 받는 미러 사이트 url을 넣었고 version을 변수로 사용
GET_URL="http://archive.apache.org/dist/httpd/$INSTALL_FILE"

# 설치 파일을 두는 경로이고 없으면 만듬
[ ! -d "$INSTALL_DIR" ] && mkdir -p "$INSTALL_DIR";





# FTP로 업로드 했을 경우에 파일을 찾아서 압축을 해제
ARCH_FILE=`find $DIR -type f | grep "$INSTALL_FILE$"`
find_rs=$?
if [ "$find_rs" -eq "0" ]; then
# tar 로 압축된 archive 파일을 압축 해제
  tar xfz "$ARCH_FILE" -C "$DIR"
  echo -e "# [INFO] apache install file is $INSTALL_FILE \\n"
  else
# 설치 파일이 없는 경우 웹에서 다운받음
  wget "$GET_URL" -P "$INSTALL_DIR"
  wget_rs=$?

# tar 로 압축된 archive 파일을 압축 해제
  tar xfz "$INSTALL_DIR/$INSTALL_FILE"
  tar_rs=$?
# wget과 tar가 실패 했을 경우 ERROR로 판단
  if [ "$wget_rs" -eq "0" ] && [ "$tar_rs" -eq "0" ]; then
    echo -e "# [INFO] apache-$VERSION download successed \\n"
  else
    echo -e "# [ERROR] There was problems during download(or unarchive) apache-$VERSION \\n"
    exit 1;
  fi 
fi

2019년 7월 17일 수요일

apache httpd 서버 설치 스크립트

오픈소스 중 가장 많이 쓰는 웹서버 apache httpd server 를 설치 스크립트로 작성해 보았다.
httpd 설치는 두가지 방법이 있다. 패키지 설치, 소스컴파일!!
소스컴파일에 대한 스크립트이다. (패키지 설치는 너무 쉬움 yum install httpd -y) 

httpd 설치는 compile 제외하곤 그리 어렵지 않다.(사실 컴파일도 그렇게 어렵지 않다) 그래도 매번 반복되는 작업을 하지 않기 위해 스크립트를 만들어보았고, 만들면서.. 과연 이게 필요할까도 생각 했지만...끝은 내고 싶었기에 완성 하였다

최초 설치에 앞서 root 또는 sudo 권한이 있는 계정으로 필수 패키지를 설치 해야한다.
centos 기반으로 만들었고 최초 vm 생성한 후 컴파일 해가며 필요한 패키지를 찾았다.

#!/bin/bash

# root or sudo permission
# Required package
array=(apr-devel apr-util-devel openssl-devel pcre-devel)



# 반복문을 통해서 패키지를 하나씩 설치 한다.
for pkg in "${array[@]}"
do
  yum list $pkg > /dev/null
  if [ $? -eq 0 ];  then
    sudo yum install $pkg -y
  else
    echo "# [ERROR] $pkg not found or unknown name "
  fi
done



DIR=$(pwd)
# 설치 할 configure 파일 찾음
CONFIG=`find $DIR -type f -name "configure"`
# configure 파일경로 찾음
CONFIG_DIR=$(dirname $CONFIG)

# httpd server 를 설치할 디렉토리(prefix라함), 이미 환경변수(PREFIX)에 경로를 설정했으면 yes or no 물어본 후 설치가 진행됨
PREFIX=
echo "# PREFIX=$PREFIX"
# 환경변수(PREFIX)가 설정되지 않았음 프롬프트에서 받아서 처리
if [ -z $PREFIX ]; then
  echo -n "# Input PREFIX (install directory): ";
  read prefix;
# 입력이 없으면 에러 발생
  if [ -z $prefix ]; then
    echo ""
    echo "# [ERROR] Please input(prefix) it correctly!!! "
    echo ""
    exit ;
  fi
  PREFIX=$prefix
else
# 당연히 PREFIX 디렉토리는 없을 거고 웹서버가 설치 되면서 경로를 만들 것임, 하지만 이구분은 PREFIX 를 제대로 입력하였는지 확인 하는 용도
  if [ ! -d $PREFIX ]; then
    echo "# [INFO] PREFIX($PREFIX) will be created directory! automatically "
    echo ""
# 설치 진행 할 경우 yes, y 를 입력! 설치를 원치 않으면 no, n를 입력하는데 잘못 입력할 것을 대비해서 while 과 case를 써서 정확한 입력을 받음

    while true; do
      read -p  "# Do you want to install httpd server continue? (yes or no) " yn
      case $yn in
        [Yy]* ) echo "# [INFO] You entered YES"; echo "";
# 일반적으로 설치 할경우 설치파일 경로로 가서 configure, options로 설치한다. options은 크게 중요하지 않음
        cd $CONFIG_DIR;
        ./configure --prefix=$PREFIX --with-mpm=worker --enable-modules=most \
                    --enable-mods-shared=most --enable-cache --enable-file-cache \
                    --enable-so --enable-mime-magic --enable-expires --enable-header \
                    --enable-proxy --enable-ssl --enable-https --enable-mpms-shared=all \
                    --enable-vhosts-alias --enable-rewrite \

        make && make install;
        break;;

# 설치 진행 대답을 no로 했을 경우 그냥 빠져 나옴!
        [Nn]* ) echo "# [INFO] You entered NO";  echo ""; exit;;
        * ) echo "##################################";   
            echo "# [WARN] Please answer Yes or No #";   
            echo "##################################";;
      esac
    done
  fi
fi

2019년 7월 12일 금요일

java thread dump 스크립트

java process 가 서비스를 수행 중 느려지거나, 아무런 동작하지 않을 때(locked) 현재 그 java process 상태를 확인 하기 위해서 thread dump를 많이 사용한다. 
thread dump를 남기는 방법은 두가지가 있다.

kill -3 or jstack command를 사용할 수 있는데,

kill -3 은 stdout 파일 예를들면 catalina.out 파일에 dump를 남기고
jstack의 경우에는 console 화면에 보여진다. 
console 보여진다는 의미는 jstack $PID 를 실행하였을 시에 모니터 화면에 바로 볼 수있다. 

thread dump 를 생성하는 방법은 동일하지만, 로그 내용을 쓰는데는 방식이 다르다.

catalina.out을 통해서 보는것도 좋지만, vi에서 화면을 오르랄 내리락 해야하기 때문에 jstack을 통해서 thread dump 내용을 파일로 리다이렉션 하는 것이 좀더 편해 보인다. 

jstack으로 thread dump를 생성하는 것을 bash scripts 로 만들었다. 

#!/bin/bash

export CATALINA_BASE=$(dirname $(dirname $(realpath $0)))
. $CATALINA_BASE/bin/env.sh > /dev/null

DATE=`date +%Y-%m-%d`

# 2초에 한번씩 총 5번 thread dump를 생성
for count in 1 2 3 4 5; do
    echo "# Thread Dump : $count"
    for i in `ps -ef | grep java | grep "$SERVER_NAME " | awk '{print $2}'`;do
echo "# PID [$i] jstack is running "
$JAVA_HOME/bin/jstack -l $i >  $LOG_DIR/threaddump.$DATE
echo "# sleep 2 sec"
sleep 2;
    done
    echo "done"
    sleep 3
done
echo ""
# thread dump 로그파일을 남김
echo "# Dumpfile is  $LOG_DIR/threaddump.$DATE"
echo ""

2019년 7월 10일 수요일

Tomcat 기동 시 CLOSE_WAIT으로 인해 startup 이 안되는 경우

jvm 경우 프로세스를 강제종료(kill) 하면 모든 스레드도 종료된다.

하지만 특이한 경우 프로세스를 강제종료(kill) 했음에도 불구하고, 종료되지 않은 경우가 있는데 이를 확인하기 위해 netstat 으로 톰켓 포트를 확인 해 봤을 시에 해당 포트가 CLOSE_WAIT이 걸리면서 기동을 하려고 했을 때 아래와 같은 메시지가 발생할 수 있다.

SEVERE [main] org.apache.catalina.core.StandardServer.await StandardServer.await: create[localhost:8005]:
        java.net.BindException: Address already in use (Bind failed)


이런 경우에 정말 깔끔하게 톰캣 프로세스를 종료 하는 스크립트를 만들어 봤다.
 

#!/bin/bash

export CATALINA_BASE=$(dirname $(dirname $(realpath $0)))
. $CATALINA_BASE/bin/env.sh > /dev/null


# 프로세스 id 찾은 후 변수 처리
PID=`ps -ef | grep java | grep "=$SERVER_NAME" | awk '{print $2}'`

# 현재 서비스 중이 포트를 찾아서 변수 처리 (명령어 종류는 많음)
HTTP_PORT=$CATALINA_BASE/bin/env.sh  | grep HTTP_PORT


# waitng 이 걸린 connection을 찾은 후 변수 처리 cconnection 수가 많기 때문에 반복문 사용 
for NETSTAT in `netstat -anp 2>/dev/null | grep $HTTP_PORT | awk '{print $4}'`;
do
    echo "$NETSTAT"
done


if [ $NETSTAT != 0 ]; then

# fuser 명령어를 통해서 모든 커넥션 정리
  fuser -kvn tcp ${HTTP_PORT};


# 명령어가 없을 수도 있으니 명령어가 실행 되었는지 확인 0=true not 0=false
  if [ $? != 0 ]; then
    echo "[ERROR] Have to install psmisc (ex) yum install psmisc -y"
    exit;
  fi
  sleep 2;
  else
    echo "### Tomcat is Not Runnable ## "
    echo ""
    exit;
fi

현재 구성한 서버 환경에서는 잘 동작한다.












2019년 7월 7일 일요일

jmap 을 사용하여 java process 상태 모니터링

모든 WAS의 경우 jvm에 의해 기동이 된다. (java로 기동되기 때문)
기동 된 이후에는 Xms 값만큼 사용하였다가 메모리가 더 필요할 경우 Xmx 값까지 사용한다. Xms, Xmx값은 동일 값으로 설정 해 주는 것이 좋다. 왜냐면 minimum 에서 maximum 까지 도달하는데까지 오버헤드가 발생한다. (실제 이슈가 있었던 경험도 있음)


그럼 jvm에 의해 기동 된 프로세스를 모니터링하고 싶은 경우, 여러 방법이 있지만, 단순 메모리 사이즈 또는 힙에 대한 내용을 확인 하고 싶을 경우 jmap이 가장 직관적이였다. (주관적인 기준)


명령어는 단순한다.
ps -ef| grep java 로 pid 및 프로세스 상태를 확인 한 후


jmap -heap [PID] 로 확인이 가능한다.


하지만, 아래와 같은 메시지가 발생한다.






더 자세한 내용을 확인하고 싶다.


이럴경우 OpenJDK에 debuginfo 를 설치 해주어야 한다.
http://debuginfo.centos.org/7/x86_64/


시스템 환경에 맞는 버전을 다운로드 후 설치 해준다.



다시 동일하게 실행 했을 경우, 명령어가 잘 실행 된다.