오늘은 다양한 무중단 배포 전략에 대해서 알아보고 그중 하나인 blue/green 전략을 도입한 경험에 대해서 공유해 보겠습니다.
예상 독자
- EC2 한 대에 docker compose로 nginx와 애플리케이션을 띄우고 계신 분
무중단 배포란?
가장 단순한 방법의 배포라면 기존 버전의 서버를 내리고 새로운 버전의 서버를 올리는 방법일 것입니다.
그렇다면 아주 잠깐이라도 서버가 내려간 순간에는 사용자들이 응답을 받지 못하게 됩니다.
이러한 중단 상태를 잠시라도 만들지 않고 배포하는 것을 무중단 배포라고 합니다.
주로 많이 사용하는 3가지 전략에 대해 알아보겠습니다.
롤링 배포 (Rolling deployments)
롤링 배포 전략은 인스턴스를 하나씩 새로운 버전으로 바꾸는 방식입니다.
바뀔 인스턴스는 트래픽이 전달되지 않도록 잠시 연결을 끊고, 새 버전을 적용한 후 다시 연결합니다.
👍) 롤백이 간편합니다.
👍) 추가적인 리소스가 필요하지 않습니다.
👎) 새 버전과 기존 버전 간 데이터 호환성 문제가 생길 수 있습니다.
👎) 모든 인스턴스가 변경되는 데 시간이 오래 걸립니다.
블루/그린 배포 (Blue/green deployments)
기존 버전의 서버를 Blue, 새 버전의 서버를 Green이라고 칭합니다.
Blue만 처리하던 트래픽을 Green으로 한 번에 변경합니다.
문제가 없으면 Blue를 제거합니다.
👍) 일제히 새로운 버전으로 적용되기 때문에 호환성 문제가 없습니다.
👎) 동시에 2개의 서버가 돌아갈 수 있는 리소스가 필요합니다.
카나리 배포 (Canary Deployments)
운영 중인 서버 트래픽의 일부를 새로운 버전으로 보내 새 버전을 테스트하는 방식입니다.
👍) 새 버전을 일부 사용자에게만 제공하므로 리스크를 줄일 수 있습니다.
👍) 빠른 피드백을 받을 수 있습니다.
👍) A / B 테스트에 용이합니다.
👎) 동시에 2개의 서버가 돌아갈 수 있는 리소스가 필요합니다.
단일 인스턴스 서버의 무중단 배포
docker-compose 기반으로 구성한 서비스의 구조입니다.
services:
nginx:
build:
dockerfile: ./nginx/Dockerfile
volumes:
- ./:/nginx/
ports:
- "80:80"
networks:
- network
webserver:
build:
dockerfile: ./webserver/Dockerfile
expose:
- 8000
networks:
- network
networks:
network:
driver: bridge
위에서 설명드린 바와 같이 단일 인스턴스에서는 선택할 수 있는 전략이 blue/green 뿐입니다.
별도의 인스턴스를 생성하거나 오케스트레이션 서비스를 사용하면 다른 전략도 고려할 수 있습니다.
하지만 mvp 단계의 서비스에서 러닝커브가 있는 기술울 학습하기에는 적절하지 못하다고 판단하여, 현재 구조에서 가능한 무중단 배포 전략을 선택했습니다.
그래서 선택한 blue / green 전략을 구현할 방법은 다음과 같습니다.
- 새로운 버전의 webserver 서비스를 생성한다.
- nginx의 설정을 변경한다.
- nginx reload를 호출한다.
- 기존 버전의 webserver 서비스를 제거한다.
docker-compose.yml 파일을 다음과 같이 수정합니다.
webserver 서비스가 blue, green이라는 접미사와 함께 2개 생성되었습니다.
services:
nginx:
build:
dockerfile: ./nginx/Dockerfile
volumes:
- ./:/nginx/
ports:
- "80:80"
networks:
- network
webserver-blue:
build:
dockerfile: ./webserver/Dockerfile
expose:
- 8000
networks:
- network
webserver-green:
build:
dockerfile: ./webserver/Dockerfile
expose:
- 8000
networks:
- network
networks:
network:
driver: bridge
서비스가 2개가 되었으니, nginx에서 docker-compose의 서비스 이름을 host로 통신하던 nginx 설정 파일을 수정해주어야 합니다.
기존 설정은 요청이 들어오면 webserver:8000
으로 라우팅 해주는 방식이었습니다.
이제는 webserver-blue:8000
와 webserver-green:8000
으로 라우팅 하는 설정 파일을 각각 만들어두고 상황에 맞는 설정 파일을 사용하도록 합니다.
위 작업들을 수행하는 bash 스크립트입니다.
지속적 배포 툴(ex. github action)을 통해 main 브랜치에 변경사항이 감지되면 EC2에서 blue / green 배포를 수행할 bash 스크립트를 실행할 수 있도록 합니다.
디렉토리를 이동하는 명령어는 지웠으니 각자의 path에 맞게 조정해 주세요.
echo "1st phase: git pull"
# 최신 상태의 코드로 만들기
git pull origin main
echo "2nd phase: blue-green deployment strategy"
# 현재 실행중이 웹서버가 BLUE인지 GREEN인지 판단
GREEN_CONTAINER_INFO=$(docker ps | grep webserver-green || true)
BLUE_CONTAINER_INFO=$(docker ps | grep webserver-blue || true)
if [ -n "$GREEN_CONTAINER_INFO" ] || [ -z "$BLUE_CONTAINER_INFO" ]; then
echo "-- Current webserver is green --"
# BLUE를 새로 빌드하여 실행
docker compose -f docker-compose.yml up -d --build webserver-blue
echo "-- update nginx configuration --"
# NGINX 설정을 BLUE로 변경 후 reload
docker exec nginx cp /etc/nginx/deploy/nginx-blue.conf /etc/nginx/nginx.conf
docker exec nginx nginx -s reload
if [ -n "$GREEN_CONTAINER_INFO" ]; then
# GREEN 제거
echo "-- shutdown old process --"
docker stop webserver-green
docker rm webserver-green
fi
else
echo "-- Current webserver is blue --"
docker compose -f docker-compose.prod.yml up -d --build webserver-green
echo "-- update nginx configuration --"
docker exec nginx cp /etc/nginx/deploy/nginx-green.conf /etc/nginx/nginx.conf
docker exec nginx nginx -s reload
echo "-- shutdown old process --"
docker stop webserver-blue
docker rm webserver-blue
fi
sudo docker system prune -f
echo "Deployment was finished"
결론
무중단 배포 전략 3가지와 단일 인스턴스에 적용할 수 있는 방법에 대해서 알아보았습니다.
EC2에 접근하기 위한 방법으로 AWS SSM을 사용하는 등 몇 가지 더 소개해 드리면 좋을 내용들이 있는데, 다음 기회에 남겨보도록 하겠습니다.
'개발 노트' 카테고리의 다른 글
[Postgresql] 쿼리 플랜으로 의사 결정하기 (0) | 2025.03.16 |
---|