Quan Sát và Gỡ Lỗi: logs, exec, describe, events
Lý thuyết đẹp đến đâu, ngày làm việc thật của bạn với Kubernetes phần lớn là gỡ lỗi: pod kẹt Pending, container CrashLoopBackOff, service không nhận traffic. Bài này không thêm khái niệm mới — nó rèn phản xạ: khi có sự cố, nhìn vào đâu, theo thứ tự nào. Ta học qua hai ca hỏng kinh điển, tái hiện thật trên minikube.
Bộ công cụ và thứ tự dùng
Khi một pod không ổn, đây là trình tự nên theo:
1. kubectl get pods → STATUS gì? RESTARTS bao nhiêu? (cái nhìn đầu tiên)
2. kubectl describe pod <p> → mục Events: VÌ SAO ra nông nỗi này (quan trọng nhất)
3. kubectl logs <p> → app BÊN TRONG nói gì (lỗi ứng dụng)
4. kubectl exec -it <p> -- sh → vào trong soi tận nơi (khi cần đào sâu)
Quy tắc số một: describe trước, đoán sau. Mục Events ở cuối describe gần như luôn chỉ thẳng nguyên nhân.
Ca 1: ImagePullBackOff — kéo image thất bại
Tạo một pod với image không tồn tại:
kubectl run broken-image --image=nginx:doesnotexist-9999
kubectl get pod broken-image
NAME READY STATUS RESTARTS AGE
broken-image 0/1 ErrImagePull 0 12s
STATUS: ErrImagePull (rồi chuyển thành ImagePullBackOff khi Kubernetes lùi lại thử lại). Đừng đoán — hỏi describe:
kubectl describe pod broken-image
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 12s default-scheduler Successfully assigned default/broken-image to minikube
Normal Pulling 12s kubelet Pulling image "nginx:doesnotexist-9999"
Warning Failed 8s kubelet Failed to pull image "nginx:doesnotexist-9999":
manifest for nginx:doesnotexist-9999 not found: manifest unknown
Events nói rõ ràng: kéo image thất bại vì không tồn tại tag đó. Trong thực tế, ImagePullBackOff thường do: gõ sai tên/tag image, image ở registry riêng mà thiếu imagePullSecret, hoặc mất mạng tới registry. describe cho bạn biết là cái nào — khỏi mò mẫm.
Ca 2: CrashLoopBackOff — container cứ chết
Tạo pod có container thoát ngay với lỗi:
kubectl run crasher --image=busybox:1.36 -- sh -c "echo 'khởi động...'; exit 1"
kubectl get pod crasher
NAME READY STATUS RESTARTS AGE
crasher 0/1 Error 5 (2m17s ago) 3m46s
Dấu hiệu nhận diện: RESTARTS tăng dần (ở đây đã 5 lần). Container chạy, chết, Kubernetes restart, lại chết... Giữa các lần restart, Kubernetes lùi lại (chờ lâu dần: 10s, 20s, 40s...) và pod hiện STATUS: CrashLoopBackOff — đó là cách nó tránh restart điên cuồng một container hỏng. Khác với ImagePullBackOff (chưa chạy được), ở đây container có chạy nhưng thoát ngay, nên chỗ cần nhìn là log:
kubectl logs crasher
khởi động...
App in "khởi động..." rồi exit 1. Trong thực tế đây là nơi bạn thấy stack trace, "không kết nối được DB", "thiếu biến môi trường"... Nếu container đã restart và bạn muốn xem log của lần chạy trước (lần đã crash), thêm -p:
kubectl logs crasher -p # log của lần chạy ngay trước (previous)
CrashLoopBackOff thường do: app lỗi cấu hình (thiếu env/secret — Bài 7), liveness probe quá gấp (Bài 10), hoặc lệnh khởi động sai. Cặp logs + logs -p là chìa khoá.
Xem toàn bộ sự kiện cluster
describe cho events của một đối tượng. Muốn nhìn dòng thời gian toàn cluster (hữu ích khi không rõ cái gì hỏng trước):
kubectl get events --sort-by=.lastTimestamp
Warning Failed pod/broken-image Failed to pull image ... manifest unknown
Warning Failed pod/broken-image Error: ImagePullBackOff
Normal BackOff pod/broken-image Back-off pulling image "nginx:doesnotexist-9999"
Sắp theo thời gian giúp bạn dựng lại "chuyện gì xảy ra theo thứ tự nào" — quý khi gỡ sự cố dây chuyền.
exec: vào bên trong soi
Khi cần kiểm tra từ bên trong container — file cấu hình có đúng không, gọi được service khác không, biến môi trường có chưa:
kubectl exec -it <pod> -- sh
# bên trong:
env | grep DB # biến môi trường đã vào chưa? (Bài 7)
cat /etc/config/app.conf
wget -qO- http://other-service # gọi được service khác? (Bài 5)
Đây là cách kiểm chứng giả thuyết nhanh nhất. (Với image tối giản không có shell, Kubernetes có kubectl debug để gắn một container tạm có sẵn công cụ — nâng cao hơn nhưng đáng biết.)
Dashboard: nhìn cụm bằng giao diện
minikube có sẵn dashboard đồ hoạ — tiện để nhìn tổng thể, nhất là khi mới học:
minikube dashboard
Nó mở trình duyệt với giao diện xem mọi namespace, workload, pod, log, sự kiện — cùng thông tin kubectl cho, nhưng dễ lướt. Hữu ích để nắm bức tranh lớn; còn khi gỡ lỗi nhanh và làm việc thật, kubectl vẫn nhanh hơn.
Khung tư duy gỡ lỗi
Gói lại thành phản xạ:
STATUS bất thường?
├─ Pending → describe: thiếu tài nguyên? chưa có node? PVC chưa bound?
├─ ImagePullBackOff → describe: sai tên image / thiếu pull secret
├─ CrashLoopBackOff → logs (+ logs -p): app chết vì sao
├─ Running 0/1 → readiness probe fail (Bài 10): describe xem probe
└─ Service không vào → kubectl get endpoints: selector có khớp pod không?
Gần như mọi sự cố nền tảng đều rơi vào một trong các nhánh này, và describe + logs giải quyết phần lớn.
Tổng kết
Gỡ lỗi Kubernetes là một quy trình, không phải đoán mò: get pods (STATUS, RESTARTS) → describe (mục Events — vì sao) → logs (+ -p cho lần crash trước) → exec (soi bên trong). ImagePullBackOff = không kéo được image (sai tên/thiếu pull secret) — đọc Events; CrashLoopBackOff = container chạy rồi chết lặp lại (RESTARTS leo thang) — đọc logs. kubectl get events --sort-by cho dòng thời gian toàn cluster, minikube dashboard cho cái nhìn đồ hoạ. Quy tắc vàng: describe trước, đoán sau.
Ta đã đủ mảnh ghép — kiến trúc, workload, mạng, cấu hình, lưu trữ, vận hành, gỡ lỗi. Bài 14 ghép tất cả thành một dự án hoàn chỉnh: deploy một ứng dụng nhiều thành phần lên minikube từ đầu tới cuối, rồi tổng kết cả series.