앞에서 언급한 것처럼 프로젝트를 배포한 이후에도 개발이 멈추지 않았는데, 변경된 코드를 서버에 적용하기 위해서는 개발환경에서 테스트를 마친 이후 깃허브에 푸쉬하고 서버에 접속핸 뒤 깃허브에서 코드를 당겨온 후 서버를 재부팅하는 과정을 반복했다.
그런데 서비스에 사용된 자연어처리 모델을 로드하는데 꽤 오랜 시간이 걸렸기 때문에 한번 수정사항을 서버에 반영하기 위해서는 최소 1 ~ 3분의 시간이 낭비되었다. 그 동안은 서버가 내려가있는 상태이기 때문에 실제 서비스에서는 이러한 일을 방지해야 할 것 같았다.
그래서 다음 프로젝트에서는 배포중 반복되는 일련의 과정을 CI/CD를 통해 해결하고 배포가 진행되는 중에도 서버가 실행되도록 하기 위해 무중단 배포를 하는 방법을 간략하게 정리하였다.
CI/CD란 지속적 통합, 지속적 배포(Continuous Integration/Continuous Deployment) 의 약자로, 어플리케이션의 개발 단계부터 배포까지의 모든 단계를 자동화하여 좀 더 효율적이고 빠르게 사용자에게 빈번히 배포할 수 있는 작업방식을 말한다.
CI/CD는 CI단계와 CD단계로 나뉘는데 각 단계의 특징과 역할은 아래와 같다.
정리하면 CI/CD 파이프라인은 빌드, 테스트, 릴리즈, 배포 총 4단계를 자동화 한 것이라고 볼 수 있다.
CI/CD를 지원하는 툴은 Jenkins, CircleCI, TravisCI등 여러가지가 있다.
그 중 무료 소프트웨어인 Jenkins를 사용하여 CI/CD를 구현하였다고 가정하면 CI/CD이후 개발과정은 아래와 같다.
Jenkins를 깃허브에 연동하고 깃허브 webhook을 설정하는 것만으로 손쉽게 CI/CD 개발환경을 구축할 수 있다.
무중단 배포란 서비스가 운영중인 상태에서 새로운 버전을 배포하기 위해서는 기존 서비스를 종료하고 새로운 서비스를 시작해야 하는데, 두 작업 사이에 필연적으로 발생하는 다운타임을 없애는 것이다.
무중단 배포를 구현하기 위한 방식으로는
등 여러방식이 있다.
무중단 배포를 구현하기 위한 전략은 대표적으로 세가지가 있는데 각각의 원리와 특징은 다음과 같다.
Blue/Green방식으로 Nginx와 Docker를 활용하여 이번 프로젝트에서 무중단 배포를 구현하는 상황을 가정하면 배포는 다음과 같은 순서로 이루어진다.
위의 방법으로 무중단 배포를 구현하는 방법은 아래와 같다.
blue, green docker-compose.yml작성 : Blue, Green컨테이너를 띄우는 과정
# dokcer-compose.green.yml
version: '3.1'
services:
api:
image: ${DOCKER_REGISTRY}/${DOCKER_APP_NAME}:${IMAGE_TAG}
container_name: ${DOCKER_APP_NAME}-green
ports:
- '8080:8000'
# dokcer-compose.blue.yml
version: '3.1'
services:
api:
image: ${DOCKER_REGISTRY}/${DOCKER_APP_NAME}:${IMAGE_TAG}
container_name: ${DOCKER_APP_NAME}-blue
ports:
- '8081:8000'
blue, green nginx.conf 작성 : Ngnix에서 바라보는 컨테이너를 바꾸는 과정
# nginx.green.conf
http {
upstream backend {
server localhost:8080; # Green Container
}
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
include /etc/nginx/uwsgi_params;
proxy_pass http://backend;
}
}
# nginx.blue.conf
http {
upstream backend {
server localhost:8081; # Blue Container
}
access_log /var/log/nginx/access.log;
server {
listen 80;
location / {
include /etc/nginx/uwsgi_params;
proxy_pass http://backend;
}
}
deploy.sh작성 : nginx.conf와 docker-compose.yml을 교체하는 과정
# deploy.sh
#!/bin/bash
# Blue 를 기준으로 현재 떠있는 컨테이너를 체크한다.
EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml ps | grep Up)
# 컨테이너 스위칭
if [ -z "$EXIST_BLUE" ]; then
echo "blue up"
docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml up -d
BEFORE_COMPOSE_COLOR="green"
AFTER_COMPOSE_COLOR="blue"
else
echo "green up"
docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yaml up -d
BEFORE_COMPOSE_COLOR="blue"
AFTER_COMPOSE_COLOR="green"
fi
sleep 10
# 새로운 컨테이너가 제대로 떴는지 확인
EXIST_AFTER=$(docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.${AFTER_COMPOSE_COLOR}.yaml ps | grep Up)
if [ -n "$EXIST_AFTER" ]; then
# nginx.config를 컨테이너에 맞게 변경해주고 reload 한다
cp /etc/nginx/nginx.${AFTER_COMPOSE_COLOR}.conf /etc/nginx/nginx.conf
nginx -s reload
# 이전 컨테이너 종료
docker-compose -p ${DOCKER_APP_NAME}-${BEFORE_COMPOSE_COLOR} -f docker-compose.${BEFORE_COMPOSE_COLOR}.yaml down
echo "$BEFORE_COMPOSE_COLOR down"
fi
이렇게 nginx의 설정과 도커 컨테이너를 스위칭하는 방식으로 Blue/Green 무중단 배포를 구현하여 서버를 내리지 않고도 새로운 버전의 서비스를 배포할 수 있다.