Vấn đề: Bế tắc trong bảo trì
Bạn đã bao giờ thử drain một node và rồi chỉ biết đứng nhìn terminal bị treo vô thời hạn chưa? Bạn có lẽ đang thực hiện việc bảo trì node định kỳ—có thể là vá lỗi hệ điều hành hoặc thay đổi kích thước instance—nhưng tiến trình này không hề dịch chuyển. Bạn chạy lệnh kubectl drain <node-name>, và thay vì node đó được dọn trống, bạn lại thấy lỗi này lặp lại sau mỗi vài giây:
error when evicting pods/"api-gateway-v2-7c4d98bf9-xyz1" (assigned to "worker-node-01"):
Cannot evict pod as it would violate the pod's disruption budget.
evicting pod default/api-gateway-v2-7c4d98bf9-xyz1
error when evicting pods/"api-gateway-v2-7c4d98bf9-xyz1": Cannot evict pod...
Kubernetes hành xử như vậy vì một PodDisruptionBudget (PDB) đang thực hiện nhiệm vụ duy nhất của nó: giữ cho ứng dụng của bạn luôn trực tuyến. Tuy nhiên, một cấu hình quá nghiêm ngặt có thể vô tình biến "lưới an toàn" thành một rào cản ngăn chặn cluster quản lý phần cứng của chính nó.
Bước 1: Xác định PDB đang gây nghẽn
Bắt đầu bằng cách tìm PDB cụ thể đang cản trở việc drain. Chạy lệnh này trong namespace bị ảnh hưởng:
kubectl get pdb -n <your-namespace>
Việc rà soát các cột dữ liệu trả về là rất quan trọng. Hãy tập trung vào ALLOWED DISRUPTIONS. Nếu giá trị đó là 0, Eviction API sẽ từ chối tác động đến bất kỳ pod nào chịu sự quản lý của ngân sách đó. Không ngoại lệ.
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
api-gateway-pdb 1 N/A 0 12d
Bước 2: Tại sao các gián đoạn bị chặn?
Việc không cho phép gián đoạn (zero allowed disruptions) thường do ba tình huống phổ biến sau:
1. Cái bẫy Single-Replica
Nếu bạn có replicas: 1 trong Deployment và PDB được thiết lập là minAvailable: 1, bạn đã tạo ra một điểm bế tắc. Để di chuyển pod, Kubernetes phải xóa pod hiện tại. Nhưng việc xóa nó sẽ làm số lượng pod giảm xuống 0, vi phạm quy tắc "tối thiểu 1" của bạn. Hệ thống sẽ không xóa pod để nhường chỗ cho pod mới vì điều đó sẽ gây ra gián đoạn tạm thời.
2. Khoảng cách về năng lực thực tế (Healthy Capacity Gap)
Hãy tưởng tượng một Deployment có 3 replicas và một PDB yêu cầu minAvailable: 3. Nếu một pod đã bị lỗi—có lẽ do CrashLoopBackOff hoặc ImagePullBackOff—bạn chỉ còn 2 pods khỏe mạnh. Vì bạn đã ở dưới mức tối thiểu yêu cầu, Kubernetes sẽ khóa các pods còn lại để ngăn chặn tình trạng tồi tệ hơn.
3. Lỗi cấu hình '100%'
Việc thiết lập minAvailable: 100% nói với Kubernetes rằng bạn không bao giờ muốn bất kỳ một pod nào ngoại tuyến để bảo trì. Điều này hiếm khi là thứ bạn thực sự muốn cho một hệ thống phân tán, vì nó khiến việc nâng cấp node trở nên bất khả thi nếu không có sự can thiệp thủ công.
Bước 3: Giải quyết điểm nghẽn
Chọn phương án phù hợp với mức độ chấp nhận rủi ro hiện tại của bạn.
Giải pháp A: Scale Up tạm thời (Cách xử lý sạch nhất)
Cách an toàn nhất để giải tỏa việc drain là cung cấp cho ngân sách một chút "không gian để thở". Nếu PDB yêu cầu 1 pod sẵn sàng và bạn chỉ có 1, hãy scale deployment lên 2. Khi pod thứ hai ở trạng thái Ready trên một node khác, ALLOWED DISRUPTIONS sẽ chuyển thành 1, và việc drain sẽ tự động tiếp tục.
kubectl scale deployment api-gateway --replicas=2 -n <namespace>
Giải pháp B: Chuyển sang dùng maxUnavailable
Đối với các workload nhỏ, maxUnavailable thường trực quan hơn. Chỉnh sửa PDB để cho phép 1 pod bị dừng hoạt động sẽ an toàn hơn là bắt buộc một số lượng cụ thể các pods phải duy trì trong quá trình scale-down.
# Mở PDB để chỉnh sửa
kubectl edit pdb api-gateway-pdb -n <namespace>
# Thay thế minAvailable bằng:
maxUnavailable: 1
Giải pháp C: Tùy chọn 'mạnh tay' (Cách xử lý nhanh nhất)
Nếu bạn đang ở giữa khung giờ bảo trì và có thể chấp nhận một khoảng gián đoạn ngắn tầm 30 giây, chỉ cần xóa PDB. Lệnh kubectl drain sẽ ngay lập tức evict pod. Bạn có thể tạo lại PDB sau khi node đã hoạt động trở lại.
kubectl delete pdb api-gateway-pdb -n <namespace>
Bước 4: Xác minh
Kiểm tra trạng thái PDB lần cuối. Bạn cần thấy ALLOWED DISRUPTIONS ở mức 1 hoặc cao hơn.
kubectl get pdb -n <namespace>
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
api-gateway-pdb N/A 1 1 12d
Tiến trình kubectl drain của bạn bây giờ sẽ tiếp tục, di chuyển các pods sang các node khác và cho phép node mục tiêu chuyển sang trạng thái SchedulingDisabled trước khi tắt máy.
Bài học cho lần sau
- Tránh sử dụng 100% minAvailable: Đây là công thức dẫn đến việc cluster bị treo. Hãy sử dụng tỷ lệ phần trăm như 50% hoặc 80%.
- Các Pod đơn lẻ không cần PDB: Nếu một ứng dụng không thể scale lên 2+ replicas, một PDB với
minAvailable: 1chỉ tạo thêm rắc rối trong quá trình nâng cấp. - Sử dụng maxUnavailable: 1: Đối với các cluster nhỏ, cách này thường linh hoạt hơn việc tính toán giá trị
minAvailable. - Giám sát Allowed Disruptions: Sử dụng các cảnh báo Prometheus để tìm các PDB có 0 allowed disruptions trước khi bạn bắt đầu khung giờ bảo trì.

