콘텐츠 대표 이미지 - 클러스터 롤링 업데이트 설계
☁️ Cloud / DevOps

클러스터 롤링 업데이트 설계

무중단 배포의 핵심 전략 — 실전 설계부터 트러블슈팅까지 완전 정복 🚀

야 솔직히 말해서... 서비스 배포하다가 "잠깐 서비스 점검 중입니다" 뜨는 거 보면 진짜 식은땀 나지 않음? 😅
특히 트래픽 많은 시간대에 배포 잘못 건드렸다가 장애 터지면... 그날 야근은 기본이고 슬랙에 알림 폭탄 맞는 거 상상만 해도 아찔하잖아 ㅋㅋㅋ

그래서 오늘은 클러스터 롤링 업데이트(Rolling Update)에 대해 진짜 깊게 파볼 거야.
단순히 "이런 게 있어요~" 수준이 아니라, 실제로 설계하고 운영할 때 어떤 포인트를 잡아야 하는지까지 다 털어놓을게. 🔥

💬 "근데 롤링 업데이트가 뭔데요? 그냥 서버 껐다 켜는 거 아닌가요?"
"ㅋㅋㅋ 그 마인드로 운영하다가 장애 터진 거 아닐까요... 지금부터 제대로 배워봅시다 😤"

🎯 롤링 업데이트가 뭔지 제대로 알고 가자

롤링 업데이트(Rolling Update)는 클러스터 내의 여러 노드(서버 인스턴스)를 한 번에 다 내리지 않고, 순차적으로 조금씩 교체하면서 업데이트하는 배포 전략이야.

쉽게 비유하면... 🏗️ 건물 리모델링할 때 전체 층을 한 번에 공사하면 아무도 못 들어가잖아?
근데 1층 공사하는 동안 2~5층은 정상 운영, 1층 완료되면 2층 공사... 이런 식으로 하면 건물 전체가 멈추지 않고 계속 돌아가는 거랑 같은 원리야.

롤링 업데이트 진행 흐름 STEP 1 초기 상태 STEP 2 1번 교체 중 STEP 3 2번 교체 중 STEP 4 완료! 파드 1 v1.0 (구버전) 파드 2 v1.0 (구버전) 파드 3 v1.0 (구버전) 파드 4 v1.0 (구버전) → 파드 1 ⟳ 업데이트 중 파드 2 v1.0 (운영 중) 파드 3 v1.0 (운영 중) 파드 4 v1.0 (운영 중) → 파드 1 v2.0 ✓ 완료 파드 2 ⟳ 업데이트 중 파드 3 v1.0 (운영 중) 파드 4 v1.0 (운영 중) → 파드 1 v2.0 ✓ 파드 2 v2.0 ✓ 파드 3 v2.0 ✓ 파드 4 v2.0 ✓ 구버전 운영 중 업데이트 진행 중 신버전 완료

위 그림처럼 파드(Pod)를 하나씩 순차적으로 교체하면서 전체 서비스는 계속 살아있는 상태를 유지하는 게 핵심이야.
이게 바로 무중단 배포(Zero-Downtime Deployment)의 기본 중 기본! 🎉


📊 배포 전략 비교 — 롤링이 왜 핵심인가

배포 전략이 롤링 업데이트만 있는 건 아니야. 다른 전략들이랑 비교해보면 왜 롤링이 그렇게 많이 쓰이는지 바로 이해됨 ㅋㅋ

전략 방식 다운타임 리소스 롤백 속도
Recreate 전체 종료 후 새 버전 배포 ❌ 있음 적음 느림
Rolling Update 순차적 교체 ✅ 없음 보통 보통
Blue/Green 두 환경 동시 운영 후 스위칭 ✅ 없음 2배 필요 매우 빠름
Canary 일부 트래픽만 신버전으로 ✅ 없음 보통 빠름
💡 롤링 업데이트가 기본값인 이유
Kubernetes에서 Deployment의 기본 배포 전략이 바로 RollingUpdate야.
추가 리소스 없이도 무중단 배포가 가능하고, 대부분의 상황에서 충분한 안정성을 제공하기 때문이지.
Blue/Green은 리소스가 2배 필요하고, Canary는 설정이 복잡해서 롤링이 가성비 최고임 ㅋㅋ

⚙️ Kubernetes 롤링 업데이트 핵심 파라미터

쿠버네티스에서 롤링 업데이트를 제대로 설계하려면 두 가지 핵심 파라미터를 완전히 이해해야 해.
이거 모르면 설계 자체가 불가능하다고 봐야 함 😤

maxUnavailable — 동시에 내릴 수 있는 최대 파드 수
maxUnavailable은 업데이트 중에 사용 불가능한 상태로 있을 수 있는 파드의 최대 개수야.

예를 들어 파드가 10개인데 maxUnavailable: 2라면,
업데이트 중에도 최소 8개의 파드는 항상 정상 운영 상태여야 한다는 뜻이지.

절대값으로 설정할 수도 있고 (2),
퍼센트로 설정할 수도 있어 (25%).
maxSurge — 추가로 생성할 수 있는 최대 파드 수
maxSurge는 업데이트 중에 원래 파드 수를 초과해서 추가로 생성할 수 있는 파드의 최대 개수야.

파드가 10개인데 maxSurge: 2라면,
업데이트 중에 최대 12개의 파드가 동시에 존재할 수 있다는 뜻.

이 값이 클수록 업데이트 속도가 빨라지지만, 그만큼 리소스를 더 쓰게 돼.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 2    # 최대 2개까지 동시에 내릴 수 있음
      maxSurge: 2          # 최대 2개까지 추가 생성 가능
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app:v2.0
        readinessProbe:    # 이거 없으면 롤링 업데이트 의미 없음!
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
🔥 진짜 중요한 포인트!
readinessProbe 없이 롤링 업데이트 하면 반쪽짜리야.
새 파드가 실제로 트래픽 받을 준비가 됐는지 확인하는 게 readinessProbe인데,
이게 없으면 파드가 뜨자마자 트래픽 받다가 에러 터질 수 있거든. 꼭 설정해줘! 🙏
maxUnavailable vs maxSurge 동작 원리 replicas: 6 기준 예시 maxUnavailable: 2 업데이트 중 최소 4개는 살아있어야 함 파드1 종료 중 파드2 종료 중 파드3 운영 중 파드4 운영 중 파드5 운영 중 파드6 운영 중 ⬆ 최대 2개 동시 교체 가능 나머지 4개는 계속 서비스 유지 → 가용성 보장 우선 maxSurge: 2 최대 8개까지 파드 존재 가능 (6+2) 파드1 v1 운영 파드2 v1 운영 파드3 v1 운영 파드4 v1 운영 신규1 v2 시작 신규2 v2 시작 ⬆ 2개 추가 생성 후 구버전 교체 잠시 6+2=8개 파드 동시 존재 → 배포 속도 우선

🏗️ 실전 롤링 업데이트 설계 전략

이론은 알겠고, 이제 진짜 실전에서 어떻게 설계해야 하는지 파보자.
서비스 규모나 특성에 따라 전략이 달라지거든. 이걸 모르면 교과서 지식만 있는 거야 ㅋㅋ

🎯 시나리오 1: 고가용성이 최우선인 서비스 (금융, 결제 등)
결제 서비스나 금융 서비스는 단 1초의 다운타임도 허용 안 되잖아.
이런 경우엔 maxUnavailable을 0으로 설정하는 게 핵심이야.

maxUnavailable: 0으로 하면 기존 파드를 하나도 내리지 않고,
새 파드가 완전히 Ready 상태가 된 다음에야 구 파드를 내리게 돼.
대신 maxSurge를 적절히 설정해서 배포 속도를 조절하면 됨.
# 고가용성 우선 설정
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0    # 절대 기존 파드 먼저 내리지 않음
    maxSurge: 1          # 한 번에 1개씩 추가 생성 후 교체
    
# 이 설정의 동작 순서:
# 1. 새 파드 1개 생성 (총 replicas+1개)
# 2. 새 파드 Ready 확인
# 3. 구 파드 1개 종료
# 4. 반복...
🚀 시나리오 2: 빠른 배포가 중요한 서비스 (내부 도구, 개발 환경)
내부 어드민 도구나 개발 환경은 약간의 불안정성을 감수하더라도 빠른 배포가 더 중요할 수 있어.
이런 경우엔 maxUnavailable과 maxSurge 둘 다 높게 설정하면 돼.
# 빠른 배포 우선 설정 (replicas: 20 기준)
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 5    # 25% 동시 교체
    maxSurge: 5          # 25% 추가 생성 허용
    
# 이 설정으로 20개 파드를 5개씩 묶어서 배포
# 총 4번의 배치로 완료 → 훨씬 빠름!
⚖️ 시나리오 3: 균형 잡힌 일반 서비스 (기본 권장값)
대부분의 서비스는 이 설정으로 충분해. Kubernetes 기본값이기도 하고.
maxUnavailable: 25%, maxSurge: 25%가 기본값인데,
이게 가용성과 배포 속도 사이의 균형점이라고 보면 돼.
# 균형 잡힌 기본 설정 (replicas: 8 기준)
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 25%  # = 2개 (소수점 내림)
    maxSurge: 25%        # = 2개 (소수점 올림)
    
# 동작: 2개씩 교체, 최대 10개까지 파드 존재 가능
# 총 4번의 배치로 완료

🔍 Probe 설계 — 롤링 업데이트의 진짜 핵심

롤링 업데이트 설계에서 파라미터 설정만큼 중요한 게 바로 Probe 설계야.
Probe를 잘못 설계하면 롤링 업데이트가 있으나 마나야. 진짜로 ㅋㅋ 😅

3가지 Probe 역할 비교 🫀 Liveness Probe "살아있니?" 파드가 살아있는지 체크 실패 시 파드 재시작 데드락, 무한루프 감지 에 주로 활용 실패 → 컨테이너 재시작 롤링 업데이트와 직접 관련 낮음 ✅ Readiness Probe "트래픽 받을 준비됐니?" 트래픽 수신 준비 상태 체크 실패 시 로드밸런서에서 제외 ★ 롤링 업데이트의 핵심! Ready 확인 후 구버전 종료 실패 → 엔드포인트에서 제거 파드는 살아있지만 트래픽 차단 🚀 Startup Probe "시작 완료됐니?" 앱 초기 시작 완료 여부 체크 성공 전까지 다른 Probe 비활성 느린 시작 앱(JVM, ML 모델) 에 필수! 실패 → 컨테이너 재시작 Liveness보다 긴 타임아웃 설정
실전 Probe 설정 예시
containers:
- name: my-app
  image: my-app:v2.0
  
  # 시작 프로브: 앱이 완전히 뜰 때까지 기다림
  startupProbe:
    httpGet:
      path: /health/startup
      port: 8080
    failureThreshold: 30    # 30번 실패 허용
    periodSeconds: 10       # 10초마다 체크 → 최대 300초 대기
    
  # 준비 프로브: 트래픽 받을 준비 됐는지 (롤링 업데이트 핵심!)
  readinessProbe:
    httpGet:
      path: /health/ready
      port: 8080
    initialDelaySeconds: 5  # 시작 후 5초 뒤부터 체크
    periodSeconds: 5        # 5초마다 체크
    successThreshold: 1     # 1번 성공하면 Ready
    failureThreshold: 3     # 3번 연속 실패하면 Not Ready
    timeoutSeconds: 3       # 3초 안에 응답 없으면 실패
    
  # 생존 프로브: 데드락 등 감지
  livenessProbe:
    httpGet:
      path: /health/live
      port: 8080
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 3
💬 "근데 /health/ready 엔드포인트는 어떻게 만들어요? 그냥 200 반환하면 되나요?"
좋은 질문! 🙌

단순히 200 반환하는 건 반쪽짜리야. 진짜 Readiness 체크는 이런 걸 확인해야 해:

1. DB 연결 상태 — DB에 실제로 쿼리 날려보기
2. 캐시 연결 상태 — Redis/Memcached 연결 확인
3. 외부 API 의존성 — 필수 외부 서비스 연결 확인
4. 워밍업 완료 여부 — JVM 워밍업, 모델 로딩 완료 등

이 중 하나라도 실패하면 503 반환 → 트래픽 차단 → 안전하게 업데이트 진행!

🔄 Graceful Shutdown — 진행 중인 요청 보호하기

롤링 업데이트 중에 구버전 파드를 내릴 때, 진행 중인 요청을 어떻게 처리하느냐가 진짜 중요해.
이걸 제대로 안 하면 롤링 업데이트 중에 클라이언트가 에러를 받게 되거든. 😱

SIGTERM 시그널과 terminationGracePeriodSeconds
쿠버네티스가 파드를 종료할 때 순서는 이래:

1단계: 파드를 로드밸런서에서 제거 (새 요청 차단)
2단계: 컨테이너에 SIGTERM 시그널 전송
3단계: terminationGracePeriodSeconds 동안 대기 (기본 30초)
4단계: 시간 초과 시 SIGKILL로 강제 종료
spec:
  # 파드 종료 대기 시간 설정 (기본 30초)
  terminationGracePeriodSeconds: 60  # 60초로 늘림
  
  containers:
  - name: my-app
    lifecycle:
      preStop:
        exec:
          # SIGTERM 받기 전에 먼저 실행되는 훅
          # 로드밸런서 업데이트 지연을 위한 sleep
          command: ["/bin/sh", "-c", "sleep 5"]
⚡ preStop 훅에 sleep 5 넣는 이유
쿠버네티스가 파드를 엔드포인트에서 제거하는 것과 SIGTERM을 보내는 게 동시에 일어나는데,
로드밸런서가 업데이트되는 데 약간의 시간이 걸려.
그 사이에 새 요청이 들어올 수 있어서 5초 정도 sleep 줘서 안전하게 처리하는 거야.
이거 모르면 롤링 업데이트 중에 간헐적 에러 발생함! 🔥
애플리케이션 코드에서의 Graceful Shutdown
# Python FastAPI 예시
import signal
import asyncio
from fastapi import FastAPI

app = FastAPI()
is_shutting_down = False

@app.on_event("shutdown")
async def shutdown_event():
    global is_shutting_down
    is_shutting_down = True
    # 진행 중인 요청 완료 대기
    await asyncio.sleep(5)

@app.get("/health/ready")
async def readiness():
    if is_shutting_down:
        # 종료 중이면 503 반환 → 로드밸런서에서 제거
        return Response(status_code=503)
    return {"status": "ready"}

# Node.js Express 예시
process.on('SIGTERM', () => {
    console.log('SIGTERM received, starting graceful shutdown');
    server.close(() => {
        console.log('HTTP server closed');
        process.exit(0);
    });
    // 새 연결 거부, 기존 연결 완료 대기
    setTimeout(() => process.exit(1), 30000);
});

🚨 롤백 전략 — 문제 생겼을 때 빠르게 되돌리기

롤링 업데이트 설계에서 배포만큼 중요한 게 롤백 전략이야.
배포 잘 됐는데 운영 중에 문제 터지면? 그때 빠르게 롤백할 수 있어야 진짜 설계가 완성되는 거거든 ㅋㅋ

kubectl을 이용한 즉각 롤백
# 현재 배포 상태 확인
kubectl rollout status deployment/my-app

# 배포 히스토리 확인
kubectl rollout history deployment/my-app
# REVISION  CHANGE-CAUSE
# 1         kubectl apply --image=my-app:v1.0
# 2         kubectl apply --image=my-app:v2.0
# 3         kubectl apply --image=my-app:v3.0

# 즉시 이전 버전으로 롤백 (가장 많이 씀!)
kubectl rollout undo deployment/my-app

# 특정 리비전으로 롤백
kubectl rollout undo deployment/my-app --to-revision=1

# 롤백 진행 상황 모니터링
kubectl rollout status deployment/my-app --watch
⚠️ 롤백이 빠른 이유
쿠버네티스는 이전 ReplicaSet을 삭제하지 않고 보관해 둬.
그래서 롤백 시 새 이미지를 다운받을 필요 없이 기존 ReplicaSet을 활성화하는 방식으로 동작해서 매우 빠름!
기본적으로 10개의 리비전을 보관하는데, revisionHistoryLimit으로 조절 가능해.
spec:
  revisionHistoryLimit: 5  # 최근 5개 리비전만 보관 (기본값 10)
  # 너무 많이 보관하면 etcd 용량 차지하니까 적절히 설정
자동 롤백 설계 — 메트릭 기반

수동 롤백은 사람이 모니터링하다가 문제 발견하고 명령어 치는 거잖아.
근데 새벽 3시에 배포하다가 문제 터지면? 😴 그래서 자동 롤백 설계가 필요해!

# Argo Rollouts를 활용한 자동 롤백 설계 예시
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
spec:
  replicas: 10
  strategy:
    canary:
      steps:
      - setWeight: 10      # 10% 트래픽만 신버전으로
      - pause: {duration: 5m}  # 5분 관찰
      - setWeight: 50      # 50%로 증가
      - pause: {duration: 5m}
      - setWeight: 100     # 전체 전환
      
      # 자동 분석 설정
      analysis:
        templates:
        - templateName: success-rate
        startingStep: 1
        args:
        - name: service-name
          value: my-app
          
---
# 분석 템플릿 (에러율 5% 초과 시 자동 롤백)
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  metrics:
  - name: success-rate
    interval: 1m
    successCondition: result[0] >= 0.95  # 성공률 95% 이상
    failureLimit: 3
    provider:
      prometheus:
        address: http://prometheus:9090
        query: |
          sum(rate(http_requests_total{
            job="my-app",status!~"5.."}[5m]))
          /
          sum(rate(http_requests_total{
            job="my-app"}[5m]))

📈 모니터링 설계 — 롤링 업데이트 중 뭘 봐야 하나

배포 중에 눈 감고 있으면 안 되지 ㅋㅋ 어떤 메트릭을 봐야 하는지 정리해줄게.

롤링 업데이트 모니터링 대시보드 HTTP 에러율 (5xx) 0% 1% 2% 3% 배포 시작 임계값 평균 응답시간 (ms) 100 200 300 400 배포 시작 파드 상태 현황 Running 8 Pending 2 Terminating 2 Error 0 업데이트 진행률 50% 예상 완료까지: 약 3분 20초 알림 임계값 설정 🔴 에러율 > 5% → 즉시 롤백 트리거 🟡 응답시간 P99 > 2000ms → 슬랙 알림 + 배포 일시정지 🟢 파드 Ready율 < 80% → 배포 속도 감소
핵심 모니터링 메트릭 체크리스트
1
HTTP 5xx 에러율 — 배포 전 대비 에러율 증가 여부. 5% 초과 시 즉시 롤백 고려
2
응답 시간 (P95, P99) — 레이턴시 급증은 새 버전 성능 문제 신호
3
파드 Ready 상태 — Pending/CrashLoopBackOff 파드 수 모니터링
4
CPU/메모리 사용률 — 새 버전의 리소스 사용 패턴 확인
5
비즈니스 메트릭 — 주문 수, 로그인 성공률 등 실제 비즈니스 지표

🛡️ PodDisruptionBudget — 클러스터 레벨 안전장치

롤링 업데이트 설계에서 자주 놓치는 게 바로 PodDisruptionBudget(PDB)이야.
노드 유지보수나 클러스터 업그레이드 때도 서비스 가용성을 보장해주는 중요한 설정이거든.

PDB가 필요한 상황

클러스터 노드 유지보수 시 kubectl drain을 실행하면 해당 노드의 파드들이 다른 노드로 이동해.
이때 PDB가 없으면 여러 파드가 동시에 내려가서 서비스 장애가 날 수 있어.
PDB는 "동시에 내릴 수 있는 파드 수를 제한"해서 이런 상황을 방지해줌!
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  # 방법 1: 최소 가용 파드 수 지정
  minAvailable: 3          # 항상 최소 3개는 살아있어야 함
  
  # 방법 2: 최대 불가용 파드 수 지정 (둘 중 하나만 사용)
  # maxUnavailable: 1      # 동시에 최대 1개만 내릴 수 있음
  
  selector:
    matchLabels:
      app: my-app
      
# 퍼센트로도 설정 가능
# minAvailable: "70%"      # 항상 70% 이상 유지
# maxUnavailable: "30%"    # 최대 30%까지 동시 중단 허용
💡 PDB 설계 팁
minAvailable을 replicas의 50% 이상으로 설정하는 게 일반적이야.
단, minAvailable: replicas로 설정하면 노드 드레인 자체가 불가능해지니까 주의!
그리고 싱글 레플리카 파드에 PDB 설정하면 드레인이 블로킹될 수 있어서 조심해야 해.

🔧 실전 트러블슈팅 — 자주 만나는 문제들

이론 다 알아도 실전에서 막히는 순간이 있잖아 ㅋㅋ 자주 만나는 문제들 정리해줄게.

🚫 문제 1: 롤링 업데이트가 멈춰서 진행이 안 됨
증상: kubectl rollout status 해보면 계속 Waiting 상태

원인 1: 새 파드가 Readiness Probe를 통과 못 하고 있음
→ kubectl describe pod [파드명]으로 이벤트 확인

원인 2: 리소스 부족으로 새 파드가 Pending 상태
→ kubectl get events에서 "Insufficient cpu/memory" 확인

원인 3: ImagePullBackOff — 이미지 못 가져옴
→ 이미지 태그, 레지스트리 접근 권한 확인
# 디버깅 명령어 모음
# 파드 상태 상세 확인
kubectl describe pod [파드명] -n [네임스페이스]

# 파드 로그 확인
kubectl logs [파드명] --previous  # 이전 컨테이너 로그

# 롤아웃 이벤트 확인
kubectl describe deployment [디플로이먼트명]

# 리소스 사용량 확인
kubectl top nodes
kubectl top pods

# 롤아웃 일시정지 (문제 분석 시간 벌기)
kubectl rollout pause deployment/my-app

# 분석 후 재개
kubectl rollout resume deployment/my-app
⚡ 문제 2: 배포 중 간헐적 에러 발생
증상: 배포 중에 클라이언트에서 간헐적으로 502/503 에러

원인: 파드 종료 시 진행 중인 요청이 끊김 (Graceful Shutdown 미설정)

해결책:
1. preStop 훅에 sleep 추가
2. terminationGracePeriodSeconds 늘리기
3. 애플리케이션 코드에서 SIGTERM 처리 구현
4. 로드밸런서 헬스체크 간격 확인
🔄 문제 3: 롤백 후에도 문제가 지속됨
증상: 롤백했는데도 에러가 계속 남

원인: DB 스키마 변경이 이미 적용됨 (하위 호환성 없는 마이그레이션)

해결책:
1. DB 마이그레이션은 항상 하위 호환성 유지 (Expand-Contract 패턴)
2. 새 컬럼 추가 시 NOT NULL 제약 없이 먼저 추가
3. 구버전이 새 스키마에서도 동작하는지 확인 후 배포

Expand-Contract 패턴:
Phase 1 (Expand): 새 컬럼 추가 (구버전 호환)
Phase 2: 새 버전 배포 (새 컬럼 사용)
Phase 3 (Contract): 구 컬럼 제거

🏢 대규모 클러스터에서의 롤링 업데이트 설계

파드 수백 개, 노드 수십 개 규모에서는 추가로 고려해야 할 게 있어.
재능넷 같은 플랫폼에서도 트래픽이 늘어나면 이런 설계가 필요해지거든 😊

토폴로지 분산 제약 (Topology Spread Constraints)
파드가 특정 노드나 가용 영역에 몰려있으면 롤링 업데이트 중에 위험해.
예를 들어 10개 파드가 모두 같은 노드에 있으면, 그 노드에 문제 생기면 전체 서비스 장애!
topologySpreadConstraints로 파드를 균등하게 분산시켜야 해.
spec:
  template:
    spec:
      # 파드를 가용 영역(AZ)에 균등 분산
      topologySpreadConstraints:
      - maxSkew: 1                    # AZ 간 파드 수 차이 최대 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: my-app
            
      # 노드 간에도 균등 분산
      - maxSkew: 2
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: ScheduleAnyway  # 불가능하면 그냥 배치
        labelSelector:
          matchLabels:
            app: my-app
리소스 요청/제한 설정의 중요성
containers:
- name: my-app
  resources:
    requests:
      cpu: "500m"       # 스케줄링 기준 (이만큼 보장)
      memory: "512Mi"
    limits:
      cpu: "1000m"      # 최대 사용 제한
      memory: "1Gi"
      
# requests가 없으면 스케줄러가 노드 선택을 못 해서
# 롤링 업데이트 중 파드가 Pending 상태로 멈출 수 있음!
# 반드시 requests 설정할 것!
🎯 대규모 배포 시 추가 팁
1. 배포 시간대 선택: 트래픽이 낮은 시간대에 배포 (새벽 2~4시)
2. 배포 속도 조절: maxUnavailable을 낮게 설정해서 천천히 배포
3. 카나리 먼저: 전체 배포 전에 1~2개 파드만 먼저 신버전으로 테스트
4. 피처 플래그: 코드는 배포하되 기능은 플래그로 제어해서 리스크 분리

📋 롤링 업데이트 설계 체크리스트

자, 이제 정리해보자. 롤링 업데이트 설계할 때 이 체크리스트 다 확인하면 거의 완벽해 ㅋㅋ 💪

롤링 업데이트 설계 완전 체크리스트 📦 배포 설정 ✅ maxUnavailable / maxSurge 서비스 특성에 맞게 설정 ✅ revisionHistoryLimit 적절히 설정 (5~10) ✅ 리소스 requests/limits 반드시 설정 ✅ topologySpreadConstraints 파드 분산 설정 🔍 Probe 설정 ✅ readinessProbe 실제 의존성 체크 포함 ✅ livenessProbe 데드락 감지 설정 ✅ startupProbe 느린 앱 초기화 처리 ✅ Probe 타임아웃/임계값 실측 기반 설정 🛡️ 안전장치 ✅ PodDisruptionBudget 설정 ✅ terminationGracePeriodSeconds 충분히 설정 ✅ preStop 훅 sleep 설정 (로드밸런서 지연) ✅ 앱 코드 SIGTERM Graceful Shutdown 처리 📊 모니터링/롤백 ✅ 에러율/응답시간 알림 임계값 설정 ✅ 롤백 절차 팀 내 공유 및 훈련 ✅ DB 마이그레이션 하위 호환성 확인 ✅ 배포 후 비즈니스 메트릭 모니터링 🎯 이 체크리스트를 모두 통과하면 진짜 프로덕션 레벨의 롤링 업데이트 설계 완성! 🚀

🎓 마무리 — 롤링 업데이트 설계의 핵심 정리

자, 여기까지 왔으면 이제 롤링 업데이트에 대해 진짜 깊게 이해한 거야 👏
마지막으로 핵심만 딱 정리해줄게.

1
maxUnavailable과 maxSurge는 서비스 특성에 맞게 설정. 고가용성 서비스는 maxUnavailable: 0이 기본!
2
readinessProbe는 단순 200 응답이 아니라 실제 의존성(DB, 캐시 등)까지 체크해야 진짜 의미 있음
3
Graceful Shutdown 없이는 배포 중 간헐적 에러 피할 수 없음. preStop 훅 + 앱 코드 처리 필수!
4
PodDisruptionBudget으로 클러스터 유지보수 중에도 서비스 가용성 보장
5
롤백 전략은 배포 전에 미리 준비. DB 마이그레이션 하위 호환성은 선택이 아닌 필수!
🌟 마지막으로 한마디

롤링 업데이트는 단순히 쿠버네티스 명령어 몇 개 아는 게 아니야.
애플리케이션 코드, 인프라 설정, 모니터링, 팀 프로세스가 모두 맞물려야 진짜 무중단 배포가 되는 거거든.

이런 DevOps 관련 지식이나 클라우드 인프라 설계 도움이 필요하다면,
재능넷(jaenung.net)에서 관련 전문가를 찾아볼 수도 있어.
다양한 DevOps 엔지니어들이 실전 경험을 나눠주고 있으니까 참고해봐! 😊

오늘 배운 내용 바로 적용해보고, 배포 때 식은땀 흘리는 일 없어지길 바랄게! 🚀
댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0
댓글을 불러오는 중입니다.

아직 댓글이 없습니다.