PodDisruptionBudget bảo Kubernetes: đừng đuổi quá nhiều bản cùng lúc. Bài này đo nó bằng cách rút node ra bảo trì ba lần với ba cấu hình.

Ba kết quả của cùng một lệnh drain, và vì sao maxUnavailable an toàn hơn

Cùng một lệnh, ba kết quả

Deployment 4 bản, rút một node ra bảo trì:

kubectl drain
không có PDB 2,1 giây
PDB minAvailable: 4 không bao giờ xong
PDB minAvailable: 3 6,6 giây

Với minAvailable: 4 trên 4 bản:

cho-phep-duoi = 0

error when evicting pods/"pdb-...-m8bw4" -n "default": global timeout reached: 45s
error when evicting pods/"pdb-...-sns95" -n "default": global timeout reached: 45s

Một con số sai và node không bao giờ rút ra được.

Kubernetes không báo lỗi cấu hình — PDB đó hoàn toàn hợp lệ. Nó chỉ nghĩa là "không được đuổi bản nào", và drain tôn trọng điều đó mãi mãi.

Cột cho-phep-duoi là thứ nói thật

minAvailable=4    trên 4 bản   ->  cho-phep-duoi = 0    KẸT
minAvailable=3    trên 4 bản   ->  cho-phep-duoi = 1    chạy được
maxUnavailable=1  trên 4 bản   ->  cho-phep-duoi = 1    chạy được
kubectl get pdb

Cột ALLOWED DISRUPTIONS bằng 0 nghĩa là mọi việc bảo trì liên quan tới pod đó sẽ treo. Đây là một con số nên có trên bảng theo dõi, vì nó là dạng cấu hình sai không gây triệu chứng gì cho tới ngày bạn cần nâng cấp cụm.

maxUnavailable an toàn hơn minAvailable

minAvailable: 3     ->  cố định
maxUnavailable: 1   ->  luôn cho phép một, bất kể số bản

Với ứng dụng có HPA (phần 66), minAvailable là quả bom hẹn giờ:

  • Giờ cao điểm: 10 bản, minAvailable: 3 → cho phép đuổi 7. Rộng rãi.
  • Đêm tải thấp: HPA thu gọn về 3 bản → cho phép đuổi 0. Kẹt.

Và nó chỉ nổ vào đêm tải thấp — đúng lúc bạn muốn bảo trì.

maxUnavailable: 1 không có vấn đề đó: dù 3 bản hay 10 bản, luôn cho phép đuổi một.

Dùng tỉ lệ phần trăm cũng được nhưng cần cẩn thận: maxUnavailable: 25% trên 3 bản cho phép đuổi floor(0,75) = 0 — lại kẹt.

PDB chỉ áp cho việc đuổi tự nguyện

Đây là giới hạn quan trọng nhất và hay bị hiểu sai.

PDB chặn được:

  • kubectl drain (bảo trì node)
  • Cluster Autoscaler thu gọn (phần 68)
  • VPA giết pod để đổi requests (phần 67)
  • Bất cứ thứ gì dùng API eviction

PDB không chặn được:

  • Node chết đột ngột (phần 42)
  • OOMKilled (phần 54)
  • kubelet đuổi pod vì node hết RAM (phần 53)
  • kubectl delete pod trực tiếp
  • Vết NoExecute (phần 69 — đuổi trong 1,3 giây, không hỏi PDB)

Nghĩa là PDB không phải cơ chế bảo đảm tính sẵn sàng. Nó chỉ ngăn các công cụ tự động làm hỏng dịch vụ khi chúng đang làm việc theo kế hoạch.

Muốn sống sót qua sự cố thật thì cần đủ bản và rải chúng ra (phần 69), không phải PDB.

PDB cho StatefulSet là bắt buộc

Với Deployment không trạng thái, mất một bản trong lúc bảo trì thường chấp nhận được.

Với StatefulSet chạy hệ thống đồng thuận — etcd, ZooKeeper, cơ sở dữ liệu có bầu chọn — mất hai bản cùng lúc là mất quorum, và cụm ngừng hoạt động.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: {name: db}
spec:
  maxUnavailable: 1
  selector: {matchLabels: {app: db}}

maxUnavailable: 1 là con số đúng cho gần như mọi hệ thống ba bản: chịu được bảo trì tuần tự, không bao giờ mất quorum.

PDB không có selector khớp thì vô dụng

kubectl get pdb <ten> -o jsonpath='{.status.currentHealthy}'

Bằng 0 với deployment đang chạy nghĩa là selector không khớp pod nào — thường vì nhãn gõ sai.

PDB đó tồn tại, trông có vẻ đang bảo vệ, và không bảo vệ gì cả. Không có cảnh báo nào cho trường hợp này.

Ba con số nên kiểm định kỳ

kubectl get pdb -A -o custom-columns=\
NS:.metadata.namespace,TEN:.metadata.name,\
MIN:.spec.minAvailable,MAX:.spec.maxUnavailable,\
KHOE:.status.currentHealthy,\
CHO_PHEP:.status.disruptionsAllowed
  • KHOE bằng 0 → selector sai, PDB vô dụng.
  • CHO_PHEP bằng 0 → mọi bảo trì sẽ treo.
  • MIN có giá trị và ứng dụng có HPA → sẽ kẹt vào giờ tải thấp.

Ba dòng lệnh này đáng chạy trước mỗi lần nâng cấp cụm — chúng biến một sự cố bảo trì lúc nửa đêm thành một sửa đổi cấu hình lúc chiều.

Thử ba mươi giây

Thử xem cụm của bạn có rút node ra được không, mà không thật sự rút:

kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --dry-run=server

--dry-run=server cho Kubernetes tính toán đầy đủ mà không đuổi ai. Nếu nó báo pod nào không đuổi được, đó chính xác là thứ sẽ chặn bạn vào lần bảo trì thật.

Phần sau đo RBAC: ai được làm gì, và cách tìm ra quyền thừa.