Phần trước đo nhật ký ứng dụng. Sự kiện là nửa còn lại: nơi Kubernetes tự nói ra vì sao nó làm điều nó vừa làm.
Đúng một giờ
Cụm của tôi chạy liên tục nhiều giờ. Đọc toàn bộ sự kiện:
cũ nhất 61 phút trước
mới nhất 1 phút trước
tổng 623 sự kiện
Không có cấu hình nào đặt --event-ttl trong manifest của API server. 61 phút là mặc định, và nó là trần cứng.
Chỗ khác biệt lớn so với nhật ký: nhật ký hết hạn thì tệp đã xoay vòng vẫn còn trên đĩa node, moi ra được. Sự kiện hết hạn thì API server xoá khỏi etcd và không còn bản sao ở đâu cả.
Nên quy tắc thực hành duy nhất đáng nhớ về sự kiện là: chụp trước, đọc sau.
kubectl get events -A -o yaml > su-kien-$(date +%s).yaml
Ba mươi giây gõ lệnh này, hay một giờ sau ngồi đoán. Sự cố lúc 2 giờ sáng mà 9 giờ mới mở máy thì không còn gì để xem.
kubectl events thay cho kubectl get events
Từ 1.28 có một lệnh riêng, và nó tốt hơn hẳn:
kubectl events -n <ns> # sắp xếp theo thời gian sẵn
kubectl events --for pod/<ten> # chỉ một đối tượng
kubectl events -A --watch # theo dõi trực tiếp
kubectl get events mặc định sắp xếp theo tên, nên danh sách nhảy lung tung về thời gian — đo được thứ tự 6m1s, 16s, 16s, 16s, 27s, 6m. Ai cũng phải nhớ thêm --sort-by=.lastTimestamp, còn kubectl events làm sẵn.
Nó cũng hiện số lần gộp ngay trên dòng: 36s (x26 over 6m8s).
Gộp sự kiện, và con số dễ đọc nhầm
Một pod crashloop, sau sáu phút:
count |
reason |
lần cuối |
|---|---|---|
| 1 | Scheduled |
— |
| 6 | Pulled |
16:17:00 |
| 6 | Created |
16:17:00 |
| 6 | Started |
16:17:00 |
| 26 | BackOff |
16:19:38 |
Số lần khởi động lại thật sự: 5.
Kubernetes không tạo một bản ghi cho mỗi lần xảy ra. Sự kiện trùng nhau gộp vào một đối tượng, tăng count và cập nhật lastTimestamp. Nhờ vậy một pod hỏng không làm ngập etcd.
Nhưng chỗ này đọc rất dễ nhầm. Ba dòng Pulled/Created/Started dừng ở 16:17 — pod thôi khởi động lại từ lúc đó, vì backoff đã leo lên 5 phút. Trong khi BackOff vẫn phát đều mỗi khoảng mười giây và đếm tiếp tới 26.
Đọc BackOff x26 rồi kết luận "pod khởi động lại 26 lần" là sai gấp năm lần. Số đúng chỉ có một chỗ:
kubectl get pod <ten> -o jsonpath='{.status.containerStatuses[0].restartCount}'
Cách phân biệt tổng quát: count của sự kiện đếm số lần kubelet nói về một tình trạng, không đếm số lần tình trạng đó xảy ra. Với sự kiện mô tả trạng thái kéo dài — BackOff, FailedScheduling, Unhealthy — hai con số đó khác hẳn nhau.
Dấu hiệu nhận ra nhanh: so firstTimestamp với lastTimestamp. Khoảng cách chia cho count ra đúng vài giây thì đó là sự kiện lặp theo nhịp, không phải sự kiện đếm lần.
Sự kiện sống lâu hơn đối tượng
Tôi xoá hẳn một pod rồi đếm lại:
trước khi xoá 6 sự kiện
sau khi xoá 6 sự kiện
kubectl describe pod -> NotFound
Sự kiện không bị xoá theo. Với một pod đã biến mất — bị ReplicaSet thay, bị đuổi khỏi node, bị người khác xoá — sự kiện là dấu vết duy nhất còn lại.
Đây là công cụ mạnh nhất cho câu hỏi hay gặp nhất: "pod của tôi đâu rồi?"
kubectl events -A | grep -iE "evict|preempt|kill|oom"
Ba đáp án thường gặp nằm ngay trong đó: Evicted (node hết tài nguyên), Preempted (pod ưu tiên cao hơn chiếm chỗ), Killing (bị xoá có chủ ý). Sự kiện nói rõ ai làm và vì sao — thứ mà describe trên một pod không còn tồn tại không thể trả lời.
Nhưng vẫn trong giới hạn một giờ. Sau đó thì pod đó chưa từng tồn tại, xét theo mọi thứ cụm còn nhớ.
Các reason đáng thuộc
reason |
Nghĩa |
|---|---|
FailedScheduling |
Không node nào nhận, kèm lý do từng node |
Evicted |
kubelet đuổi vì node cạn tài nguyên |
Preempted |
Pod ưu tiên cao hơn chiếm chỗ |
Unhealthy |
Probe trượt — kèm luôn phản hồi thật |
FailedMount |
Volume không gắn được, thường là secret/configmap chưa có |
NodeNotReady |
Node mất liên lạc |
SuccessfulCreate |
ReplicaSet/Job tạo pod — có tên pod mới |
FailedScheduling là cái đáng đọc kỹ nhất: nó liệt kê từng nhóm node và lý do bị loại, đúng cái bộ lọc của scheduler đã tính. Đó là câu trả lời trực tiếp cho "vì sao pod vẫn Pending", không cần đoán.
Gửi sự kiện đi nơi khác
Hạn một giờ là lý do đủ để gom sự kiện ra ngoài. Ba cách, theo mức công sức:
kubectl events -A --watchghi ra tệp — thô sơ, nhưng dùng được ngay trong lúc điều tra.kube-state-metricsphơikube_pod_status_reasonvà bạn bè cho Prometheus — hợp để cảnh báo, không giữ nội dung thông điệp.- Một bộ xuất sự kiện chạy thường trực, đẩy sang nơi lưu nhật ký — giữ được đầy đủ.
Điều đáng cân nhắc trước khi bật cái thứ ba: sự kiện rất ồn. Cụm 623 sự kiện trong một giờ ở trên chỉ có mười mấy pod. Lọc theo type=Warning trước khi lưu là bước gần như bắt buộc.
Thử ba mươi giây
Xem sự kiện cảnh báo trong cụm, gom theo lý do:
kubectl get events -A --field-selector type=Warning -o json | python3 -c '
import sys, json
from collections import Counter
c = Counter()
for e in json.load(sys.stdin)["items"]:
c[(e["reason"], e["involvedObject"]["kind"])] += e.get("count", 1)
for (r, k), n in c.most_common(15):
print(f"{n:5d} {r:22} {k}")
'
Cụm khoẻ thì bảng này gần như trống. Có dòng nào đếm hàng trăm là chỗ đang lặp lại một lỗi mà chưa ai nhìn tới — và nó sẽ biến mất khỏi cụm sau một giờ nữa.
Phần sau: kubectl debug và ephemeral container — cách vào xem một pod không có shell, không có curl, không có gì cả.