클라우드 Prod 환경 CICD 및 Blue Green 배포 구축 확정 롤백 - 100-hours-a-week/16-Hot6-wiki GitHub Wiki
Confirm Prod Deployment
Workflow – 불필요한 MIG 정리
1. 전체코드
name: Confirm Prod Deployment (Clean Old MIG)
on:
workflow_dispatch:
inputs:
confirm_slot:
description: '배포된 슬롯 이름(예: blue, green) ❌삭제할 버전 아님❌'
required: true
jobs:
confirm:
runs-on: ubuntu-latest
env:
ZONE: asia-northeast3-a
steps:
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: '${{ secrets.GCP_SA_KEY }}'
- name: Confirm deployment and clean old MIG
run: |
SLOT="${{ github.event.inputs.confirm_slot }}"
ZONE="$ZONE"
if [ "$SLOT" == "blue" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$SLOT"-==-"blue"-); then
OLD_SLOT=green
else
OLD_SLOT=blue
fi
OLD_MIG="onthetop-backend-$OLD_SLOT"
echo "$OLD_MIG 를 삭제합니다..."
gcloud compute instance-groups managed delete $OLD_MIG --zone=$ZONE --quiet || true
Confirm Prod Deployment (Clean Old MIG)
워크플로는 배포가 정상적으로 검증된 뒤 여분의 MIG를 제거해 리소스 비용을 줄입니다.
트리거 & 인풋
입력 | 설명 | 예시 |
---|---|---|
confirm_slot |
현재 트래픽을 받고 있는 슬롯 이름(삭제 대상이 아님) | blue |
핵심 로직
-
대상 식별 : 입력 슬롯이
blue
면green
MIG를, 반대면blue
MIG를OLD_MIG
로 지정. -
MIG 삭제
gcloud compute instance-groups managed delete $OLD_MIG --zone=$ZONE --quiet || true
|| true
로 MIG가 이미 없을 때도 오류 없이 종료 – 멱등성 보장.
검증 후 1‑클릭으로 불필요한 인스턴스 그룹을 없애 비용 최적화와 깨끗한 슬롯 관리를 동시에 달성합니다.
Rollback Prod
Workflow – 안전한 전체 롤백
2. 전체코드
name: Rollback Prod (Safe)
on:
workflow_dispatch:
inputs:
be_slot:
description: '현재 잘못 배포된 BE 슬롯 (예: blue, green)'
required: true
fe_slot:
description: '현재 잘못 배포된 FE 슬롯 (예: blue, green)'
required: true
jobs:
rollback:
runs-on: ubuntu-latest
env:
REGION: asia-northeast3
ZONE: asia-northeast3-a
BACKEND_SERVICE: onthetop-backend-service
CLOUDFRONT_DISTRIBUTION_ID: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
AWS_DEFAULT_REGION: ap-northeast-2
steps:
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: '${{ secrets.GCP_SA_KEY }}'
- name: Set up gcloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Set up AWS CLI
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.CLOUDFRONT_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.CLOUDFRONT_SECRET_KEY }}
aws-region: ap-northeast-2
- name: Rollback Backend with MIG Health Check
run: |
SLOT="${{ github.event.inputs.be_slot }}"
if [ "$SLOT" == "blue" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$SLOT"-==-"blue"-); then
TARGET="green"
else
TARGET="blue"
fi
NEW_MIG="onthetop-backend-$TARGET"
OLD_MIG="onthetop-backend-$SLOT"
PROJECT=$(gcloud config get-value project)
echo "🔍 $TARGET MIG 인스턴스 그룹 헬스체크 중..."
for i in {1..20}; do
STATUS=$(gcloud compute instance-groups managed list-instances "$NEW_MIG" \
--zone="$ZONE" --format=json | \
jq -r 'map(.instanceStatus) | unique | .[]')
echo "⏳ 시도 $i: 인스턴스 상태 = $STATUS"
[ "$STATUS" == "RUNNING" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$STATUS"-==-"RUNNING"-) && break
sleep 10
done
if [ "$STATUS" != "RUNNING" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$STATUS"-!=-"RUNNING"-); then
echo "❌ MIG 인스턴스 그룹이 준비되지 않았습니다. 롤백 중단."
exit 1
fi
echo "✅ MIG 인스턴스 그룹 준비 완료. 백엔드에 연결 중..."
gcloud compute backend-services add-backend "$BACKEND_SERVICE" \
--global \
--instance-group="$NEW_MIG" \
--instance-group-zone="$ZONE"
echo "🔍 LB to MIG 헬스체크 확인 중..."
MIG_URL="https://www.googleapis.com/compute/v1/projects/$PROJECT/zones/$ZONE/instanceGroups/$NEW_MIG"
for i in {1..20}; do
STATE=$(gcloud compute backend-services get-health "$BACKEND_SERVICE" --global --format=json | \
jq -r --arg MIG "$MIG_URL" \
'.[] | select(.backend == $MIG) | (.status.healthStatus // []) | map(.healthState) | unique | .[]?')
echo "⏳ 시도 $i: 상태 = $STATE"
[ "$STATE" == "HEALTHY" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$STATE"-==-"HEALTHY"-) && break
sleep 10
done
if [ "$STATE" != "HEALTHY" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$STATE"-!=-"HEALTHY"-); then
echo "❌ HEALTHY 상태가 아님. 롤백 중단."
exit 1
fi
echo "✅ HEALTHY 상태 확인됨. 롤백 진행."
gcloud compute backend-services remove-backend "$BACKEND_SERVICE" \
--global \
--instance-group="$OLD_MIG" \
--instance-group-zone="$ZONE" || true
echo "🧹 $OLD_MIG 삭제 중..."
gcloud compute instance-groups managed delete "$OLD_MIG" --zone="$ZONE" --quiet || true
- name: Rollback CloudFront FE Origin
run: |
SLOT="${{ github.event.inputs.fe_slot }}"
if [ "$SLOT" == "blue" ](/100-hours-a-week/16-Hot6-wiki/wiki/-"$SLOT"-==-"blue"-); then
TARGET="green"
else
TARGET="blue"
fi
echo "🔄 FE 슬롯을 $TARGET 으로 되돌립니다."
aws cloudfront get-distribution-config --id "$CLOUDFRONT_DISTRIBUTION_ID" > raw.json
ETAG=$(jq -r '.ETag' raw.json)
jq '.DistributionConfig' raw.json > config-only.json
jq --arg TARGET "$TARGET" \
'.Origins.Items[0].OriginPath = "/frontend/prod/\($TARGET)"' \
config-only.json > updated-config.json
aws cloudfront update-distribution \
--id "$CLOUDFRONT_DISTRIBUTION_ID" \
--if-match "$ETAG" \
--distribution-config file://updated-config.json
- name: Invalidate CloudFront Cache
run: |
aws cloudfront create-invalidation \
--distribution-id "$CLOUDFRONT_DISTRIBUTION_ID" \
--paths "/" "/index.html" "/assets/*.js" "/assets/*.css"
배포 실패·장애 발생 시 백엔드 + 프론트엔드를 한 번에 이전 슬롯으로 되돌립니다.
트리거 & 인풋
입력 | 설명 | 예시 |
---|---|---|
be_slot |
문제 발생한 백엔드 슬롯 | green |
fe_slot |
문제 발생한 프론트엔드 슬롯 | green |
입력값은 잘못 올라간 슬롯입니다. 워크플로는 자동으로 반대 슬롯을
TARGET
으로 판단합니다.
롤백 단계 요약
-
GCP 인증 & AWS CLI 준비
-
백엔드 롤백
- 대상
TARGET
MIG 헬스체크(최대 200s) - LB 백엔드 서비스에
TARGET
MIG 추가 → HEALTHY 확인 - 기존
OLD_MIG
제거 + 삭제
- 대상
-
프론트엔드 롤백
- CloudFront OriginPath를
/frontend/prod/{TARGET}
로 수정 - 캐시 무효화로 즉시 반영
- CloudFront OriginPath를
안전 장치
단계 | 실패 시 처리 |
---|---|
MIG 준비 미완료 | 워크플로 중단, 기존 상태 유지 |
LB Health 미통과 | 새 MIG 제거 후 중단 (트래픽 기존 슬롯 유지) |
덕분에 롤백 자체가 실패해도 서비스는 중단되지 않도록 설계되어 있습니다.
실제 운영 흐름 예시
Deploy Prod
– 새로운 버전 배포- 기능 검증 후
Confirm Prod Deployment
로 구슬롯 제거 - 장애 발견 시
Rollback Prod
→ 즉시 이전 슬롯으로 전환
배포 스크립트와 위 두개의 워크플로를 조합하면, 배포 → 검증 → 확정 or 롤백까지 전 주기가 자동화되면서도 사람이 개입할 수 있는 안전한 Blue‑Green 파이프라인이 완성됩니다.