롤링 업데이트(Rolling Update) 전략과 MaxSurge, MaxUnavailable 이해
현대의 클라우드 네이티브 인프라 환경에서 사용자는 서비스의 중단을 결코 용납하지 않습니다. 새로운 기능이 추가된 애플리케이션 버전을 배포하거나 치명적인 버그를 수정하여 패치할 때, 시스템을 잠시 내리고 올리는 방식(Downtime)은 과거의 유물이 되었습니다.
쿠버네티스는 이러한 무중단 배포(Zero-downtime Deployment)를 완벽하게 프레임워크 레벨에서 지원하며, 그 중심에는 롤링 업데이트(Rolling Update) 전략이 있습니다. 본 가이드에서는 쿠버네티스의 Deployment가 롤링 업데이트를 수행하는 내부 원리와, 이 과정의 속도와 안정성을 세밀하게 통제하는 두 가지 핵심 파라미터인 MaxSurge와 MaxUnavailable의 메커니즘을 심층적으로 해부합니다.

1. 롤링 업데이트의 핵심: 점진적 교체 알고리즘
롤링 업데이트는 이름 그대로, 구버전의 파드(Pod)들을 한꺼번에 삭제하지 않고 물결이 일듯 순차적으로 신버전 파드로 교체해 나가는 전략입니다.
Deployment 리소스의 명세서(YAML)에서 컨테이너 이미지 태그를 변경하고 적용(Apply)하면, 쿠버네티스 내부에서는 다음과 같은 점진적 교체 작업이 시작됩니다.
- 신규 ReplicaSet 생성: Deployment 컨트롤러는 새로운 설정이 적용된 파드들을 관리하기 위해 빈 껍데기 상태의 새로운 ReplicaSet(v2)을 생성합니다.
- 교차 스케일링(Cross-scaling): 새로운 ReplicaSet의 파드 개수를 조금씩 늘려가면서(Scale up), 동시에 기존 구형 ReplicaSet(v1)의 파드 개수를 조금씩 줄여나갑니다(Scale down).
- 트래픽의 자연스러운 전환: 쿠버네티스의 Service 객체는 라벨(Label) 셀렉터를 기반으로 작동하므로, 새롭게 구동되어
Ready상태가 된 신규 파드들에게 자연스럽게 사용자 트래픽을 분산시키기 시작합니다. - 완료: 모든 파드가 신버전으로 교체되고 구형 파드가 0개가 되면 업데이트 프로세스가 종료됩니다.
이 과정이 얼마나 빠르고 공격적으로 일어날지, 아니면 얼마나 보수적이고 안전하게 일어날지를 결정하는 것이 바로 MaxSurge와 MaxUnavailable 설정값입니다.
2. 배포를 통제하는 두 개의 밸브: MaxSurge와 MaxUnavailable
Deployment 명세서의 spec.strategy.rollingUpdate 하위에 위치하는 이 두 파라미터는 롤링 업데이트의 생명줄과 같습니다. 이 값들은 절대적인 숫자(예: 1, 2)나 백분율(예: 25%)로 설정할 수 있습니다.
2.1. MaxSurge (최대 초과 파드 수)
업데이트 과정에서 설정된 기본 파드 개수(Replicas)를 초과하여 임시로 얼마나 더 많은 파드를 생성할 수 있는가를 결정합니다.
- 예를 들어
replicas: 4인 상태에서MaxSurge: 1(또는 25%)로 설정했다면, 업데이트 도중 클러스터 내에 존재할 수 있는 파드의 최대 개수는 5개가 됩니다. - 이 값이 클수록 신버전 파드를 한 번에 많이 띄울 수 있으므로 배포 속도가 급격히 빨라집니다. 하지만 그만큼 노드(Node)의 CPU와 메모리 등 추가적인 인프라 리소스가 순간적으로 많이 필요하게 됩니다.
2.2. MaxUnavailable (최대 불가 파드 수)
업데이트 과정에서 동시에 서비스 불가능(Unavailable) 상태가 되어도 허용되는 파드의 최대 개수를 결정합니다.
- 예를 들어
replicas: 4인 상태에서MaxUnavailable: 1(또는 25%)로 설정했다면, 쿠버네티스는 업데이트 중에도 최소 3개(4 - 1)의 파드는 반드시 정상적으로 살아서 트래픽을 처리하도록 보장합니다. - 이 값이 클수록 구버전 파드를 한 번에 많이 죽일 수 있으므로 역시 배포 속도가 빨라집니다. 하지만 처리해야 할 트래픽이 남아있는 파드들에게 순간적으로 몰리게 되므로, 가용성이 떨어지고 시스템 부하가 발생할 위험이 커집니다.
3. 실전 시나리오로 이해하는 파라미터 튜닝 전략
애플리케이션의 특성과 인프라의 리소스 여유 상태에 따라 이 두 가지 값을 적절히 조합해야 합니다. 실무에서 널리 쓰이는 3가지 대표적인 전략 패턴을 살펴봅니다.
시나리오 A: 극단적인 안정성 추구 (보수적 배포)
- 설정:
MaxSurge: 1,MaxUnavailable: 0 - 동작: 구버전 파드를 절대 먼저 죽이지 않습니다. 무조건 신버전 파드를 1개 띄우고, 그 파드가 정상적으로 트래픽을 받을 준비가 끝나면 그때서야 구버전 파드를 1개 지웁니다.
- 장점:
MaxUnavailable이 0이므로, 배포 도중 단 한 번도 파드의 총 가용 용량(Capacity)이 원래의 목표치 아래로 떨어지지 않습니다. 사용자 경험 측면에서 가장 완벽한 무중단을 보장합니다. - 단점: 배포 속도가 가장 느리며, 신버전 파드를 먼저 띄울 수 있는 여유 리소스가 워커 노드에 반드시 확보되어 있어야 합니다.
시나리오 B: 쿠버네티스 기본값 (균형 잡힌 배포)
- 설정:
MaxSurge: 25%,MaxUnavailable: 25%(별도 설정이 없을 때의 디폴트 값) - 동작: 파드 개수가 4개라면
MaxSurge1개,MaxUnavailable1개가 적용됩니다. 즉, 최대 5개의 파드가 존재할 수 있으며, 최소 3개의 파드는 살아있어야 합니다. - 장단점: 배포 속도와 서비스 가용성, 그리고 인프라 리소스 소모량 사이의 가장 합리적인 균형을 유지합니다. 대부분의 일반적인 웹 서비스나 마이크로서비스에 적합합니다.
시나리오 C: 리소스가 극도로 부족한 환경
- 설정:
MaxSurge: 0,MaxUnavailable: 1(또는 그 이상) - 동작: 여유 인프라가 없어 파드를 더 띄울 수 없는 상태입니다. 따라서 신버전 파드를 띄우기 전에 구버전 파드를 먼저 1개 삭제하여 공간을 강제로 확보합니다.
- 장점: 추가적인 워커 노드 확장이나 여유 리소스 없이도 롤링 업데이트를 강행할 수 있습니다.
- 단점: 파드 1개 분량의 가용성이 떨어지므로(처리 능력 저하), 트래픽 피크 타임에 이 전략으로 배포할 경우 남은 파드들에 과부하가 걸려 연쇄적인 장애(Cascading Failure)가 발생할 위험이 높습니다.
4. 롤링 업데이트의 생명줄: Readiness Probe
MaxSurge와 MaxUnavailable을 아무리 정교하게 계산하더라도, 파드의 명세서에 Readiness Probe(준비성 프로브)가 설정되어 있지 않다면 롤링 업데이트는 최악의 대참사로 끝날 수 있습니다.
Deployment 컨트롤러가 "신버전 파드가 배포 완료되었다"라고 판단하고 다음 구버전 파드를 죽이는 기준은 오직 컨테이너 프로세스가 켜졌는지 여부가 아닙니다. 쿠버네티스는 해당 파드가 '진짜로 사용자 요청을 처리할 준비가 되었는지'를 파악해야 합니다.
- 만약 Java 기반의 Spring Boot 애플리케이션이라면, 컨테이너 셸이 실행된 후 JVM이 로딩되고 톰캣 서버가 올라가기까지 수십 초가 걸립니다.
- Readiness Probe가 없다면, 쿠버네티스는 컨테이너가 켜진 직후 1초 만에 "파드가 준비되었다"고 착각합니다. 그리고 트래픽을 아직 부팅 중인 신버전 파드로 쏟아버린 채, 멀쩡히 살아있던 구버전 파드들을 빛의 속도로 다 죽여버립니다. 결과적으로 수십 초 동안 서비스 전체가 먹통이 되는 장애가 발생합니다.
따라서 애플리케이션의 /health 엔드포인트를 주기적으로 찔러보아 200 OK 응답이 올 때만 파드의 상태를 Ready로 전환해 주는 Readiness Probe의 설정은 롤링 업데이트를 완벽하게 통제하기 위한 가장 중요한 전제 조건입니다.
롤링 업데이트는 낡은 부품을 떼어내고 새로운 부품을 끼워 넣는 비행 중인 비행기의 엔진 교체 작업과 같습니다. 클러스터 관리자는 MaxSurge와 MaxUnavailable이라는 두 개의 조종간을 쥐고, 인프라의 가용 리소스 상황과 비즈니스의 무중단 요구 수준을 정확히 파악하여 가장 최적화된 배포 속도를 설계해야 합니다.
'1. K8s Core & Architecture > 1.3. 파드(Pod)와 워크로드 아키텍처' 카테고리의 다른 글
| DaemonSet 동작 원리: 모든 노드에 파드를 보장하는 스케줄링 메커니즘 (0) | 2026.04.09 |
|---|---|
| StatefulSet 아키텍처: 상태를 가지는 애플리케이션의 식별자 유지 비결 (0) | 2026.04.09 |
| Deployment 리소스의 내부 동작: ReplicaSet을 어떻게 관리하는가? (0) | 2026.04.09 |
| Ephemeral Containers: 실행 중인 파드 디버깅을 위한 혁신 (0) | 2026.04.08 |
| 사이드카 컨테이너 (Sidecar Containers) 기본 지원 (v1.28+) 아키텍처 분석 (0) | 2026.04.08 |