IT/Kubernets

PodDisruptionBudget 실전 설정 가이드

gfrog 2026. 7. 7. 09:11
SMALL

노드 drain 걸었는데 특정 파드가 계속 evict 안 되고 남아 있던 적, 다들 한 번쯤 있을 거다. 반대로 drain 명령 하나로 서비스가 순간적으로 다 내려가서 알람이 우수수 뜬 경험도. 이 두 상황 사이의 균형을 잡아주는 게 PodDisruptionBudget(PDB)인데, 막상 실무에서 어떻게 세팅해야 할지는 문서만 봐서는 잘 안 잡힌다.

우리 팀도 노드 수십 대짜리 EKS 클러스터에서 Karpenter로 consolidation을 돌리면서 몇 번 삽질을 했다. PDB 하나 잘못 걸어서 consolidation이 몇 시간씩 멈춰 있던 적도 있고. 그래서 지금 팀 안에서 굳어진 룰 위주로 정리해본다.

minAvailable vs maxUnavailable, 뭘 쓸까

이거 은근히 헷갈리는데, 결론부터 말하면 상황에 따라 다르다.

stateless 서비스는 maxUnavailable. 이유는 단순하다. 레플리카 수가 늘어나거나 줄어도 자동으로 스케일된다. HPA를 붙여 놓은 웹 API에 minAvailable: 5를 걸어두면, 트래픽이 줄어서 레플리카가 3까지 떨어졌을 때 PDB가 영원히 disruption을 막아버린다. 이 경우 maxUnavailable: 25% 같은 비율 지정이 훨씬 안전하다.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-api-pdb
spec:
  maxUnavailable: 25%
  selector:
    matchLabels:
      app: web-api

quorum이 필요한 stateful 서비스는 minAvailable. etcd, ZooKeeper, Consul 같은 것들. 3-node etcd라면 minAvailable: 2. 5-node라면 minAvailable: 3. 여기서 퍼센트 쓰면 안 된다. 정수로 하드코딩해야 quorum이 깨질 상황을 확실히 막을 수 있다.

절대 하지 말아야 할 설정

minAvailable: 1을 replicas가 1인 Deployment에 걸면 어떻게 될까? disruptionsAllowed가 영원히 0이다. 노드 drain은 무한 대기. Cluster Autoscaler는 scale down을 못 하고, Karpenter는 consolidation을 못 한다. 우리 팀도 이거 때문에 노드 요금이 이상하게 안 떨어져서 확인해봤더니, 어떤 개발자가 dev 환경 pod에 replicas 1 + PDB minAvailable 1로 걸어놓은 걸 발견했다. 클러스터 청소하는 데 하루 걸렸다.

싱글 레플리카 워크로드에는 PDB를 걸지 않거나, 걸더라도 maxUnavailable: 1로 걸어야 한다. 이러면 최소한 disruption이 가능해진다.

unhealthyPodEvictionPolicy: AlwaysAllow

이거 최근에야 안정화된 필드인데, 실무에서 정말 유용하다. K8s 1.31에서 stable로 승격됐고, 기본값은 여전히 IfHealthyBudget이다.

문제 상황: CrashLoopBackOff 상태의 파드가 있을 때, 기본 정책이면 이 파드도 PDB의 "healthy" 카운트에 안 들어가서 노드 drain이 막힐 수 있다. 파드가 이미 죽어 있는데도 evict 못 하는 이 상황.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-api-pdb
spec:
  maxUnavailable: 25%
  unhealthyPodEvictionPolicy: AlwaysAllow
  selector:
    matchLabels:
      app: web-api

AlwaysAllow로 두면 Ready 상태가 아닌 파드는 언제든 evict 가능하다. 이걸 켜두고 나서 우리 팀은 야간에 노드 drain이 걸려서 페이지 받는 일이 눈에 띄게 줄었다. 새 클러스터 세팅할 땐 거의 반사적으로 넣는다.

검증은 어떻게 하나

PDB가 실제로 잘 걸려있는지 보려면:

kubectl get pdb -A

출력에서 ALLOWED DISRUPTIONS 컬럼을 확인한다. 이게 0으로 뜨는 게 있으면 그 워크로드는 drain이 막혀 있다는 뜻이다. 정상적인 상황(예: 롤아웃 중)일 수도 있지만, 상시 0이면 위에서 말한 함정에 걸린 거다.

CI 단계에서 미리 잡고 싶다면 kyverno나 OPA Gatekeeper로 "replicas 1인 Deployment에 minAvailable 1 PDB 금지" 룰을 걸어두는 게 좋다. 실제로 우리 팀 클러스터에는 이 룰이 admission에 들어가 있다.

마무리

PDB는 "설정 하고 잊어버리는" 리소스가 아니다. 워크로드가 스케일 아웃/인 하면서 상황이 바뀌기 때문에 주기적으로 점검해야 한다. 특히 노드 오토스케일러나 Karpenter를 쓰는 클러스터라면 잘못 걸린 PDB 하나가 비용에 직접 영향을 준다.

혹시 다른 팀에서 쓰는 PDB 패턴 있으면 댓글로 공유해주면 좋겠다. 특히 stateful 워크로드 쪽은 우리도 아직 실험 중이라.

BIG