1. 롤링 업데이트란?
Deployment의 이미지 버전을 바꿔서 kubectl apply를 실행하면, Kubernetes는 기본적으로 롤링 업데이트(Rolling Update) 전략으로 배포를 진행한다. 구버전 Pod를 한 번에 모두 내리고 신버전으로 교체하는 것이 아니라, 신버전 Pod를 하나씩 새로 띄우면서 구버전 Pod를 하나씩 내리는 방식으로 점진적으로 교체해서 서비스 중단 없이 배포가 이루어지도록 한다.
지금까지 이 시리즈에서 다룬 requests/limits, Probe, HPA가 전부 이 롤링 업데이트 과정에서 실제로 맞물려 동작한다. 이번 글에서 그 연결고리를 확인할 수 있다.
2. maxSurge와 maxUnavailable
롤링 업데이트 중 Pod 개수가 어떻게 변하는지는 strategy.rollingUpdate의 두 값으로 조절한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 목표치보다 최대 몇 개까지 더 띄울 수 있는지
maxUnavailable: 1 # 목표치보다 최대 몇 개까지 줄어들어도 되는지
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: myregistry/my-app:2.0.0
- maxSurge: 배포 중 replicas 설정값보다 최대 몇 개까지 초과해서 Pod를 띄울 수 있는지. 값이 클수록 신버전을 더 빨리 많이 띄울 수 있지만, 그만큼 순간적으로 더 많은 자원을 사용한다
- maxUnavailable: 배포 중 replicas 설정값보다 최대 몇 개까지 부족해도 되는지. 값이 클수록 구버전을 더 빨리 많이 내릴 수 있지만, 그만큼 순간적으로 처리 가능한 Pod 수가 줄어든다
두 값 모두 정수 또는 퍼센트(25%처럼)로 지정할 수 있으며, 기본값은 둘 다 25%다.
replicas: 4에 maxSurge: 1, maxUnavailable: 1인 경우, 배포가 진행되는 동안 전체 Pod 개수는 항상 3~5개(4±1) 사이를 오간다. 신버전이 하나씩 늘어나고 구버전이 하나씩 줄어드는 과정이 반복되며, 최종적으로 모든 Pod가 신버전으로 교체되면 다시 4개로 돌아온다.
3. readinessProbe가 롤링 업데이트의 '문지기'다
여기서 앞서 다룬 [Probe 글]의 readinessProbe가 결정적인 역할을 한다. Kubernetes는 신버전 Pod의 readinessProbe가 성공해야만 그다음 구버전 Pod를 종료하기 시작한다. 즉 readinessProbe는 롤링 업데이트가 다음 단계로 넘어가도 되는지를 판단하는 문지기(gatekeeper) 역할을 한다.
- 신버전 Pod 1개가 생성된다 (maxSurge 한도 내)
- 이 Pod의 readinessProbe가 성공할 때까지 Kubernetes는 기다린다
- 성공하면 그제서야 구버전 Pod 1개를 종료한다
- 이 과정이 모든 Pod가 교체될 때까지 반복된다
만약 신버전에 문제가 있어서 readinessProbe가 계속 실패한다면 어떻게 될까? 이 경우 구버전 Pod는 종료되지 않고 그대로 유지된다. 즉 readinessProbe가 제대로 설정되어 있다면, 문제 있는 신버전이 트래픽을 받기도 전에 롤링 업데이트 자체가 안전하게 멈춘다. 사용자 입장에서는 배포에 문제가 생겼다는 것조차 체감하지 못한 채, 여전히 잘 동작하는 구버전이 계속 트래픽을 처리해준다.
반대로 readinessProbe가 설정되어 있지 않다면 이 안전장치 자체가 무력화된다. 신버전 Pod는 컨테이너가 뜨는 즉시 정상으로 간주되어 바로 트래픽을 받기 시작하고, 실제로는 망가진 상태라면 그 장애가 곧바로 사용자에게 전파된다. "롤링 업데이트니까 안전하겠지"라는 생각으로 readinessProbe 없이 배포하는 것이 왜 위험한지가 바로 이 지점이다.
4. 배포 진행 상황 확인하기
배포가 진행되는 동안 아래 명령으로 실시간 상태를 볼 수 있다.
kubectl rollout status deployment/my-app
Waiting for deployment "my-app" rollout to finish: 2 out of 4 new replicas have been updated...
Waiting for deployment "my-app" rollout to finish: 1 old replicas are pending termination...
deployment "my-app" successfully rolled out
지금까지 배포 이력은 아래 명령으로 확인할 수 있다.
kubectl rollout history deployment/my-app
5. 배포가 멈췄을 때: progressDeadlineSeconds
신버전 Pod의 readinessProbe가 계속 실패하면 구버전 Pod는 안전하게 유지되지만, 그렇다고 배포가 영원히 대기 상태로 남아있는 것도 바람직하지 않다. Kubernetes는 progressDeadlineSeconds(기본값 600초)만큼 배포에 진전이 없으면, Deployment 상태를 ProgressDeadlineExceeded로 표시해서 배포가 정체되었음을 알려준다.
spec:
progressDeadlineSeconds: 300 # 5분 동안 진전이 없으면 실패로 간주
이 상태는 자동으로 롤백을 수행하지는 않는다. 다만 CI/CD 파이프라인이나 모니터링에서 이 상태를 감지해 경고를 보내거나, 자동으로 rollout undo를 트리거하도록 구성하는 것이 일반적이다.
6. 롤백: kubectl rollout undo
배포 후 문제를 발견했다면 직전 버전으로 즉시 되돌릴 수 있다.
# 바로 직전 버전으로 롤백
kubectl rollout undo deployment/my-app
# 특정 리비전으로 롤백 (rollout history에서 확인한 번호)
kubectl rollout undo deployment/my-app --to-revision=3
롤백도 내부적으로는 똑같이 롤링 업데이트 방식으로 진행된다. 즉 롤백 과정에서도 readinessProbe가 동일하게 문지기 역할을 하며, maxSurge/maxUnavailable 설정도 그대로 적용된다.
6.1 롤백 이력이 안 남는 경우
기본적으로 revisionHistoryLimit(기본값 10)만큼의 과거 ReplicaSet만 보관되며, 이보다 오래된 리비전은 자동으로 정리되어 롤백할 수 없다. 롤백 이력을 더 길게 유지하고 싶다면 이 값을 늘리면 된다.
spec:
revisionHistoryLimit: 20
또한 Deployment에 kubectl set image처럼 변경 원인이 기록되지 않는 방식으로 배포하면 rollout history에 CHANGE-CAUSE가 비어 보일 수 있다. 배포 이력을 명확히 남기고 싶다면 kubectl apply -f로 관리되는 YAML 자체에 변경 이력을 남기거나(Git 커밋 로그 등), --record 플래그(구버전) 대신 CI/CD 파이프라인에서 별도로 배포 로그를 남기는 방식을 권장한다.
7. 실전 팁
7.1 HPA와 함께 쓸 때 주의점
앞서 다룬 [HPA 글]에서 설명한 것처럼, HPA가 관리하는 Deployment에 롤링 업데이트가 동시에 진행되면 Pod 개수가 "HPA가 원하는 개수"와 "롤링 업데이트가 진행 중인 surge/unavailable"이 겹쳐서 일시적으로 더 복잡하게 움직일 수 있다. 이 자체는 정상 동작이지만, 배포 중 모니터링 대시보드의 Pod 개수 변화가 예상과 다르게 보여도 당황하지 않아도 된다.
7.2 Recreate 전략과의 차이
모든 배포가 롤링 업데이트일 필요는 없다. 동시에 두 버전이 함께 떠 있으면 안 되는 애플리케이션(예: DB 스키마 마이그레이션이 얽힌 경우)이라면 Recreate 전략을 쓸 수 있다. 이 경우 구버전을 모두 내린 뒤에야 신버전을 띄우므로 다운타임이 발생하지만, 두 버전이 공존하는 상황 자체를 원천 차단한다.
spec:
strategy:
type: Recreate
7.3 배포 전 체크리스트
- readinessProbe가 설정되어 있는가 (없으면 롤링 업데이트의 안전장치가 무력화됨)
maxSurge/maxUnavailable이 서비스의 트래픽 특성에 맞게 설정되어 있는가progressDeadlineSeconds가 애플리케이션의 정상적인 초기화 시간보다 여유 있게 설정되어 있는가- 롤백이 필요한 경우를 대비해
revisionHistoryLimit이 충분한가
8. 정리
| 개념 | 내용 |
|---|---|
| maxSurge | 배포 중 목표치보다 최대 몇 개까지 초과 생성 허용 |
| maxUnavailable | 배포 중 목표치보다 최대 몇 개까지 부족 허용 |
| readinessProbe의 역할 | 신버전이 통과해야만 구버전 종료 시작 (문지기) |
| progressDeadlineSeconds | 이 시간 동안 진전이 없으면 배포 정체로 표시 |
| kubectl rollout undo | 직전(또는 지정한) 리비전으로 롤백, 내부적으로 롤링 업데이트와 동일 방식 |
롤링 업데이트는 "설정만 해두면 알아서 안전하게 배포해주는 기능"이 아니라, readinessProbe가 제대로 설정되어 있다는 전제 위에서만 안전하게 동작하는 기능이다. 이 시리즈에서 다룬 Probe, Resource/QoS, HPA가 모두 이 한 장의 배포 과정 안에서 서로 맞물려 동작한다는 것을 이해하면, Kubernetes의 신뢰성 관련 기능들이 왜 개별적으로가 아니라 세트로 갖춰져야 하는지가 분명해진다.
'프로그래밍 > k8s' 카테고리의 다른 글
| Kubernetes HPA(HorizontalPodAutoscaler) 완벽 정리 (0) | 2026.09.16 |
|---|---|
| Kubernetes Resource Request/Limit과 QoS Class 완벽 정리 (0) | 2026.09.14 |
| Kubernetes Probe 완벽 정리 — livenessProbe / readinessProbe / startupProbe (0) | 2026.09.11 |
| Kubernetes YAML 설정 파일 완벽 정리 — 구조와 주요 리소스 예제 (0) | 2026.09.10 |
| Kubernetes RWX(ReadWriteMany) 완벽 정리 — 개념부터 실전 예제까지 (0) | 2026.09.09 |