Hiểu đúng về logging trong Kubernetes cho người mới
Sau các bài về lý thuyết căng thẳng, bài này mình sẽ đến với một vấn đề tuy không nặng kỹ thuật, hay nặng về lý thuyết nhưng không kém phần quan trọng trong quá trình phát triển phần mềm. Đó chính là check log. Với đa phần mọi người khi dev ở local, ví dụ chạy một app NestJs thì anh em dev thấy log ở ngay trong terminal, nơi chạy lệnh yarn run dev, một cách rất dễ dàng. Khi có lỗi xảy ra, chỉ cần mở terminal đó hoặc mở file log là có thể biết ngay chuyện gì đang diễn ra. Mọi thứ khá trực quan và dễ kiểm soát.
Tuy nhiên, khi bắt đầu deploy application lên Kubernetes, nhiều người sẽ cảm thấy hơi bối rối. Dù app vẫn chạy bình thường và ta vẫn có thể xem log bằng lệnh kubectl logs -f <pod_name>, nkhưng nếu dừng lại một chút để suy nghĩ, sẽ nảy sinh một câu hỏi rất tự nhiên: log này thực chất đang nằm ở đâu? Tại sao trong container lại không thấy file log nào giống như khi chạy ở local? Và nếu pod bị restart hoặc bị xoá đi, liệu log cũ có còn tồn tại hay không?
Sự bối rối này thường đến từ việc chúng ta vô thức áp dụng cách nghĩ của môi trường local vào Kubernetes. Thực tế, Kubernetes không vận hành theo cách đó. Kubernetes không phải là một hệ thống logging và cũng không có nhiệm vụ lưu trữ log của application. Nó chỉ đơn giản cung cấp cơ chế để đọc log mà container ghi ra, chứ không chịu trách nhiệm quản lý hay bảo quản log về lâu dài.
Trong bài viết này, mình sẽ đi từ những khái niệm cơ bản nhất để làm rõ cách Kubernetes xử lý log. Chúng ta sẽ cùng nhau trả lời các câu hỏi: Kubernetes có lưu log hay không, kubectl logs thực sự đang đọc log từ đâu, vì sao không nên ghi log trực tiếp vào file trong container, và trong môi trường production thì log thường được thu thập và lưu trữ theo cách nào.
Bài viết được viết theo góc nhìn của một người mới làm quen với Kubernetes hoặc developer lần đầu deploy application lên k8s, nên mình sẽ cố gắng giải thích chậm rãi, có ví dụ minh họa và demo thực tế bằng minikube để bạn có thể tự chạy, tự chụp ảnh và kiểm chứng lại nội dung
Đầu tiên, đó là Kubernetes có lưu log không?
hmm...mình tìm hiểu thì thấy Kubernetes không phải là một hệ thống logging và cũng không có trách nhiệm lưu trữ log của application Trong Kubernetes, log không được xem là “dữ liệu” cần được quản lý lâu dài như database hay file upload. k8s chỉ quan tâm đến việc chạy container, đảm bảo pod sống hay chết, scale bao nhiêu replica, còn việc log được lưu ở đâu, giữ bao lâu, tìm kiếm như thế nào… là chuyện của hệ thống khác.
Vậy tại sao chúng ta vẫn có thể xem log bằng kubectl logs?
Lý do là vì Kubernetes tuân theo một quy ước rất rõ ràng: container nên ghi log ra standard output (stdout) và standard error (stderr). Khi application in log ra hai luồng này, Kubernetes sẽ có cách để đọc lại và hiển thị cho người dùng thông qua CLI, chứ bản thân Kubernetes không “giữ” log đó trong cluster nhé
Nói cách khác, Kubernetes chỉ đóng vai trò như một người trung gian. Application ghi log ra stdout, container runtime (như Docker hay containerd) sẽ thu thập log này và lưu nó ở mức node. Khi bạn chạy lệnh kubectl logs, Kubernetes chỉ đơn giản là đi hỏi container runtime: “hãy đưa cho tôi log mà container này đã in ra”. Chỉ vậy thôi
Chính vì vậy, nếu bạn đang tìm một nơi kiểu như “thư mục log của Kubernetes” để mở ra xem tất cả log của application thì sẽ không tìm thấy. Kubernetes không được thiết kế để làm việc đó. Nó chỉ cung cấp cách truy cập tạm thời vào log của container đang hoặc vừa chạy, chứ không đảm bảo log sẽ tồn tại lâu dài. Việc hiểu rõ điều này sẽ giúp bạn tránh được rất nhiều hiểu lầm sau này, ví dụ như kỳ vọng rằng log sẽ vẫn còn sau khi pod bị xoá, hoặc cho rằng Kubernetes tự động lưu log cho môi trường production mà không cần cấu hình thêm gì cả.
Thử tận tay với Minikube: log thực sự đến từ đâu?
Lý thuyết đến đây có thể đã khá rõ, nhưng với k8s, tự tay làm thử luôn là cách hiểu nhanh nhất. Thay vì chỉ tin vào mô tả, mình sẽ dựng một ví dụ cực kỳ đơn giản bằng minikube để quan sát log hoạt động như thế nào trong thực tế
Ý tưởng của demo này rất đơn giản: chúng ta sẽ chạy một container không làm gì phức tạp, chỉ liên tục in ra một dòng log sau mỗi vài giây. Nếu log thực sự đến từ stdout như đã nói ở trên, thì kubectl logs sẽ đọc được những dòng này. Và nếu pod bị xoá đi, chúng ta sẽ thấy chuyện gì xảy ra với log cũ. Đến đây mình đoán mọi người đã có câu trả lời cho mình: nếu pod mà crash hoặc restart thì log cũ sẽ ra sao 
Trước hết, hãy đảm bảo minikube đã được khởi động.
minikube start
Sau khi cluster đã sẵn sàng, ta tạo một deployment cực kỳ nhỏ gọn, sử dụng image busybox. Container này chỉ chạy một vòng lặp vô hạn và in ra một dòng chữ ra terminal.
kubectl create deployment log-demo \
--image=busybox \
-- /bin/sh -c '
echo "=== CONTAINER STARTED at $(date) ===";
while true; do
echo "$(date) hello-from-k8s";
sleep 5;
done
'
Lúc này, Kubernetes sẽ tạo một pod cho deployment vừa rồi. Chúng ta sẽ kiểm tra status của pod bằng lệnh quen thuộc ở dưới
kubectl get pods
Đợi chút rồi kiểm tra lại đến khi pod đã ở trạng thái Running, mình sẽ thử xem log bằng lệnh quen thuộc:
kubectl logs <pod-name>

Mọi người đang thấy các dòng hello-from-k8s được in ra đều đặn. Điểm đáng chú ý ở đây là trong container không hề có file log nào cả. Toàn bộ log chỉ đơn giản là output của câu lệnh echo. Kubernetes không cần biết application của bạn viết bằng ngôn ngữ gì hay log theo format nào, miễn là log được in ra stdout hoặc stderr thì nó đều có thể đọc được. Bây giờ, để kiểm chứng thêm một điều quan trọng, hãy thử xoá pod đó đi:
kubectl delete pod <pod-name>
Kubernetes sẽ tự động tạo một pod mới để đảm bảo số replica của deployment. Nếu bạn tiếp tục chạy kubectl logs với pod mới này, bạn sẽ chỉ thấy log kể từ khi pod mới được tạo. Những dòng log cũ của pod trước đó không còn nữa. Thí nghiệm nhỏ này cho thấy rất rõ một điều: log trong Kubernetes gắn với vòng đời của pod, và kubectl logs chỉ giúp bạn xem log trong phạm vi vòng đời đó. Kubernetes không hề đảm bảo rằng log sẽ được lưu lại sau khi pod bị xoá hay được thay thế
Vì sao không nên ghi log vào file bên trong container?
Sau khi hiểu rằng kubectl logs thực chất đọc log từ stdout, nhiều người mới thường nghĩ: “Vậy mình cứ ghi log vào file trong container, khi cần thì kubectl exec vào đọc là được.” Cách nghĩ này nghe có vẻ hợp lý, nhưng trong Kubernetes lại được xem là một anti-pattern.
Lý do đầu tiên nằm ở vòng đời của pod. Pod trong Kubernetes không bền: nó có thể bị restart, bị xoá khi deploy phiên bản mới, hoặc bị thay thế khi scale. Khi pod biến mất, toàn bộ filesystem bên trong container – bao gồm cả file log – cũng biến mất theo. Điều này khiến log rất dễ bị mất mà không hề có cảnh báo rõ ràng. Lý do thứ hai liên quan đến khả năng scale. Khi application chạy nhiều replica, mỗi pod sẽ có một file log riêng. Việc debug lúc này trở nên khó khăn, vì bạn không biết cần đọc log của pod nào, và cũng không có cách nào xem log một cách tập trung. Cách làm này đi ngược lại mục tiêu vận hành và quan sát hệ thống trong môi trường Kubernetes.
Vì những lý do đó, Kubernetes khuyến khích application chỉ ghi log ra stdout hoặc stderr, và để việc thu thập, lưu trữ log cho các hệ thống chuyên dụng bên ngoài đảm nhiệm.
Tổng kết
Kubernetes không phải là một hệ thống logging. kubectl logs chỉ giúp đọc lại log mà container đã ghi ra stdout trong phạm vi vòng đời của pod. Vì pod không bền, log cũng không được đảm bảo tồn tại lâu dài nếu không có cơ chế thu thập bổ sung.
Trong môi trường production, application nên tiếp tục log ra stdout, còn phần thu thập, lưu trữ, tìm kiếm và phân tích log sẽ do hạ tầng DevOps xử lý thông qua log agent và log storage. Các thành phần cụ thể có thể khác nhau tuỳ hệ thống, nhưng nguyên tắc chung này vẫn giữ nguyên.
Bài viết này tập trung làm rõ phần nền tảng của bài toán logging trong Kubernetes: log đến từ đâu, kubectl logs hoạt động như thế nào, và vì sao không nên ghi log trực tiếp vào file trong container. Mục tiêu là giúp bạn hiểu đúng bản chất trước khi đi sâu vào các giải pháp logging cho production.
Khi đã nắm được nền tảng này, việc triển khai logging trong production sẽ trở nên rõ ràng hơn, vì bạn biết chính xác điểm cần mở rộng nằm ở đâu, và đâu là trách nhiệm của application, đâu là trách nhiệm của hạ tầng
All rights reserved