야간에 노드를 점검하려고 kubectl drain을 돌렸더니, 해당 노드의 Pod가 한꺼번에 쫓겨나면서 잠깐 서비스가 5xx를 뱉었습니다. 레플리카가 3개여도 의미가 없었던 건, 마침 3개가 같은 노드에 몰려 있었거나 드레인이 한 번에 다 비웠기 때문입니다. 이런 자발적 중단(voluntary disruption) 으로부터 최소 가용 Pod 수를 지켜주는 장치가 PodDisruptionBudget(PDB)입니다.
PDB가 막는 것과 못 막는 것
PDB는 "운영자가 의도적으로 일으키는 중단"에만 작동합니다.
| 중단 종류 | 예시 | PDB 적용 |
|---|---|---|
| 자발적 중단 | kubectl drain, 노드 업그레이드, 클러스터 오토스케일 축소 | 적용됨 |
| 비자발적 중단 | 노드 하드웨어 장애, OOM 킬, 커널 패닉 | 적용 안 됨 |
즉 PDB는 장애 방어가 아니라, 계획된 작업 중에 한꺼번에 너무 많이 내려가지 않게 막는 가드레일입니다.
minAvailable vs maxUnavailable
핵심 필드는 둘 중 하나만 씁니다.
YAML
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2 # 항상 최소 2개는 살아있어야 함
selector:
matchLabels:
app: web
maxUnavailable을 쓰면 "동시에 내려갈 수 있는 최대 개수"로 표현합니다.
YAML
spec:
maxUnavailable: 1 # 한 번에 1개까지만 내려감
선택 기준은 단순합니다.
| 상황 | 권장 필드 |
|---|---|
| 레플리카 수가 고정·소수(3~5) | minAvailable: N (예: 2) |
| 레플리카가 오토스케일로 변동 | maxUnavailable: 1 또는 25% |
| 최소 정족수가 중요한 상태 저장 앱 | minAvailable로 정족수 명시 |
비율(50%)도 쓸 수 있지만, 레플리카가 1개면 minAvailable: 1은 드레인을 영원히 막아버리니 주의합니다.
적용과 확인
Kubernetes
kubectl apply -f web-pdb.yaml
kubectl get pdb web-pdb
출력의 ALLOWED DISRUPTIONS 값이 핵심입니다.
OUTPUT
NAME MIN AVAILABLE ALLOWED DISRUPTIONS AGE
web-pdb 2 1 10s
ALLOWED DISRUPTIONS가 0이면 그 순간엔 어떤 Pod도 자발적으로 못 내려갑니다. 이 상태에서 drain을 걸면 PDB를 만족할 때까지 블로킹됩니다.
체크리스트
Kubernetes
# 1. PDB가 가리키는 selector가 실제 Pod와 맞는지
kubectl get pods -l app=web
# 2. 허용 가능한 중단 수가 0이 아닌지
kubectl get pdb web-pdb -o jsonpath='{.status.disruptionsAllowed}'
# 3. drain이 PDB를 존중하는지 테스트
kubectl drain <node> --ignore-daemonsets --dry-run=server
minAvailable이 레플리카 수와 같으면 드레인이 멈춰버리니, 항상 레플리카 - 1 이하로 잡는 게 안전합니다.
PDB를 만들어 직접 drain을 걸어보며 드레인이 멈추는 순간을 관찰하는 실습은 쿠버네티스 트랙에서 회원가입 없이 무료로 해볼 수 있습니다.