DevOps 31/08/2026 8 phút

Pod in ra 400.000 dòng nhật ký, nằm sờ sờ 53 MB trên đĩa — kubectl logs trả về đúng 0 dòng, không một lời cảnh báo

kubectl logs là lệnh ai cũng gõ đầu tiên khi có sự cố — bài này đo nó thực sự đọc gì và không đọc gì. Log là tệp văn bản trên đĩa node, không qua control plane; kubectl logs chỉ đọc tệp HIỆN TẠI, nên 400.000 dòng đã xoay vòng ra file khác trả về 0 dòng không lỗi. Hệ quả đáng sợ: pod ồn ào tự xoá log của chính mình, và đúng lúc sự cố thì nó in nhiều nhất nên chính phần đầu sự cố bị đẩy ra khỏi tầm với. Thêm: containerLogMaxSize 10Mi không phải trần cứng — đo được 55 MB vì kubelet chỉ kiểm định kỳ.

DevOps 31/08/2026 8 phút

Ba lỗi mạng hoàn toàn khác nhau trong Kubernetes cho ra đúng một thông báo và đúng một thời gian — và một lệnh duy nhất phân biệt được cả ba

Nhãn sai, cổng sai, pod chưa sẵn sàng — ba nguyên nhân khác hẳn nhau nhưng đều ra ConnectionRefused ~0 ms, và DNS thì phân giải tốt ở cả ba nên nslookup chẳng chứng minh gì. Đo cách một bảng endpointslices tách được ba bệnh cùng triệu chứng, và vì sao khác biệt Refused-ngay-lập-tức so với Timeout-đúng-hạn-chờ (3004 ms khi bật NetworkPolicy) là phép chia đôi tốt nhất khi lần lỗi mạng.

DevOps 31/08/2026 8 phút

Tôi xoá tay một Service do Helm tạo, rồi hỏi helm status — nó vẫn thản nhiên báo 'deployed', vì Helm chỉ đọc lại biên nhận của chính mình chứ không nhìn vào cụm

Đo hai thứ ở Helm: nó thêm gì vào manifest, và nó KHÔNG biết gì. 380 dòng chart nguồn chỉ sinh ra 100 dòng YAML — giá trị của Helm không nằm ở viết ít mà ở tham số hoá. Trạng thái release là một Secret base64 hai lần rồi gzip, giữ cả mã nguồn chart nên 1,9 KB manifest phình thành 12 KB. Nhưng chỗ đáng nhớ nhất: xoá tay một Service thì helm status vẫn báo deployed, vì Helm không phải bộ điều khiển — nó đọc lại cái nó ĐÃ làm, không phải cái đang CÓ. Và uninstall để lại PVC của StatefulSet lẫn CRD, vì Helm chỉ dọn được thứ chính nó tạo.

DevOps 31/08/2026 7 phút

emptyDir trong RAM ghi nhanh gấp bốn lần trên đĩa — nhưng nó âm thầm ăn vào giới hạn bộ nhớ của pod, và cú OOMKilled sau đó đổ lỗi nhầm chỗ

Pod là thứ tạm thời, dữ liệu thì thường không — đo bốn cách gắn lưu trữ và cái nào sống sót qua việc pod bị xoá. emptyDir trên tmpfs nhanh gấp bốn emptyDir trên đĩa nhưng tính vào limits.memory nên ghi quá tay là OOMKilled dù ứng dụng chẳng cấp phát gì. emptyDir gắn vòng đời POD không phải container: sống qua restart, chết qua xoá pod. PVC local-path cấp phát muộn (WaitForFirstConsumer) và bị ghim vào một node, nên node chết là pod kẹt Pending. Và reclaimPolicy Delete mặc định nghĩa là kubectl delete pvc xoá dữ liệu vĩnh viễn, không thùng rác.

DevOps 31/08/2026 7 phút

Tôi cấp một ServiceAccount đúng quyền 'chỉ đọc' Secret — rồi đọc ra ngay SieuBiMat123, và ba quyền nghe vô hại khác hoá ra tương đương quyền quản trị

Cấp quyền từng lớp cho một ServiceAccount rồi đo chính xác nó mở ra được gì. Role bó rất chặt (đúng động từ, đúng tài nguyên, đúng namespace), nhưng 'chỉ đọc' Secret là đọc được mọi mật khẩu vì base64 không phải mã hoá. Ba quyền nghe vô hại trong một bản YAML — create pods, get secrets, create rolebindings — đều là đường leo thang lên quyền toàn cụm. Và kubectl auth can-i là cách duy nhất kiểm quyền thực tế thay vì đọc YAML rồi đoán.

DevOps 31/08/2026 7 phút

HPA phóng từ 2 lên 8 bản trong 30 giây, nhưng thu về mất tới 258 giây — bốn phút rưỡi ôm 8 bản ở 0% CPU, và đó là cố ý

HPA tự tăng giảm số bản theo tải — đo cả hai chiều thì chúng chênh nhau 8,6 lần. Mở rộng 30 giây (HPA tính thẳng số bản cần bằng ceil(bản × CPU/mục tiêu), không nhích từng cái), thu gọn 258 giây vì stabilizationWindow mặc định của scaleDown là 300 giây còn scaleUp là 0. Bất đối xứng này có chủ ý: mở rộng chậm thì người dùng khổ, thu gọn chậm chỉ tốn ít tiền vài phút. Thêm hai cái bẫy: thiếu requests.cpu thì HPA im lặng không bao giờ chạy, và co giãn theo bộ nhớ hiếm khi đúng vì JVM/Go không trả RAM.