본문 바로가기
개발환경, 인프라/Docker

Blue-Green 배포 전략

by Pendine 2026. 4. 25.
728x90
반응형

배경: 백엔드 빌드 중 다운타임 문제 논의 중 정리

핵심 개념

운영 환경을 항상 두 벌 유지한다.

[사용자]
   │
[로드밸런서 / nginx]
   │
   ├──→ [Blue 환경]  ← 현재 운영 중 (트래픽 100%)
   │
   └──→ [Green 환경] ← 대기 중 (트래픽 0%)

배포 순서:

1. Green에 새 버전 배포 + 테스트
2. 로드밸런서 전환 → Green이 운영 (트래픽 100%)
3. Blue는 대기 상태로 전환

다음 배포 때는 Blue에 올리고 또 전환. 계속 교대.


장단점

장점

항목 내용
다운타임 0 전환이 nginx reload 수준 (수 밀리초)
즉시 롤백 문제 생기면 이전 환경으로 트래픽 전환 — 재빌드 불필요
운영과 동일 환경 테스트 Green이 실제 운영 인프라에서 뜬 채로 검증 가능
안전한 DB 마이그레이션 전환 전 Green에서 migration 결과 확인 가능

단점

항목 내용
인프라 비용 2배 서버/컨테이너 두 벌 항상 유지
DB 공유 문제 Blue/Green이 같은 DB를 보면 스키마 변경 시 충돌 가능
세션/캐시 동기화 전환 순간 기존 세션이 끊길 수 있음 (Stateless면 무관)
구성 복잡도 단순 배포보다 CI/CD 스크립트가 복잡해짐

DB 스키마 변경 시 주의사항

Blue-Green의 가장 까다로운 부분. 전환 찰나에 두 버전이 같은 DB를 동시에 바라보는 순간이 생긴다.

Blue:  v1 코드 → v1 스키마 읽음
Green: v2 코드 → v2 스키마 읽음 (컬럼 추가/변경)
       ↑ 전환 순간 두 버전이 같은 DB를 동시에 바라봄

해결책: Expand-Contract 패턴

1단계 (Expand):   DB에 새 컬럼 추가 (기존 컬럼 유지)
                  → Blue는 새 컬럼 무시하고 정상 동작
2단계 (전환):     Green으로 트래픽 이동
3단계 (Contract): 다음 배포 때 기존 컬럼 제거

한 번에 스키마를 바꾸지 않고, 추가 → 전환 → 제거 두 단계로 나눠서 진행하는 방식.


유사 전략 비교

방식 다운타임 롤백 속도 인프라 비용 복잡도
기존 (stop→run) 있음 재배포 필요 1배 낮음
Blue-Green 없음 즉시 2배 중간
Rolling Update 거의 없음 느림 1배 중간
Canary 없음 즉시 2배+ 높음

Rolling Update

인스턴스를 하나씩 교체. 여러 인스턴스가 있을 때 유효.

v1, v1, v1 → v2, v1, v1 → v2, v2, v1 → v2, v2, v2

Canary

일부 트래픽만 새 버전으로 서서히 전환. 문제 조기 감지 목적.

트래픽 5% → Green(신규)
트래픽 95% → Blue(기존)
이상 없으면 10% → 50% → 100% 순차 확대

이 프로젝트(가계부)에 적용한다면

현재 문제: CI 배포 시 docker stop → docker run 사이 다운타임 발생.

최소 구현안 (컨테이너명 교체 방식)

Docker 네트워크 내에서 컨테이너명으로 통신하므로 호스트 포트 충돌 없이 Blue-Green 구현 가능.

1. 새 이미지로 backend-green 컨테이너 기동 (호스트 포트 노출 없음)
2. /actuator/health 헬스체크 통과 확인
3. nginx upstream을 backend-blue → backend-green으로 변경
4. nginx reload (graceful, 기존 커넥션 유지)
5. backend-blue 컨테이너 종료
6. 다음 배포를 위해 green/blue 역할 파일에 기록
# nginx upstream 설정 예시
upstream backend {
    server backend-green:8080;  # 활성 환경에 따라 CI가 교체
}

CI 스크립트 변경 포인트

# 현재
docker stop backend-prod
docker run --name backend-prod ...

# Blue-Green 적용 후
ACTIVE=$(cat /deploy/active)   # "blue" or "green"
NEXT=$([ "$ACTIVE" = "blue" ] && echo "green" || echo "blue")

docker run --name backend-$NEXT ...
# 헬스체크
sed -i "s/backend-$ACTIVE/backend-$NEXT/" /etc/nginx/upstream.conf
nginx -s reload
docker stop backend-$ACTIVE
echo $NEXT > /deploy/active

전제 조건

  • Spring Boot Actuator 의존성 추가 (/actuator/health 엔드포인트)
  • 서버 메모리가 컨테이너 2개 동시 실행 가능한지 확인
  • nginx 설정에서 upstream을 동적으로 교체 가능한 구조

참고

  • 현재 프로젝트는 소규모라 빌드 다운타임(1~2분)을 감수하는 것도 실용적인 선택
  • 트래픽이 늘거나 SLA가 중요해지는 시점에 도입 검토
  • Kubernetes 사용 시 RollingUpdate 전략이 기본값으로 제공됨
728x90
반응형

댓글