Hình dung một quy định nhân sự: "không được cho quá nhiều người nghỉ phép cùng lúc, để văn phòng luôn có người trực". Hợp lý. Nhưng nếu ai đó viết nó thành "luôn phải có mặt đủ cả bốn người" trong một nhóm bốn người, thì hệ quả là không ai xin nghỉ được nữa — kể cả để đi khám bệnh bắt buộc. Quy định nghe như bảo vệ, thực ra khoá cứng. PodDisruptionBudget của Kubernetes tạo ra đúng cái bẫy này, và tệ hơn: nó chỉ lộ ra vào đúng ngày bạn cần bảo trì. Bài này đo nó bằng cách rút node ra ba lần với ba cấu hình.
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 podtrự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
KHOEbằng 0 → selector sai, PDB vô dụng.CHO_PHEPbằng 0 → mọi bảo trì sẽ treo.MINcó 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.
Mẫu số chung: ràng buộc tuyệt đối thành bẫy khi quy mô đổi, và một rào chỉ che một lớp sự kiện
Bài này gói hai bài học về cách đặt ràng buộc, đúng ở mọi hệ. Thứ nhất: một ràng buộc ghi bằng con số tuyệt đối sẽ âm thầm sai khi cái nền mà nó dựa vào thay đổi — hãy ghi nó tương đối với nền hiện tại. minAvailable: 3 là một sàn cứng; khi HPA thu số bản về 3, sàn đó bỗng nghĩa là "không được đụng ai", và nó kẹt đúng vào đêm tải thấp. maxUnavailable: 1 an toàn vì nó nói về biến động cho phép chứ không về tổng phải giữ. Cùng cái bẫy khắp nơi: một timeout, một kích thước buffer, một ngưỡng quorum "cần 4 máy sống" hardcode cứng trong một cụm tự co giãn; một min của connection pool đặt bằng số tuyệt đối. Và cẩn thận với phần trăm ở quy mô nhỏ: 25% của 3 làm tròn xuống 0 — ràng buộc tương đối vẫn sập nếu quên chuyện làm tròn. Nguyên tắc: khi cái nền có thể thay đổi, đừng ghim ràng buộc vào một con số cố định.
Thứ hai: phải biết một cơ chế an toàn che lớp sự kiện nào — "xử lý được gián đoạn có kế hoạch" không phải "bảo đảm luôn sẵn sàng". PDB chặn drain, autoscaler, VPA — những việc tự nguyện, có kế hoạch — nhưng bất lực trước node chết, OOM, kill -9. Lẫn hai lớp này là ảo giác an toàn. Cùng họ với một graceful shutdown handler không bao giờ chạy khi máy mất điện hay bị SIGKILL; một try/finally bị kill -9 bỏ qua; một WAF canh tầng HTTP nhưng không canh CSDL phía sau; một bản backup chống xoá nhầm nhưng không chống hỏng dữ liệu tự nhân bản sang bản sao. Luôn hỏi: rào này che loại sự cố nào, và loại nào nó để lọt.
Mẫu số chung: ghi ràng buộc tương đối với nền khi nền còn thay đổi (và coi chừng làm tròn ở N nhỏ); rồi xác định rõ rào chắn của mình che lớp sự kiện nào — vì cái nó không che mới là cái làm bạn ngã.
Muốn tự soi, 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.