Pod 'Ma' Đầy Phiền Toái
Chúng ta đều đã từng gặp tình huống này. Bạn chạy lệnh kubectl delete pod, đợi vài giây, rồi chạy get pods chỉ để thấy trạng thái vẫn nằm ở Terminating. Phút biến thành giờ, và pod đơn giản là không chịu biến mất. Thường thì nó trông như thế này:
NAME READY STATUS RESTARTS AGE
web-server-v2-7x 1/1 Terminating 0 14h
Nếu bạn tìm hiểu kỹ hơn bằng lệnh kubectl describe pod web-server-v2-7x, bạn sẽ thấy một thông báo xác nhận pod bị kẹt vì DeletionTimestamp đã được thiết lập, nhưng thời gian ân hạn (thường là 30 giây) đã hết hạn từ lâu.
Tại Sao Pod Của Bạn Không Chịu 'Chết'
Thủ phạm hầu như luôn là một Finalizer. Hãy coi finalizer như một ô tích trong danh sách kiểm tra trước khi bay. Nó báo cho Kubernetes: "Đợi đã! Đừng xóa đối tượng này cho đến khi tôi dọn dẹp xong."
Mặc dù finalizers được thiết kế để ngăn mất dữ liệu, chúng thường bị kẹt vì vài lý do:
- Node không phản hồi: Node worker bị tắt nguồn hoặc mất kết nối mạng, nên
kubeletkhông thể xác nhận pod đã biến mất. - Lỗi lưu trữ: Một volume bên ngoài, như đĩa AWS EBS hoặc Azure Disk, không thể gỡ bỏ sau thời gian chờ tiêu chuẩn 6 phút.
- Zombie Controllers: Một custom operator hoặc controller chịu trách nhiệm dọn dẹp đã bị crash hoặc chính nó đã bị xóa.
- Phân đoạn mạng (Network Partitions): API server không thể giao tiếp với node để xác minh trạng thái của pod.
Giải Pháp: Từng Bước Khôi Phục
Bước 1: Xác Định Finalizer Bị Kẹt
Trước khi bắt đầu can thiệp sâu, hãy xem điều gì thực sự đang giữ "cánh cửa" mở. Xuất cấu hình pod sang YAML và kiểm tra phần metadata:
kubectl get pod web-server-v2-7x -o yaml
Cuộn xuống khối metadata.finalizers. Bạn có thể sẽ thấy các mục như sau:
metadata:
finalizers:
- kubernetes.io/pvc-protection
- custom-cleanup-logic.io/wait-for-log-flush
Bước 2: Kiểm Tra Thời Gian Chờ Xóa
Biết chính xác pod đã bị treo trong bao lâu sẽ rất hữu ích. Điều này giúp bạn quyết định xem mình đang đối mặt với sự chậm trễ tạm thời hay một tình trạng khóa vĩnh viễn. Trích xuất mốc thời gian bằng lệnh sau:
kubectl get pod web-server-v2-7x -o jsonpath='{.metadata.deletionTimestamp}'
Nếu kết quả hiển thị thời gian từ ba giờ trước, rõ ràng việc dọn dẹp tự động đã thất bại.
Bước 3: Xóa Sạch Finalizers Bằng Lệnh Patch
Cách đáng tin cậy nhất để loại bỏ một pod bị kẹt là xóa danh sách finalizers một cách thủ công. Bằng cách đặt danh sách thành null, về cơ bản bạn đang bảo Kubernetes bỏ qua danh sách kiểm tra và xóa tài nguyên ngay lập tức.
Thực thi lệnh patch sau:
kubectl patch pod web-server-v2-7x -p '{"metadata":{"finalizers":null}}' --type=merge
Pod sẽ biến mất khỏi danh sách của bạn ngay lập tức.
Bước 4: Giải Pháp Cuối Cùng (Xóa Cưỡng Bức)
Nếu lệnh patch không hiệu quả—điều này hiếm khi xảy ra—bạn có thể bỏ qua hoàn toàn xác nhận từ kubelet. Sử dụng cờ force với thời gian ân hạn bằng 0:
kubectl delete pod web-server-v2-7x --grace-period=0 --force
Cảnh báo: Hãy thận trọng khi sử dụng lệnh này. Việc xóa cưỡng bức một pod trong khi node của nó vẫn đang chạy có thể dẫn đến việc hai instance của cùng một pod chạy song song nếu một Deployment cố gắng thay thế nó ngay lập tức.
Xác Minh và Phòng Ngừa
Kiểm tra namespace của bạn lần cuối: kubectl get pods. Pod "ma" sẽ biến mất. Nếu bạn đang sử dụng Deployment, một pod mới khỏe mạnh sẽ được thay thế.
Khi tôi xử lý các sự cố treo pod này ở nhiều múi giờ khác nhau, tôi thường sử dụng Timestamp Converter trên ToolCraft. Đó là một cách nhanh chóng để chuyển chuỗi 2023-10-27T14:22:11Z sang giờ địa phương. Điều này giúp tôi đối chiếu thời điểm pod bị lỗi với các lỗi cụ thể trong log ELK hoặc Datadog.
Để giữ cho cụm của bạn luôn sạch sẽ trong tương lai:
- Theo dõi sát sao sức khỏe của node; một node ở trạng thái NotReady là nguyên nhân số 1 khiến pod bị kẹt.
- Kiểm tra log của CSI driver nếu các finalizer liên quan đến lưu trữ liên tục bị treo.
- Chỉ sử dụng custom finalizers nếu controller của bạn được đảm bảo thiết lập có tính sẵn sàng cao (high-availability).

