Oke, Bách lười đây =)) lần này sang seri khác nhá. Đây sẽ là bài đầu tiên về Docker in production, bao gồm những phân mục như loging, socket control, sigterm, storage và sau cùng là đào sâu về các đối tượng nền của container. Hi vọng là mình đủ thời gian kết thúc con này sớm rồi viết container orchestration trước khi tất cả anh em đều biết nhiều hơn mình =))).
Ố Cầy. Câu hỏi đầu tiên, tại sao mình lại viết về logging trước?.
Trước hết mình xin được xác định trước khung tổng thể ở đây, chúng ta không bàn về bài toán hoàn thiện của orchestration. Chúng ta bàn về việc các bạn build một con container hay một cụm container xong rồi bạn thử scale nó lên cho một bài toán nhỏ. Nói chung quy, bạn đang định biến nó thành production và với kinh nghiệm của mình, thì vấn đề đầu tiên xuất hiện sẽ là vấn đề về Logging.
Khi nói tới Logging chúng ta cần phải nói rõ về hai tính chất sau của container.
1. Container được sinh ra với mục tiêu cuối cùng là khởi chạy các services stateless. Chúng ta đổi xử với VM như thú cưng, nếu nó hỏng thì phải vào cứu chữa, còn với Container thì chúng là gia súc, nó ốm bệnh bạn cho nó ra đi và kéo một con khác vào thế chỗ.
2. Khi lấy các logs của Container để tìm ra lỗi, chúng ta đồng thời phải để mắt tới logs host của chúng. Các ảnh hưởng chéo là hoàn toàn dễ hiểu và có thể sảy ra.
I, Stateless và log-storage.
Docker hướng tới stateless application. Khi thread chính bên trong nó kết thúc container sẽ tự thân ngừng hoạt động, dưới góc nhìn logging thì có nghĩa là khi container ngừng hoạt động những dữ liệu của nó cũng biến mất đồng thời bao gồm cả dữ liệu logs của chúng.
Vì thế docker xây dựng một số built-in logging drivers. Default là json-file
, docker ghi logs ra máy host để lưu trữ, khi container stop bạn sử dụng lệnh
docker logs <container_id>
thì docker sẽ hiển thị logs chính là logs được lưu trữ ở trên máy host, bình thường đường dẫn của nó sẽ là
/var/lib/docker/containers/[container-id]/[container-id]-json.log
Khi chúng ta xây dựng các hệ thống có lượng log lớn, default config sẽ có vấn đề do không define log rotation và khiến cho dung lượng lưu trữ của bạn sớm bị nghẹn cứng. Đây sẽ là vấn đề đầu tiên mà những người mới gặp phải.
Tới thời điểm này bạn có các sự lựa chọn sau:
1. Tiếp tục sửa dụng json-file
, sửa config daemon để apply log rotation cho tất cả các container hoặc là apply riêng rẽ vào từng container phù hợp.
2. Sử dụng các local storage driver khác, như journald
để bắn thẳng log về var/log/message và tích hợp vào log host. local
sẽ đưa log vào các vùng lưu trữ mặc định mỗi container 100MB bao gồm 5 file mỗi file 20MB.
3. Sử dụng các server storage driver, khi đó logs sẽ được bắn tẳng tới socket của server lưu trữ.
4. Sử dụng SaaS solution.
Cá nhân mình đánh giá phương pháp tối ưu nhất là sử dụng option 1 + 4. Tuy nhiên hãy nhìn lại và phân tích một chút.
Option 2, journald sẽ dẫn tới một khu lực lưu trữ logs chung điều này sẽ gây khó khăn cho việc phân tách logs theo container ngay chỉ từ khi bạn chạy từ 2 container trở lên.
Option 3, do việc bắn thẳng log từ container tới server sử dụng UDP có thể thất thoát logs còn TCP thì có thể khiến container chết khi việc truyền dữ liệu gặp cản trở, và đồng thời cả UDP hay TCP tới log server đều khiến luồng của container bị can thiệp và latency cơ bản tăng cao.
Với 1 +4, khi chỉnh sửa thay đổi log để turn on rotation chúng ta sẽ giải quyết được bài toán về lưu trữ, tiếp đó sử dụng các log analysis solution như ELK cho việc thu thập cũng như xử lý logs. Điều này đảm bảo được luồng của các container không bị ảnh hưởng cũng như logs của chúng ta có thể được xử lý, truyền gửi, phân tích một cách tốt nhất bởi các bộ solution có tính chuyên nghiệp cao. Với một hệ thống xử lý tập trung thì việc lưu trữ local được giảm thiểu, không cần duy trì container để xem logs vì logs đã được truyền thẳng về hệ thống xử lý, điều này sẽ giảm thiểu nút thắt khi ta muốn deploy container thay thế cho container đã chết. Hệ thống chạy ổn định, vẫn có logs để phân tích.
II, Application và Log-optimization.
Giờ cùng quay lại góc nhìn nhỏ hơn là góc nhìn về App và log bên trong. Khi không thay đổi, docker logs sẽ là tất cả những gì sẽ hiển thị trên terminal khi bạn chạy container đó.
Nói cách khác lượng dữ liệu ở đây có thể dư thừa dẫn đến gây khó khăn cho việc trace logs sau này, hoặc có thể image của bạn là non-interactive process như web-server hay database thì logs sẽ không hiển thị bất kì thứ gì bạn mong muốn.
Vì vậy phương pháp tốt nhất là xây dựng hoặc sử dụng các log stream và lấy chúng làm log hiển thị tới container. Ví dụ ở đây chúng ta có nginx và apache là hai web-server, họ truyền thẳng steam log làm log của container.
The officialnginx
image creates a symbolic link from/var/log/nginx/access.log
to/dev/stdout
, and creates another symbolic link from/var/log/nginx/error.log
to/dev/stderr
, overwriting the log files and causing logs to be sent to the relevant special device instead. See the Dockerfile.
The officialhttpd
driver changes thehttpd
application’s configuration to write its normal output directly to/proc/self/fd/1
(which isSTDOUT
) and its errors to/proc/self/fd/2
(which isSTDERR
). See the Dockerfile.
III, Tổng kết.
Khi bạn triển khai ứng dụng dưới dạng production thì vấn đề về logging là bắt buộc, vì vậy hãy nghiên cứu kĩ để tìm ra phương án tốt nhất cho bài toán của mình. Tối ưu chúng ở cả cấp độ container và host đồng thời suy nghĩ tới phương pháp xử lý log tập trung với chúng!!
.
Thế nhá, chàoô.