현재는 한대의 EC2서버에서 하나의 어플리캐이션이 작동중이다.
그래서 배포상태로 들어가면 서비스가 종료되는 문제가 생긴다.
이를 해결하기 위한 무중단 배포방법을 도입해보자.
책에서는 몇가지의 무중단 배포 방식을 예로 들고 있다.
Blue 는 실제 프로덕션 환경을 말하고, Green 은 새롭게 배포할 환경을 말한다.
이 둘을 항상 띄워놓고 배포할때 사용하는것을 말한다.
구성방식을 설명하면
우선 기존의 서버그룹과 같은 서버그룹을 하나 더 만든다. 서버 버전도 동일하고 모든게 똑같지만 로드밸런서에 연결되어 있지는 않다.
복사한 서버그룹 내부의 서버들을 업데이트 진행한다.
업데이트가 진행된 복사한 서버그룹을 로드밸런서에 연결한다.
기존에 존재하던 서버그룹을 로드밸런서에서 연결 해제한다.
이렇게 되면 처음에 먼저 배포가 끝난 서버그룹으로 연결이 이어지고 배포가 완료된 새 버전의 서비스제공이 시작된다.
블루그린 배포의 장점
단점
도커란,
컨테이너라는 가상의 공간을 만들어서 호스트OS와는 전혀 별개의 환경에서 프로세스들이 동작하는 기술이다.
이러한 컨테이너를 이미지로 만들어 저장하면 하나의 이미지에서 여러개의 컨테이너를 생성할 수 있고 독립된 가상 공간에서 실행이 된다.
도커 이미지를 만드는 방법은 Dockerfile로 만들어지고 이미지를 다운받고 관리할 수 있는 도커허브 사이트를 지원하고 있다.
장점
단점
로드밸런싱을 통한 무중단 배포를 가능하게 한다.
로드밸런싱이란 부하부산을 말하는데,
동일한 역할을 수행하는 서버 그룹을 VIP로 연결하고 서버로 향하는 트래픽을 일단 VIP를 가진 L4 스위치로 수신한 후 분배정책에 따라 적절한 서버에 분배해 주는 것을 말한다.
징점
단점
전부 각각의 장단점이 확실하다.
하지만 나는 혼자 공부하는 입장이고 비용적인 측면과 난이도 적인 측면에서 절충안이 필요했다.
여기서 등장하는 것이 NGINX이다.
기존에 절대 강자였던 웹서버 아파치를 밀어낸 고성능 오픈소서 웹서버이다.
NGINX는 스레드와 프로세스를 사용하는 Apache 와 달리, 비동기 이벤트 호출 방식을 사용한다.
외부의 요청을 받아 백앤드 서버로 요청을 전달하는 기능인 리버스 프록시를 지원하는게 특징이다.
장점
단점
일단 인프라 구성은 기존에 사용중인 EC2서버를 그대로 사용할 예정이다.
그러므로 추가적인 인스턴스를 필요로 하지 않는다.
(물론 별도로 구축도 가능하다. 하지만 비용이 발생할 것이다.)
기존에는 8080포트로 하나의 Jar를 실행했었다.
이를 8081,8082 두 포트로 각각의 Jar를 실행하는 구조로 변경할 것이다.
이중에 8081포트 Jar를 Nginx와 연결을 한 상태로 가정을 하자.
그리고 새로운 버전의 업데이트가 이루어져야 하는 상황이 발생했다.
이 업데이트를 연결하지 않은 8082부터 시작을 한다.
8082가 업데이트 되는 도중에는 8081포트로 연결을 해줌으로써 서비스를 지속하는 것이다.
그리고 8082포트쪽 업데이트가 마무리되고 배포가 완료되면 정상적으로 작동하는지를 테스트한 뒤 NGINX 설정을 8082 포트를 바라보도록 수정후 reload를 시킨다.
8081포트 Jar를 업데이트 한다.
8082포트때와 동일한 과정을 반복해서 진행후 완료되면 다시 NGINX의 설정을 8081로 바꾸고 reload를 시키면 끝난다.
EC2 서버에 NGINX를 설치하자.
sudo yum install nginx
에러가 발생했다.
nginx is available in Amazon Linux Extra topic "nginx1"
nginx1로 다시 수행해보자.
책에서 사용하던 커맨드가 또 지원되지 않는 것 같다.
지원되는 커맨드를 구글링해서 찾았다.
sudo amazon-linux-extras install nginx1.2
이번에는 설치가 진행이 되었다. 과연 제대로 된 것인가..
정상적으로 설치가 되었는지 확인하자.
sudo service nginx start
책에서 나오는 메세지와 다른 내용이 출력되었다.
nginx의 설치버전을 확인하고 프로세스에 nginx가 있는지 확인해 보았다.
내용으로만 봐서는 설치는 제대로 된 것 같다.
EC2 보안그룹에 NGINX가 사용할 포트80에 대한 인바운드 규칙을 추가하자.
포트를 지운다음 어플리케이션에 접근해보자.
http://ec2-3-37-37-4.ap-northeast-2.compute.amazonaws.com/
NGINX가 정상적으로 호출되었다.
기존에 등록된 주소에서 포트 정보를 제거한 URL을 등록하도록 하자.
Google 도메인 추가
Naver 도메인 추가
이제 NGINX에 프록시를 설정하도록 하자.
sudo vim /etc/nginx/nginx.conf
아래와 같이 location 항목을 추가해주면 된다.
작성이 끝났으면 NGINX을 재시작해줘야 한다.
sudo systemctl restart nginx
이제 포트정보없이 도메인으로 접속해보자.
정상적으로 접근이 되었다.
이제 무중단 배포를 위한 API를 추가해야 한다.
API를 통해서 8081 포트를 사용할지 8082포트를 쓸지를 판단하도록 만들자.
활성화된 properties를 반환하는 API를 만들어 보자.
real, real1, real2 3가지 중 하나를 반환하도록 만들 것이다.
만들어진 컨트롤러에 대한 테스트코드를 작성하도록 하자.
생성자 주입방식으로 주입된 properties 별로 테스트코드를 작성하자.
security에서 permitAll 항목에 '/profile'을 추가하자.
등록된 /profile에 대한 접근 테스트코드를 작성하자.
이제 개발된 소스를 commit & push 후 PR로 반영하자.
설정이 반영되었다면 도메인에서 port를 제거하고 /profile로 접근해보도록 하자.
현재는 8081, 8082로 설정한 properties가 없기 때문에 real로만 연결해주는 것을 확인할 수 있었다.
이제 8081, 8082를 사용하기 위한 properties를 작성하자.
port 8081을 사용하기 위한 properties
port 8082을 사용하기 위한 properties
완성된 properties를 git에 반영하도록 하자.
NGINX의 설정파일을 하나 생성해야 한다.
sudo vim /etc/nginx/conf.d/service-url.inc
생성되면 아래와 같은 코드를 추가하고 저장하도록 하자.
set $service_url http://127.0.0.1:8080;
프록시가 바라보는 주소를 방금 생성한 service-url.inc를 include하고 proxy_pass값을 service_url를 찾도록 nginx.conf를 수정해자.
sudo vim /etc/nginx/nginx.conf
수정이 완료되면 NGINX를 재시작해야 한다.
sudo systemctl restart nginx
새로운 경로로 무중단 배포를 구성하도록 하자.
아래 명령어로 새롭게 배포 경로를 생성하겠다.
mkdir ~/app/step3 && mkdir ~/app/step3/zip
이제 배포를 위한 스크립트들을 작성해야 한다.
변경된 경로를 수정하고 각 단계별 실행 스크립트 설정을 위해 appspec.yml을 수정해야 한다.
이제 스크립트들을 작성해 보자.
profile.sh
stop.sh
start.sh
health.sh
switch.sh
배포할때마다 버전을 알아서 갱신하도록 bundel.gradle에 아래와 같은 코드를 추가하자.
version = '1.0.1-SNAPSHOT-'+new Date().format("yyyyMMDDHHmmss")
Groovy 기반의 빌드 툴이기 때문에 문법을 사용하는 것이 가능하기에 이러한 시간정보를 직접 넣을 수 있었다.
이제 CodeDeploy에서 정상적으로 스크립트들이 작동하는지 확인해봐야 한다.
깔금하게 확인하기 위해 EC2 인스턴스를 재시작한 후 배포를 진행했다.
그래서 처음에는 구동되는 어플리케이션이 한개만 확인되었고
간단한 텍스트수정을 반영하면서 2차 배포를 시행한 뒤,
한번 더 텍스트수정을 반영하면서 무중된 배포되는 과정을 확인했다.
tail -f /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log
처음 어플리캐이션이 한개만 실행된 상태
두번째 어플리케이션이 실행되는 상태
스프링부트 로그 확인
vim ~/app/step3/nohup.out
어플리캐이션이 실행중인지 확인이 필요할 경우
ps -ef |grep java
처음에 어플리캐이션이 한개만 실행 되었을때
두개의 어플리캐이션이 모두 실행되었을때
Travis CI의 빌드과정을 모니터링하면서 브라우저로 실시간으로 refrech를 하면서 텍스가 변화하는 과정을 눈으로 확인했다.
실제로 2.31 버전으로 화면이 잘 조회가 되고 있었고 빌드가 종료되는 시점에서 재조회를 하자마자 2.32로 버전이 갱신된 것을 확인 할 수 있었다.
일련의 긴 과정을 통해서 무중단 배포까지 구현을 해보았다.
일련의 과정을 간단하게 요약해보았다.
이러한 과정을 통해서 실시간으로 서비스가 중단되지 않고 배포가 진행되고 완료되는 순간 사용 Port가 스위칭 되면서 배포가 완료된 서비스로 자연스럽게 이어지는 것을 확인할 수 있었다.
나는 기존에 SI에서 일할때 L4스위치를 통한 무중단 배포는 경험을 해본적이 있었지만
NGINX를 통한 무중단 배포는 처음 경험해봤다.
두가지 경험 다 개념은 스위칭을 해준다는 점에서 공통적이였지만
L4스위를 작업했을때의 번거로움과 비싼 장비로 구현되는 점과 비교해도 손색이 없을 정도로 사용도 편했고 성능도 우수했다.
보통은 NGINX도 별도의 인스턴스 서버를 만들어서 병렬화된 어플리캐이션 서버를 연결하는 구성을 하지만 스터디과정에서는 비용적인 측면을 고려해서 단 한개의 인스턴스 서버에서 포트만으로 병렬화된 무중단 배포를 구현했다.