이 글에서 얻는 것

  • 배포를 “코드 올리기"가 아니라 변경을 안전하게 적용하는 절차로 설계할 수 있습니다.
  • 롤링/블루그린/카나리 전략을 “언제 무엇을 쓰는지” 기준으로 선택할 수 있습니다.
  • Kubernetes, ArgoCD Rollouts, Helm 실전 명령어와 매니페스트를 즉시 활용합니다.
  • DB 마이그레이션이 포함된 배포에서 expand/contract SQL을 단계별로 작성합니다.
  • 장애 조짐이 보일 때 “배포 중단→완화→롤백"을 어떤 순서로 판단해야 하는지 런북 감각이 생깁니다.
  • 배포 사고 RCA(Root Cause Analysis) 템플릿으로 재발을 방지합니다.

0) 배포는 ‘변경 관리’다

안전한 배포는 한 문장으로 요약하면 이렇습니다.

  • 변경 범위를 작게 나누고(Blast radius),
  • 빨리 감지하고(Detect),
  • 빨리 복구한다(Recover).

그래서 런북에는 “명령"만이 아니라, **판단 기준(어떤 지표가 얼마면 중단/롤백할지)**이 들어가야 합니다.


1) 배포 전략 비교표 (의사결정 매트릭스)

전략무중단즉시 롤백트래픽 제어리소스 비용복잡도적합한 경우
Rolling⚠️ 느림내부 서비스, API 호환 보장 시
Blue/Green✅ 즉시❌ (전체 전환)★★★★★릴리스 정합성 중요, 동시 2환경 가능
Canary✅ 빠름✅ % 제어★★★★★사용자 영향 최소화, A/B 검증
Shadow✅ (영향 없음)✅ 복제★★★★★★★위험도 높은 변경, 성능 비교

선택 디시전 트리

신규 배포 or 변경?
├── API 호환성 깨짐? → Blue/Green (전체 전환)
├── 사용자 영향 불확실? → Canary (점진 노출)
├── DB 스키마 변경 포함? → Expand/Contract + Canary
├── 내부 서비스 + 호환 보장? → Rolling (가장 단순)
└── 위험도 매우 높음? → Shadow (실트래픽 복제, 응답 폐기)

2) 배포 전에 ‘반드시’ 결정할 3가지

  1. 검증 기준: 무엇을 보면 성공/실패인지 (예: 5xx < 0.1%, p99 < 500ms, 핵심 플로우 성공률 > 99.5%)
  2. 완화 수단: 피처 플래그/트래픽 스위치/레이트리밋 등 “즉시 영향 줄이는 버튼”
  3. 되돌리기 방법: 코드 롤백만 가능한지, 데이터/스키마까지 손댈지 (가장 중요)

이 3개가 없으면 배포 중 이상이 생겼을 때 “우왕좌왕"하게 됩니다.

사전 확인 체크리스트

□ 변경 범위: 어떤 기능/엔드포인트/배치가 영향을 받는가
□ 의존성: DB/캐시/메시지/외부 API 상태 (최근 장애/지연)
□ 관측 준비: 대시보드/알람/로그 조회 링크 (배포 중 클릭 한 번에 보이게)
□ 완화 수단: 피처 플래그 기본값 / 레이트리밋 / 트래픽 스위치 준비
□ DB 마이그레이션: expand/contract 단계로 분리했는가
□ 롤백 절차: 코드 롤백 명령어가 런북에 있는가
□ 온콜 연락처: 장애 에스컬레이션 경로 확인

3) Kubernetes 배포 실전 매니페스트

3-1. Rolling Update (기본)

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  labels:
    app: order-service
    version: v2.3.1
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1    # 최대 1개 Pod 내려감
      maxSurge: 1           # 최대 1개 Pod 추가 생성
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
        version: v2.3.1
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
    spec:
      terminationGracePeriodSeconds: 60
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.3.1
          ports:
            - containerPort: 8080
          
          # Readiness: 트래픽 수신 준비 완료 확인
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 3
          
          # Liveness: 프로세스 정상 동작 확인
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
            failureThreshold: 3
          
          # Startup: 초기화 완료 대기 (느린 앱)
          startupProbe:
            httpGet:
              path: /actuator/health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 30  # 최대 150초 대기
          
          # Graceful Shutdown: SIGTERM → 진행 중 요청 완료 후 종료
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 5"]  # LB 연결 해제 대기
          
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 1Gi
          
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "production"
            - name: JAVA_OPTS
              value: "-XX:MaxRAMPercentage=75.0 -XX:+UseG1GC"

3-2. Rolling Update 실전 명령어

# 배포 시작
kubectl apply -f deployment.yaml

# 배포 상태 실시간 모니터링
kubectl rollout status deployment/order-service --timeout=300s

# 배포 이력 확인
kubectl rollout history deployment/order-service

# ⚠️ 즉시 롤백 (이전 버전으로)
kubectl rollout undo deployment/order-service

# 특정 리비전으로 롤백
kubectl rollout undo deployment/order-service --to-revision=3

# 배포 일시 정지 (관찰용)
kubectl rollout pause deployment/order-service

# 배포 재개
kubectl rollout resume deployment/order-service

# Pod 상태 상세 확인
kubectl get pods -l app=order-service -o wide
kubectl describe pod <pod-name> | grep -A 20 "Events:"

# 최근 로그 확인 (에러 집중)
kubectl logs -l app=order-service --tail=100 --since=5m | grep -i error

3-3. ArgoCD Rollouts — Canary 배포

# rollout.yaml (Argo Rollouts)
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: order-service
spec:
  replicas: 4
  strategy:
    canary:
      # 단계별 트래픽 비율
      steps:
        - setWeight: 5        # 5% 트래픽 → 카나리
        - pause: { duration: 5m }  # 5분 관찰
        - analysis:
            templates:
              - templateName: success-rate
            args:
              - name: service-name
                value: order-service
        - setWeight: 25       # 25%로 증가
        - pause: { duration: 10m }
        - setWeight: 50       # 50%
        - pause: { duration: 10m }
        - setWeight: 100      # 전체 전환
      
      # 자동 롤백 분석
      canaryMetadata:
        labels:
          role: canary
      stableMetadata:
        labels:
          role: stable
      
      # 트래픽 라우팅 (Istio/Nginx)
      trafficRouting:
        istio:
          virtualService:
            name: order-service-vsvc
            routes:
              - primary
  
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.3.1
          ports:
            - containerPort: 8080
---
# analysis-template.yaml (자동 성공률 검증)
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      # Prometheus 쿼리로 성공률 측정
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            sum(rate(http_server_requests_seconds_count{
              app="{{args.service-name}}",
              status!~"5.."
            }[5m])) /
            sum(rate(http_server_requests_seconds_count{
              app="{{args.service-name}}"
            }[5m])) * 100
      # 성공률 99% 미만이면 자동 롤백
      successCondition: result[0] >= 99
      failureLimit: 3
      interval: 60s
    
    - name: p99-latency
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            histogram_quantile(0.99,
              sum(rate(http_server_requests_seconds_bucket{
                app="{{args.service-name}}"
              }[5m])) by (le)
            ) * 1000
      # p99 500ms 초과 시 실패
      successCondition: result[0] <= 500
      failureLimit: 3
      interval: 60s

3-4. ArgoCD Rollouts 명령어

# Argo Rollouts 플러그인 사용
kubectl argo rollouts get rollout order-service --watch

# 카나리 수동 승격 (다음 단계로)
kubectl argo rollouts promote order-service

# 즉시 전체 승격 (나머지 단계 건너뛰기)
kubectl argo rollouts promote order-service --full

# 즉시 롤백 (카나리 중단)
kubectl argo rollouts abort order-service

# 특정 리비전으로 롤백
kubectl argo rollouts undo order-service --to-revision=5

# 대시보드 (브라우저)
kubectl argo rollouts dashboard

4) Blue/Green 배포 — Kubernetes Service 활용

# blue-deployment.yaml (현재 운영 중)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service-blue
spec:
  replicas: 4
  selector:
    matchLabels:
      app: order-service
      slot: blue
  template:
    metadata:
      labels:
        app: order-service
        slot: blue
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.2.0
---
# green-deployment.yaml (새 버전)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service-green
spec:
  replicas: 4
  selector:
    matchLabels:
      app: order-service
      slot: green
  template:
    metadata:
      labels:
        app: order-service
        slot: green
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.3.1
---
# service.yaml (트래픽 스위칭)
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
    slot: blue   # ← 이 값을 blue/green으로 전환
  ports:
    - port: 80
      targetPort: 8080

전환/롤백 명령어

# Green으로 전환 (배포)
kubectl patch service order-service -p '{"spec":{"selector":{"slot":"green"}}}'

# Blue로 롤백 (즉시!)
kubectl patch service order-service -p '{"spec":{"selector":{"slot":"blue"}}}'

# Green 정상 확인 후 Blue 축소
kubectl scale deployment order-service-blue --replicas=0

5) DB 마이그레이션: Expand/Contract 원칙

가장 안전한 방식은 “한 번의 배포로 스키마를 완전히 바꾸지 않는 것"입니다.

5-1. 전체 과정 (컬럼 이름 변경 예시)

AS-IS: orders.user_name (VARCHAR 50)
TO-BE: orders.customer_name (VARCHAR 100)

Phase 1: Expand (확장) — 배포 #1

-- V1.1__add_customer_name_column.sql (Flyway)
-- 새 컬럼 추가 (기존 코드에 영향 없음)
ALTER TABLE orders ADD COLUMN customer_name VARCHAR(100);

-- 트리거로 실시간 동기화 (기존 쓰기도 새 컬럼에 반영)
CREATE OR REPLACE FUNCTION sync_customer_name()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.customer_name IS NULL THEN
    NEW.customer_name := NEW.user_name;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_sync_customer_name
  BEFORE INSERT OR UPDATE ON orders
  FOR EACH ROW EXECUTE FUNCTION sync_customer_name();

Phase 2: Backfill (데이터 이행) — 배포 #1 직후

-- V1.2__backfill_customer_name.sql
-- 기존 데이터를 배치로 채움 (락 최소화)
UPDATE orders
SET customer_name = user_name
WHERE customer_name IS NULL
  AND id BETWEEN 1 AND 100000;  -- 배치 단위로 실행

UPDATE orders
SET customer_name = user_name
WHERE customer_name IS NULL
  AND id BETWEEN 100001 AND 200000;

-- 진행률 확인 쿼리
SELECT 
  COUNT(*) AS total,
  COUNT(customer_name) AS filled,
  ROUND(COUNT(customer_name)::numeric / COUNT(*) * 100, 2) AS pct
FROM orders;

Phase 3: 애플리케이션 전환 — 배포 #2

// 코드에서 customer_name을 읽고/쓰도록 변경
// user_name은 여전히 트리거가 동기화하므로 롤백 가능
@Entity
public class Order {
    @Column(name = "customer_name", length = 100)
    private String customerName;
    
    // 호환성: 구버전과 신버전이 공존할 때 둘 다 읽음
    @Column(name = "user_name", length = 50, insertable = false, updatable = false)
    private String userName;
}

Phase 4: Contract (수축) — 배포 #3 (충분한 안정 기간 후)

-- V1.3__drop_user_name_column.sql
-- ⚠️ 파괴적 변경 — 롤백 불가! 반드시 Phase 3 안정 확인 후 실행

-- 트리거 제거
DROP TRIGGER IF EXISTS trg_sync_customer_name ON orders;
DROP FUNCTION IF EXISTS sync_customer_name();

-- NOT NULL 제약 추가
ALTER TABLE orders ALTER COLUMN customer_name SET NOT NULL;

-- 구 컬럼 삭제 (최종)
ALTER TABLE orders DROP COLUMN user_name;

5-2. Expand/Contract 체크리스트

Phase 1 (Expand):
  □ 새 컬럼/테이블만 추가 (기존 코드 영향 없음)
  □ 동기화 트리거 또는 듀얼 라이트 설정
  □ 롤백: ALTER TABLE DROP COLUMN으로 즉시 원복 가능

Phase 2 (Backfill):
  □ 배치 단위로 실행 (락/부하 분산)
  □ 진행률 모니터링 쿼리 준비
  □ 대형 테이블은 pt-online-schema-change 또는 gh-ost 사용

Phase 3 (코드 전환):
  □ 신/구 버전이 공존해도 동작 확인
  □ 읽기: 새 컬럼 우선, fallback 구 컬럼
  □ 쓰기: 양쪽 다 쓰기 또는 트리거 동기화
  □ 최소 1~2주 안정 운영 후 Phase 4 진행

Phase 4 (Contract):
  □ ⚠️ 롤백 불가 — 확실할 때만 실행
  □ 구 컬럼 참조하는 쿼리/인덱스/뷰 모두 제거 확인
  □ 실행 전 DDL 검증 (staging에서 먼저)
  □ 실행 후 에러 로그 10분 관찰

6) Helm 배포 실전

# 현재 릴리스 상태
helm list -n production

# 배포 (values 파일 + 오버라이드)
helm upgrade order-service ./charts/order-service \
  -n production \
  -f values-production.yaml \
  --set image.tag=v2.3.1 \
  --set replicaCount=4 \
  --timeout 5m \
  --wait                    # Pod Ready까지 대기
  --atomic                  # 실패 시 자동 롤백

# 배포 이력 확인
helm history order-service -n production

# 롤백 (이전 리비전으로)
helm rollback order-service 0 -n production  # 0 = 직전

# 특정 리비전으로 롤백
helm rollback order-service 5 -n production

# 변경 사항 미리 확인 (dry-run + diff)
helm diff upgrade order-service ./charts/order-service \
  -n production \
  -f values-production.yaml \
  --set image.tag=v2.3.1

7) 배포 중 관측 — 반드시 보는 4가지

7-1. 핵심 지표와 판단 기준

지표정상 범위경고 (관찰)위험 (중단/롤백)
에러율 (5xx)< 0.1%0.1% ~ 1%> 1%
p99 레이턴시< 200ms200ms ~ 500ms> 500ms 또는 2배 이상 증가
CPU 사용률< 60%60% ~ 80%> 80% 지속
DB 커넥션 풀< 70%70% ~ 90%> 90% 또는 대기 발생
Kafka Consumer Lag< 10001000 ~ 10000> 10000 또는 증가 추세
핵심 플로우 성공률> 99.9%99% ~ 99.9%< 99%

7-2. 실시간 모니터링 명령어

# Pod 리소스 사용량 실시간
kubectl top pods -l app=order-service --containers

# 에러 로그 실시간 스트림
kubectl logs -l app=order-service -f --since=1m | grep -iE "error|exception|fatal"

# 5xx 비율 (Prometheus)
# sum(rate(http_server_requests_seconds_count{status=~"5.."}[2m]))
# / sum(rate(http_server_requests_seconds_count[2m])) * 100

# 전체 Pod 이벤트 (OOMKill, CrashLoop 감지)
kubectl get events -n production --sort-by='.lastTimestamp' | tail -20

7-3. Grafana 대시보드 필수 패널

{
  "panels": [
    {
      "title": "배포 중 에러율 (5xx)",
      "query": "sum(rate(http_server_requests_seconds_count{status=~'5..'}[2m])) by (pod) / sum(rate(http_server_requests_seconds_count[2m])) by (pod) * 100",
      "alert": "> 1% 시 PagerDuty"
    },
    {
      "title": "p99 레이턴시 (카나리 vs 안정)",
      "query": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[2m])) by (le, role))",
      "note": "role=canary vs role=stable 비교"
    },
    {
      "title": "Pod Ready 상태",
      "query": "kube_deployment_status_replicas_ready{deployment='order-service'}",
      "note": "desiredReplicas와 비교"
    }
  ]
}

8) 이상 발생 시 대응 런북

8-1. 판단 플로우

배포 중 이상 감지
├── 에러율 > 1% OR p99 > 500ms?
│   ├── YES → 배포 즉시 중단
│   │   ├── 완화 수단 있음? (피처 플래그 OFF / 레이트리밋)
│   │   │   ├── YES → 완화 실행 → 5분 관찰 → 정상화?
│   │   │   │   ├── YES → 원인 분석 후 재배포
│   │   │   │   └── NO → 롤백
│   │   │   └── NO → 즉시 롤백
│   │   └── DB 스키마 변경 포함?
│   │       ├── YES → 코드만 롤백 (스키마는 expand 상태 유지)
│   │       └── NO → 코드 롤백
│   └── NO → 관찰 계속 (5분 단위)
└── Pod CrashLoopBackOff?
    ├── 로그 확인 → OOM? → 메모리 limit 조정
    ├── 설정 오류? → ConfigMap/Secret 확인
    └── 의존성 장애? → DB/Redis/Kafka 상태 확인

8-2. 롤백 명령어 모음

# ── Kubernetes 롤백 ──
kubectl rollout undo deployment/order-service
kubectl rollout status deployment/order-service

# ── Helm 롤백 ──
helm rollback order-service 0 -n production --wait

# ── ArgoCD Rollouts 롤백 ──
kubectl argo rollouts abort order-service
kubectl argo rollouts undo order-service

# ── 피처 플래그 즉시 OFF ──
curl -X PATCH https://flagsmith.example.com/api/v1/flags/new-checkout/ \
  -H "Authorization: Token ${FLAGSMITH_TOKEN}" \
  -d '{"enabled": false}'

# ── DB 마이그레이션 롤백 (Flyway) ──
# ⚠️ Expand 단계만 되돌림 (Contract 후에는 불가)
flyway -url=jdbc:postgresql://db:5432/orders \
  -user=deploy \
  -target=1.0 \
  undo

# ── 서비스 메쉬 트래픽 차단 ──
kubectl patch virtualservice order-service-vsvc -p '
spec:
  http:
  - route:
    - destination:
        host: order-service-stable
      weight: 100
'

9) 배포 후 검증 (스모크 테스트)

9-1. 자동화 스크립트

#!/bin/bash
# post-deploy-smoke.sh
set -e

BASE_URL="https://api.example.com"
TESTS_PASSED=0
TESTS_FAILED=0

check() {
  local name="$1" url="$2" expected_status="$3" expected_body="$4"
  
  response=$(curl -s -o /tmp/smoke_body -w "%{http_code}" "$url")
  body=$(cat /tmp/smoke_body)
  
  if [ "$response" = "$expected_status" ] && echo "$body" | grep -q "$expected_body"; then
    echo "✅ $name (HTTP $response)"
    TESTS_PASSED=$((TESTS_PASSED + 1))
  else
    echo "❌ $name (HTTP $response, expected $expected_status)"
    echo "   Body: $(echo $body | head -c 200)"
    TESTS_FAILED=$((TESTS_FAILED + 1))
  fi
}

echo "=== Post-Deploy Smoke Test ==="

# 헬스체크
check "Health"        "$BASE_URL/actuator/health"        "200" "UP"
check "Readiness"     "$BASE_URL/actuator/health/readiness" "200" "UP"

# 핵심 플로우
check "주문 목록"     "$BASE_URL/api/orders?size=1"      "200" "content"
check "상품 조회"     "$BASE_URL/api/products/1"         "200" "name"
check "인증 실패"     "$BASE_URL/api/orders"             "401" "Unauthorized"
check "잘못된 입력"   "$BASE_URL/api/orders" -d '{"amount":-1}' "400" "validation"

echo ""
echo "=== Results: $TESTS_PASSED passed, $TESTS_FAILED failed ==="

if [ $TESTS_FAILED -gt 0 ]; then
  echo "⚠️ 스모크 테스트 실패 — 롤백을 고려하세요"
  exit 1
fi

9-2. GitHub Actions에서 자동 실행

# .github/workflows/deploy.yml (발췌)
- name: Deploy to production
  run: helm upgrade ...

- name: Smoke test
  run: |
    sleep 30  # Pod Ready 대기
    bash scripts/post-deploy-smoke.sh
  
- name: Auto-rollback on failure
  if: failure()
  run: |
    echo "⚠️ Smoke test failed — rolling back"
    helm rollback order-service 0 -n production --wait
    # Slack 알림
    curl -X POST "$SLACK_WEBHOOK" -d '{"text":"🚨 배포 롤백: order-service v2.3.1 smoke test 실패"}'

10) 배포 사고 RCA 템플릿

배포 후 문제가 발생했다면 반드시 기록합니다.

## 배포 사고 RCA — [서비스명] [날짜]

### 타임라인
- HH:MM 배포 시작 (v2.3.0 → v2.3.1)
- HH:MM 카나리 5% 전환
- HH:MM 에러율 3.2% 감지 (알람 발동)
- HH:MM 배포 중단 + 피처 플래그 OFF
- HH:MM 에러율 정상화 확인
- HH:MM 롤백 실행 (v2.3.0)
- HH:MM 전체 정상 확인

### 영향
- 영향 시간: XX분
- 영향 범위: 주문 생성 API 5xx (약 YY건)
- 사용자 영향: 주문 실패 → 재시도 시 성공

### 근본 원인
- 새 버전에서 DB 컬럼 타입 변경이 구 버전 Pod와 호환되지 않았음
- expand/contract를 한 번에 실행한 것이 원인

### 재발 방지
- [ ] DB 스키마 변경은 반드시 expand/contract 3단계로 분리
- [ ] 카나리 분석에 DB 에러 메트릭 추가
- [ ] 배포 전 스키마 호환성 검증 CI 단계 추가

### 교훈
- 파괴적 스키마 변경은 배포와 분리해야 한다

11) 운영 안티패턴 6가지

안티패턴왜 위험한가올바른 접근
금요일 오후 배포주말에 인력 부족월~수 오전 배포
“한 번에 크게” 배포Blast radius 최대작은 단위로 자주
롤백 절차 없이 배포장애 시 우왕좌왕런북에 롤백 명령어 필수
DB 스키마 + 코드 동시 변경롤백 불가능expand/contract 분리
수동 배포 (ssh → pull → restart)재현 불가, 감사 불가CI/CD 파이프라인 필수
배포 후 관찰 안 함느린 장애 놓침최소 15분 대시보드 관찰

요약

  • 배포 전략은 변경의 위험도에 따라 선택한다 (Rolling < Blue/Green < Canary < Shadow).
  • 검증 기준 + 완화 수단 + 되돌리기 방법 3가지가 런북의 핵심이다.
  • DB 마이그레이션은 반드시 expand/contract로 분리한다.
  • 배포 중 에러율/레이턴시/리소스/의존성 4가지를 실시간 관찰한다.
  • 사고가 나면 RCA를 기록하여 런북을 계속 진화시킨다.

연습(추천)

  • 내 서비스의 배포 런북을 1페이지로 써보기 (검증 지표 3개 + 중단/롤백 기준 3개)
  • DB 스키마 변경이 포함된 배포를 하나 골라 expand/contract로 분해해보기
  • “피처 플래그 off"로 즉시 완화되는 시나리오를 만들어보고, 배포 중 실제로 써보기
  • ArgoCD Rollouts AnalysisTemplate을 작성하고, staging에서 자동 롤백을 검증해보기

관련 심화 학습