티스토리 뷰
Nginx
소개
Nginx는 널리 쓰이는 웹 서버 중 하나입니다.
동적 처리를 주로 담당하는 WAS(Web Application Server)와는 다르게 웹 서버(Web Server)는 정적 자원에 대한 응답을 내려주는 역할을 가지고 있는데요.
Nginx는 정적 자원의 처리 외에도 proxy 서버의 역할이나, reverse proxy 서버의 역할 등 여러방면에서 높은 활용도를 보여줍니다.
여기서는 Nginx가 CodeDeploy Agent에 의해 두 WAS간의 스위칭 역할을 담당하도록 구성해 보겠습니다.
Nginx 설치와 설정
먼저 Nginx를 설치하겠습니다.
EC2에 ssh로 접속하여 다음 커맨드를 수행합니다.
sudo yum install nginx
그럼 설치가 되는 듯 하였으나, 다음과 같이 Amazon Linux 에서의 설치법을 따로 안내해줍니다.
안내대로 다시 커맨드를 입력합니다.
sudo amazon-linux-extras install nginx1
sudo nginx -v # 설치 버전 확인
설치 후 /etc/nginx/
로 이동해 보시면 다양한 nginx 설치파일들을 보실 수 있는데요.
우리가 관심있게 보아야 할 것은 설정파일인 nginx.conf
파일입니다.
파일 수정이 필요하니 sudo 권한으로 nginx.conf 파일을 엽니다.
sudo vim /etc/nginx/nginx.conf
다음과 같이 스크립트를 추가하겠습니다.
include /home/ec2-user/service_url.inc;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_Host;
proxy_pass $service_url;
}
- include
- 다른 곳에 존재하는 설정 파일 등을 불러올 수 있습니다.
- proxy_pass
- 우리가 지정할 $service_url로 요청을 보낼 수 있도록 하는 프록시 설정입니다.
include 로 불러올 파일 경로에 다음과 같이 파일을 생성하고 $service_url 변수를 설정하겠습니다.
vim /home/ec2-user/service_url.inc
# service_url.inc
set $service_url http://127.0.0.1:8081;
이러면 nginx 설정은 끝입니다!
다음 명령어로 nginx를 시작하고 nginx의 status를 확인할 수 있습니다.
sudo service nginx start
sudo service nginx status
배포 스크립트 추가
마지막으로 프로젝트에 CodeDeploy Agent가 참고하여 배포를 진행하기 위한 스크립트들을 추가해보도록 하겠습니다.
appspec.yml에 다음과 같이 스크립트를 추가합니다.
# appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/playground-logging/
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
### 새로 추가한 부분 ###
hooks:
ApplicationStart:
- location: scripts/run_new_was.sh
timeout: 180
runas: ec2-user
- location: scripts/health_check.sh
timeout: 180
runas: ec2-user
- location: scripts/switch.sh
timeout: 180
runas: ec2-user
- hooks
- CodeDeploy의 배포에는 각 단계 별 수명 주기가 존재합니다. 수명 주기에 따라 원하는 스크립트를 수행할 수 있습니다.
- AppSpec 'hooks' 섹션 레퍼런스
ApplicationStart라는 수명 주기에 세 가지 스크립트를 차례로 실행시키겠습니다.
프로젝트 최상단에 scripts 라는 디렉토리를 만들고 다음과 같이 세 개의 파일을 만들겠습니다!
# run_new_was.sh
#!/bin/bash
CURRENT_PORT=$(cat /home/ec2-user/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0
echo "> Current port of running WAS is ${CURRENT_PORT}."
if [ ${CURRENT_PORT} -eq 8081 ]; then
TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
TARGET_PORT=8081
else
echo "> No WAS is connected to nginx"
fi
TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+')
if [ ! -z ${TARGET_PID} ]; then
echo "> Kill WAS running at ${TARGET_PORT}."
sudo kill ${TARGET_PID}
fi
nohup java -jar -Dserver.port=${TARGET_PORT} /home/ec2-user/playground-logging/build/libs/* > /home/ec2-user/nohup.out 2>&1 &
echo "> Now new WAS runs at ${TARGET_PORT}."
exit 0
- 새로운 WAS를 띄우는 스크립트입니다.
- service_url.inc 에서 현재 서비스를 하고 있는 WAS의 포트 번호를 읽어옵니다.
- 현재 포트 번호가 8081이면 새로 WAS를 띄울 타겟 포트는 8082, 혹은 그 반대 상황이라면 8081을 지정합니다.
- 만약 타겟포트에도 WAS가 떠 있다면 kill하고 새롭게 WAS를 띄웁니다.
- nohup
- 터미널 엑세스가 끊겨도 실행한 프로세스가 계속 동작하게 합니다.
- 마지막의
&
는 프로세스가 백그라운드로 실행되도록 해줍니다.
# health_check.sh
#!/bin/bash
# Crawl current connected port of WAS
CURRENT_PORT=$(cat /home/ec2-user/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0
# Toggle port Number
if [ ${CURRENT_PORT} -eq 8081 ]; then
TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
TARGET_PORT=8081
else
echo "> No WAS is connected to nginx"
exit 1
fi
echo "> Start health check of WAS at 'http://127.0.0.1:${TARGET_PORT}' ..."
for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10
do
echo "> #${RETRY_COUNT} trying..."
RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${TARGET_PORT}/health)
if [ ${RESPONSE_CODE} -eq 200 ]; then
echo "> New WAS successfully running"
exit 0
elif [ ${RETRY_COUNT} -eq 10 ]; then
echo "> Health check failed."
exit 1
fi
sleep 10
done
- 새로 띄운 WAS가 완전히 실행되기까지 health check 하는 스크립트입니다.
# switch.sh
#!/bin/bash
# Crawl current connected port of WAS
CURRENT_PORT=$(cat /home/ec2-user/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0
echo "> Nginx currently proxies to ${CURRENT_PORT}."
# Toggle port number
if [ ${CURRENT_PORT} -eq 8081 ]; then
TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
TARGET_PORT=8081
else
echo "> No WAS is connected to nginx"
exit 1
fi
# Change proxying port into target port
echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" | tee /home/ec2-user/service_url.inc
echo "> Now Nginx proxies to ${TARGET_PORT}."
# Reload nginx
sudo service nginx reload
echo "> Nginx reloaded."
- nginx 리로드를 통해 서비스하는 포트를 스위칭하는 스크립트입니다.
sudo service nginx reload
는 nginx 서버의 재시작 없이 바로 새로운 설정값으로 서비스를 이어나갈 수 있도록 합니다.sudo service nginx restart
는 말그대로 서버의 shutdown 이후 재시작하는 명령이므로 의도하지 않았다면 주의해야 합니다.
- tee
- 출력 내용을 파일로 만들어주는 커맨드입니다.
- 새로 띄운 WAS의 포트를 nginx가 읽을 수 있도록 service_url.inc에 내용을 덮어씁니다.
이제 모든 준비가 끝났습니다!
무중단 배포를 진행하기 전에, 현재 서버에 아무런 WAS가 떠 있지 않기 때문에 8081 포트에 WAS를 새로 한번 띄워보겠습니다.
EC2에 접속하여 프로젝트 내에 있는 jar 파일을 실행하겠습니다.
nohup java -jar -Dserver.port=8081 /home/ec2-user/playground-logging/build/libs/* &
nginx가 바라보도록 설정한 service_url.inc 파일이 8081포트를 가리키고 있기 때문에, 8081로 서버를 띄운 후 EC2 인스턴스의 퍼블릭 DNS로 접속해 보시면 다음과 같이 우리가 만들었던 Controller의 리턴값이 잘 나오는 것을 볼 수 있습니다.
이제 드디어 무중단 배포를 진행해볼 차례입니다.
application.yml의 버전을 0.0.2로 올리고, 커밋 - 푸시 후 Github Actions에서 배포를 진행해봅시다.
Github Actions 의 작업이 끝나고나서, CodeDeploy가 배포를 시작할 때 브라우저에서 지속적으로 새로고침을 눌러보시면!
서버의 중단 없이 한순간에 버전이 바뀌는 것을 볼 수 있습니다! (드디어!)
ps -ef | grep java
커맨드를 통해 배포 전과 배포 후를 비교해보면 8082 포트로 새로운 서버가 실행된 것을 볼 수 있습니다.
그리고 tail service_url.inc
로 내용을 확인해보시면 우리가 작성한 스크립트가 Nginx가 바라보는 포트를 8082로 변경한 것도 보실 수 있습니다!
이제 그 다음 배포를 한번 더 진행한다고 하면, 새로운 서버는 기존 8081 포트의 애플리케이션을 종료하고 새로 뜰 것이고, Nginx는 8081 포트를 서비스할 것입니다.
현재 이 배포 구성은 V2 버전의 WAS가 서비스를 하고 있으면서 이전 버전인 V1의 WAS가 서비스를 하지 않는데도 백그라운드에 그대로 떠 있는 상황인데요.
배포 직후 모니터링 과정에서 롤백해야 하는 상황이 온다면 롤백용 스크립트를 추가해서 V1 버전의 WAS를 다시 서비스하도록 Nginx를 reload하는 방식을 적용할 수도 있습니다.
또는 서비스 하는 내내 두 개의 WAS를 불필요하게 띄워놓을 필요가 없겠다는 생각이 드신다면, 배포 직후 V1 버전의 WAS가 롤백 대비용으로 떠 있다가, 모니터링을 진행하고 일정 시간이 지나면 해당 WAS를 종료하는 스크립트도 추가할 수 있을 것입니다.
이번 Github Actions + CodeDeploy + Nginx 를 이용해 최소 규모로 무중단 배포하기 시리즈는 여기까지입니다!
긴 글 읽어주셔서 감사합니다 :)
'devOps' 카테고리의 다른 글
[AWS SAA] 1. EC2, Auto Scaling, ELB (0) | 2021.02.08 |
---|---|
AWS SAA-C02 합격 후기 (0) | 2021.02.07 |
Github Actions + CodeDeploy + Nginx 로 무중단 배포하기 (2) (0) | 2020.08.20 |
Github Actions + CodeDeploy + Nginx 로 무중단 배포하기 (1) (0) | 2020.08.19 |
CodeDeploy View events 에서 에러 로그를 확인할 수 없는 경우 (0) | 2020.08.11 |