배포할 때 잠깐이라도 서비스가 멈추면 사용자는 곧장 알아챕니다. 특히 결제, 게임, 실시간 서비스라면 단 몇 초의 다운타임도 비즈니스에 영향을 줍니다. Blue-Green 배포는 두 개의 동일한 환경을 운영하면서 트래픽을 한 번에 전환하는 가장 단순하고 검증된 무중단 배포 패턴입니다.
핵심 아이디어
| 환경 | 역할 | 사용자 트래픽 |
|---|---|---|
| Blue | 현재 운영 (v1.0) | 100% 수신 |
| Green | 다음 버전 (v1.1) 대기 | 0% — 검증만 |
배포 절차:
- Green에 신규 버전을 배포
- Green이 정상 동작하는지 헬스체크
- 로드밸런서/프록시 설정만 변경 → 트래픽이 Green으로 전환
- Blue는 즉시 폐기하지 않고, 문제 발생 시 즉시 롤백 가능한 상태로 유지
핵심은 트래픽 전환이 단일 설정 변경이라는 점입니다. 코드 푸시도, 빌드도, 재시작도 아닌 — Nginx의 upstream만 바꿉니다.
1단계 — 두 개의 애플리케이션 인스턴스
같은 서버에서 두 인스턴스를 동시에 운영합니다(다른 포트로).
# Blue (운영 중)
systemctl status myapp-blue # 포트 8080
# Green (대기)
systemctl status myapp-green # 포트 8081
systemd 템플릿 유닛으로 관리하면 깔끔합니다.
# /etc/systemd/system/myapp@.service
[Unit]
Description=MyApp instance %i
After=network.target
[Service]
User=deploy
WorkingDirectory=/opt/myapp/%i
ExecStart=/opt/myapp/%i/bin/start.sh
EnvironmentFile=/opt/myapp/%i/env
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl enable myapp@blue myapp@green
sudo systemctl start myapp@blue
2단계 — Nginx upstream 정의
# /etc/nginx/conf.d/myapp.conf
upstream blue {
server 127.0.0.1:8080;
keepalive 32;
}
upstream green {
server 127.0.0.1:8081;
keepalive 32;
}
# 현재 활성 upstream을 가리키는 별명
upstream active {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name app.example.com;
location / {
proxy_pass http://active;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
active가 가리키는 포트만 바꾸면 트래픽이 전환됩니다.
3단계 — 전환 스크립트
active의 포트만 바꿔서 nginx reload 하는 스크립트입니다.
#!/bin/bash
# /usr/local/bin/switch-deploy.sh
set -euo pipefail
TARGET="${1:-}" # blue 또는 green
CONF="/etc/nginx/conf.d/myapp.conf"
if [[ "$TARGET" != "blue" && "$TARGET" != "green" ]]; then
echo "Usage: $0 <blue|green>"
exit 1
fi
PORT=8080
[[ "$TARGET" == "green" ]] && PORT=8081
# active upstream의 포트만 치환
sed -i "/upstream active/,/}/ s|server 127.0.0.1:[0-9]*;|server 127.0.0.1:${PORT};|" "$CONF"
# Nginx 설정 검증 후 reload
sudo nginx -t
sudo systemctl reload nginx
echo "Switched to $TARGET (port $PORT)"
sudo chmod +x /usr/local/bin/switch-deploy.sh
4단계 — 배포 스크립트 (Green에 배포)
#!/bin/bash
# /usr/local/bin/deploy-green.sh
set -euo pipefail
NEW_VERSION="$1"
APP_DIR="/opt/myapp/green"
echo "[1/4] Stopping green..."
sudo systemctl stop myapp@green
echo "[2/4] Deploying version $NEW_VERSION to green..."
cd "$APP_DIR"
git fetch origin
git checkout "$NEW_VERSION"
npm ci --production
# 또는 pip install / cargo build / docker pull 등
echo "[3/4] Starting green..."
sudo systemctl start myapp@green
echo "[4/4] Health check..."
for i in {1..30}; do
if curl -fsS http://127.0.0.1:8081/healthz > /dev/null; then
echo "Green is healthy"
exit 0
fi
sleep 1
done
echo "Green failed to start" >&2
exit 1
성공하면 다음과 같이 트래픽을 전환합니다:
sudo /usr/local/bin/deploy-green.sh v1.1.0
sudo /usr/local/bin/switch-deploy.sh green
5단계 — 헬스체크 엔드포인트
/healthz는 단순 200을 반환하는 게 아니라 실제 의존성까지 체크해야 합니다.
@app.route('/healthz')
def healthz():
try:
db.execute("SELECT 1") # DB 연결
redis.ping() # 캐시 연결
return {"status": "ok"}, 200
except Exception as e:
return {"status": "fail", "error": str(e)}, 503
DB가 죽었는데 단순 200을 반환하면, Green으로 전환하자마자 모든 요청이 500으로 떨어집니다.
6단계 — 롤백
문제가 생기면 한 줄로 되돌립니다.
sudo /usr/local/bin/switch-deploy.sh blue
이게 Blue-Green의 가장 큰 가치입니다. Blue가 살아 있는 한 언제든 단일 명령으로 즉시 복귀가 가능합니다.
주의해야 할 함정
상태가 있는 연결
- WebSocket, SSE, gRPC 스트림처럼 장기 연결을 유지하는 클라이언트는 reload 시 그대로 유지됩니다. 새 연결만 Green으로 갑니다. 점진적으로 자연스러운 전환이 됩니다.
- 다만 세션 어피니티가 필요한 경우(예: 인메모리 세션) 두 인스턴스 모두에 세션 스토어가 공유돼야 합니다. Redis 세션 스토어 등을 두는 것이 안전합니다.
DB 마이그레이션
- Blue와 Green이 동시에 같은 DB를 보고 있으므로, 이전 버전과 호환되는 마이그레이션만 적용해야 합니다. 컬럼 삭제, 타입 변경 같은 파괴적 변경은 다음 절차로 분리하세요.
- 새 컬럼 추가 (이번 배포)
- 코드를 새 컬럼 사용으로 교체 (다음 배포)
- 옛 컬럼 삭제 (그 다음 배포)
환경 변수 / 비밀
- Green 환경 변수가 Blue와 다르면 의도하지 않은 차이가 생깁니다. 환경 변수 파일을 같은 곳에서 읽도록 통일하세요.
연결 풀 / 캐시 워밍업
- Green이 막 떴을 때 첫 요청은 DB 연결 풀이 비어 있어 느릴 수 있습니다. 헬스체크에서 가벼운 쿼리를 한 번 보내거나,
/warmup엔드포인트를 만들어 주요 쿼리를 미리 실행해두면 좋습니다.
Canary 배포로 확장
Blue-Green을 한 단계 발전시키면 Canary 배포가 됩니다. Nginx의 가중치 기능으로 트래픽을 부분 전환할 수 있습니다.
upstream active {
server 127.0.0.1:8080 weight=9; # Blue 90%
server 127.0.0.1:8081 weight=1; # Green 10%
keepalive 32;
}
10%로 시작 → 30% → 50% → 100% 단계로 모니터링하면서 늘리면 됩니다. 문제 발생 시 가중치만 0으로 바꿔 즉시 차단합니다.
마무리
Blue-Green은 거창한 도구가 아닙니다. 두 개의 인스턴스 + 한 줄 짜리 Nginx upstream 변경만 있으면 다운타임 0초 배포가 가능합니다. 진입 비용이 낮으면서 효과는 즉시 체감됩니다.
TCP-80.NET의 일본 VPS 4GB 플랜이면 Blue-Green 환경 두 개를 모두 띄우기에 충분합니다. systemd 템플릿이나 Nginx 설정에 막히는 부분이 있으면 @tcp80net으로 한국어 문의 가능합니다.