Pod Disruption Budget (PDB) とは - Kubernetes の可用性を守る設定方法
PDB は Kubernetes でノードメンテナンス時に同時停止できる Pod 数を制限するリソース。maxUnavailable と minAvailable の使い分け / YAML 設定例を解説
Pod Disruption Budget とは
Pod Disruption Budget (PDB) は、Kubernetes でノードのメンテナンスやクラスターアップグレードなどの自発的な中断 (Voluntary Disruption) 時に、同時に停止できる Pod 数を制限するリソースである。PDB がなければ、kubectl drain は対象ノード上の Pod をまとめて退避させるため、レプリカがそのノードに偏っていればサービスが止まる。
効く経路は 1 本だけで、PDB は退避 API (Eviction API) を通る削除にしか関与しない。kubectl drain や Cluster Autoscaler はこの API を呼ぶので制限を受けるが、kubectl delete pod や Deployment そのものの削除は PDB を素通りする。ここを押さえずに「Pod が減らないようにする鍵」と読むと、保護範囲を大きく見誤る。
policy/v1alpha1 として Kubernetes 1.4 に入り、1.5 で beta (policy/v1beta1)、1.21 で policy/v1 として GA になった。policy/v1beta1 は 1.25 で提供終了しているため、古い記事の YAML をそのまま貼ると新しいクラスターでは通らない。本番環境で Kubernetes を運用するなら、ステートレスな API サーバーであっても PDB の設定は必須と考えてよい。
基本的な設定
レプリカ 3 の API に対して、常に 2 Pod を残す最小の例を示す。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: production
spec:
minAvailable: 2 # 最低 2 つの Pod が常に稼働
selector:
matchLabels:
app: api
この設定により、app: api ラベルを持つ Pod のうち、常に最低 2 つが稼働していることが保証される。3 Pod 中 1 Pod のドレインは許可されるが、2 Pod 目のドレインは 1 Pod 目の代替が Ready になるまで拒否される。ここで言う「本来あるべき Pod 数」は PDB 側の設定値ではなく、Pod の所有者 (Deployment や StatefulSet) の spec.replicas から計算される点に注意したい。所有者を持たない裸の Pod では割合指定が機能しない。
minAvailable と maxUnavailable の使い分け
PDB には 2 つの指定方法がある。両方を同時に指定することはできない。
| 設定 | 意味 | 5 Pod の場合 | 適するケース |
|---|---|---|---|
| minAvailable: 3 | 最低 3 Pod が稼働 | 同時に 2 Pod まで停止可 | 最低稼働数が明確な場合 |
| maxUnavailable: 1 | 最大 1 Pod が停止 | 同時に 1 Pod まで停止可 | レプリカ数が変わっても指定を変えたくない場合 |
| minAvailable: "80%" | 80% が稼働 | 同時に 1 Pod まで停止可 | 割合で可用性を決めたい場合 |
実務では maxUnavailable: 1 が最も使いやすい。Pod 数が HPA (Horizontal Pod Autoscaler) で動的に変わる環境でも、「同時に 1 つまで」という制約が直感的に機能する。一方 minAvailable を絶対数で書くと、レプリカ数を減らしたときに停止を許す枠がゼロへ縮み、ドレインが止まる側に倒れる。
割合指定は端数の丸め方に癖がある。minAvailable を割合で書くと必要稼働数は切り上げで、7 Pod に "50%" を指定すると 3 ではなく 4 Pod が必要になる。maxUnavailable を割合で書いた場合も停止を許す Pod 数が切り上げになるため、実際の停止許容量は指定した割合より大きくなり得る。1 Pod のずれが致命的な構成では絶対数で書く方が読み違えが少ない。
紛らわしいのは、PDB がローリング更新そのものを縛らないことだ。更新で消えた Pod や未稼働の Pod は budget を消費する一方、Deployment や StatefulSet のローリング更新自体は PDB では制限されない。更新中の同時停止数は workload 側の maxUnavailable / maxSurge で決める。
Voluntary Disruption と Involuntary Disruption
PDB が保護するのは Voluntary Disruption (自発的な中断) のみだ。
| 種類 | 例 | PDB で保護 |
|---|---|---|
| Voluntary (退避 API 経由) | kubectl drain、クラスターアップグレード、Cluster Autoscaler のノード削減 | される |
| Voluntary (直接削除) | kubectl delete pod、Deployment の削除、Pod テンプレートの更新 | されない |
| Involuntary | ノードのハードウェア障害、カーネルパニック、ノードのリソース枯渇による退避 | されない |
自発的な中断でも保護されるのは退避 API を通る操作だけで、Pod や Deployment を直接削除する操作は PDB を迂回する。「PDB があるから誤削除は防げる」という期待は成り立たない。
ノードが突然クラッシュした場合も PDB は止められない。ただし落ちた Pod は稼働数を押し下げるので、非自発的な中断で 1 Pod 失った直後は自発的な退避に使える枠がその分狭まる。障害直後にドレインが進まないのはこの計算のためで、PDB の設定ミスではない。非自発的な中断そのものへの対策は、Pod Anti-Affinity や topologySpreadConstraints で Pod を複数ノード・複数ゾーンへ分散させることだ。
PDB がないとどうなるか
PDB を設定していないと、kubectl drain は対象ノード上の Pod をまとめて退避させ、代替 Pod が Ready になるのを待たない。3 台のノードに 3 Pod が分散していても、2 ノードを続けてドレインすれば 2/3 の Pod が同時に入れ替わり、起動の遅いアプリでは残る 1 Pod に全トラフィックが乗る。
EKS のマネージドノードグループ更新は既定で 1 ノードずつ (更新設定の maxUnavailable で並列数を上げられる) 置き換える。PDB がなければ置き換えのたびに Pod がまとまって落ちるため、アップグレード中にサービスが断続的に劣化する。逆に PDB が厳しすぎると 15 分待っても Pod が退避できず、更新は PodEvictionFailure で止まる。強制指定を付けて再実行すれば Pod を直接削除して先へ進むが、それは PDB による保護を捨てることと同じだ。厳しすぎる PDB は「守り」ではなく運用の詰みになる。
実務での設定指針
ステートレスな API サーバー
spec:
maxUnavailable: 1
1 Pod ずつ停止し、新しいノードで起動してから次の Pod を停止する。レプリカ数が 3 以上であれば、常に 2 Pod 以上が稼働する。
StatefulSet (データベース、キャッシュ)
spec:
minAvailable: 2
クォーラムを維持するため、過半数の Pod が常に稼働していることを保証する。3 ノードの etcd クラスターなら minAvailable: 2 で、1 ノードずつのメンテナンスが可能になる。
バッチ処理 / CronJob
PDB なしでも可。中断されてもリトライで対応できる設計にする。ただし、長時間実行のバッチで中断コストが高い場合は PDB を設定する。
よくある落とし穴
minAvailable をレプリカ数と同じにする
minAvailable: 3 でレプリカ数も 3 の場合、1 Pod も停止できなくなる。退避要求は拒否され続け、kubectl drain はタイムアウトまで再試行を繰り返すだけでノードのメンテナンスが終わらない。必ずレプリカ数より小さい値を設定する。
HPA のスケールダウンは PDB では止まらない
「minAvailable を絶対数にすると HPA のスケールダウンが PDB にブロックされる」という説明を見かけるが、これは誤りだ。HPA が変えるのは Deployment の replicas で、余った Pod を消すのは ReplicaSet コントローラーによる直接削除であり、退避 API を通らないため PDB は関与しない。実際に困るのは逆向きで、レプリカ数が minAvailable まで縮むと自発的な退避の枠がゼロになり、その後のノードドレインが進まなくなる。HPA の minReplicas より小さい minAvailable にする、あるいは maxUnavailable で書くのが安全側だ。
1 つの Pod を複数の PDB が覆う
セレクターが重なる PDB を 2 つ作ると、退避 API は複数の PDB に覆われた Pod の退避を一律で拒否する。どちらの budget に余裕があっても退避できない。namespace 全体を覆う PDB を後から足したときに起きやすく、ドレインが理由不明で止まる典型例だ。定義を差し替える移行期を除き、セレクターは重ねない。
CrashLoopBackOff の Pod がドレインを止める
unhealthyPodEvictionPolicy の既定値 IfHealthyBudget では、Running だが Ready になっていない Pod は budget に余裕があるときしか退避できない。設定ミスやバグで壊れた Pod を PDB が守り続け、ノードのドレインがそこで停止する。Kubernetes 1.31 で安定したこのフィールドに AlwaysAllow を明示しておけば健全でない Pod は budget に関わらず退避でき、公式ドキュメントもノードドレインを進めるためにこの指定を推奨している。
より深く学ぶには関連書籍が役立つ。
この記事は役に立ちましたか?
関連用語
Kubernetes
コンテナのデプロイ、スケーリング、管理を自動化するオープンソースのオーケストレーションプラットフォーム
Kubernetes ローリングアップデート
Pod を段階的に新バージョンに置き換え、ゼロダウンタイムでアプリケーションを更新するデプロイ戦略
オートスケーリング
トラフィックや負荷に応じてコンピュートリソースを自動的に増減させる仕組み
Liveness/Readiness プローブ
Kubernetes がコンテナの生存状態と受信準備状態を判定するためのヘルスチェック機構
Resource Quota
Kubernetes の Namespace ごとに CPU / メモリ / オブジェクト数の上限を定め、1 つのチームがクラスターを占有するのを防ぐ仕組み
Service
Kubernetes で Pod 群への安定したネットワークアクセスを提供する抽象化リソース