Xử lý log và giám sát Container: Best Practices và Resource Limits
Hướng dẫn Container Logging Best Practices, giám sát Docker và Resource Limits: stdout/stderr, structured JSON, log drivers, rotation, metrics, alerting, CPU, memory và OOM.
ShanverseCập nhật 10 phút đọc— lượt xemĐang tải lượt xem
Docker
Monitoring
Tại sao logging trong Container khác máy chủ truyền thống?
Container có vòng đời ngắn, có thể bị recreate và đổi ID bất kỳ lúc nào. Ghi log vào file bên trong writable layer khiến log:
Biến mất khi Container bị xóa.
Khó thu thập khi chạy nhiều replica.
Làm writable layer tăng không kiểm soát.
Buộc ứng dụng tự xử lý rotation và retention.
Nguyên tắc mặc định:
Ứng dụng ghi normal event vào stdout, error vào stderr. Docker hoặc agent bên ngoài chịu trách nhiệm vận chuyển, xoay vòng và lưu trữ.
Bình luận
Xem log khi phát triển và xử lý sự cố
Giới hạn --tail và --since để tránh kéo toàn bộ log lớn về terminal.
Ghi log vào stdout/stderr, không ghi file trong Container
Node.js đơn giản:
Không nên:
Một số phần mềm legacy bắt buộc ghi file. Khi đó dùng volume chuyên biệt, logrotate/collector rõ ràng và retention hữu hạn; không xem đây là mặc định.
Structured JSON Logging
Text tự do:
Structured event:
Field nên có:
UTC timestamp theo ISO 8601.
level: debug, info, warn, error, fatal.
service, environment, version.
event ổn định để query.
request_id, trace_id để correlation.
Duration, status code và error type phù hợp.
Không biến toàn bộ message thành field tùy ý. Schema ổn định giúp dashboard và alert không vỡ sau mỗi deploy.
Logging bằng Pino trong Node.js
Ở production, xuất JSON một event trên một dòng. Pretty-print chỉ nên bật local vì tăng CPU và làm parser khó dự đoán.
Không log secret và dữ liệu cá nhân
Không ghi:
Password, API key, access/refresh token.
Authorization/Cookie header.
Database URL có credential.
Private key hoặc nội dung Docker Secret.
Full request/response body chứa PII.
Card number, government ID hoặc session token.
Redaction phải xảy ra trước khi event rời process. “Xóa sau trên hệ thống log” thường đã quá muộn vì dữ liệu có thể nằm trong queue, backup và nhiều replica.
Stack trace và multi-line log
Một exception nên là một structured event, với stack trace nằm trong field. Nếu mỗi dòng stack trace thành một log entry, collector có thể tách sai, alert đếm thừa và correlation khó hơn.
Logger hỗ trợ error serializer sẽ giữ message, type và stack trong cùng event JSON.
Docker logging drivers
Kiểm tra driver mặc định:
Các lựa chọn phổ biến:
local: định dạng nội bộ tối ưu cho Docker, có rotation; phù hợp single host khi vẫn cần docker logs.
json-file: tương thích rộng, nhưng phải cấu hình rotation để tránh đầy disk.
journald: tích hợp systemd journal.
syslog, fluentd, gelf, awslogs, splunk: gửi đến hệ thống ngoài; cần đánh giá backpressure và failure behavior.
Log rotation trong Docker Compose
Khuyến nghị với local:
Nếu dùng json-file:
Các giá trị option nên là string. Rotation giới hạn log local trên host; nó không thay thế retention policy của hệ thống log tập trung.
Cấu hình mặc định cho Docker daemon
/etc/docker/daemon.json:
Sau khi validate JSON, restart Docker theo maintenance plan. Cấu hình mới chỉ áp dụng cho Container được tạo mới; cần recreate service cũ.
Không xóa hoặc sửa trực tiếp file trong /var/lib/docker/containers. Docker quản lý format, offset và lifecycle của chúng.
Kiến trúc logging tập trung
Mermaid
Loading diagram…
Collector nên bổ sung metadata hữu ích như service, environment, host và version. Tránh label có cardinality cực cao như user_id, full URL chứa ID hoặc raw request ID nếu backend index theo label. Các giá trị đó có thể nằm trong payload để search khi cần.
Thiết kế thêm:
Buffer có giới hạn khi backend log chậm.
Disk queue nếu yêu cầu durability.
Alert khi collector drop event hoặc queue đầy.
Retention khác nhau cho debug, access, audit và security logs.
Access control vì log có thể chứa metadata nhạy cảm.
Log, Metric và Trace khác nhau thế nào?
Dùng cùng trace_id/request_id để nhảy từ alert metric sang trace rồi tới log liên quan.
Theo dõi nhanh bằng Docker CLI
Snapshot resource usage:
Kiểm tra trạng thái:
Tìm restart, exit code, health status, OOM state và disk usage. CLI phù hợp incident nhỏ; production cần lịch sử time-series và alert chủ động.
Monitoring production
Một stack phổ biến:
Theo dõi ít nhất:
CPU usage và throttling.
Memory working set, limit và OOM kill.
Container restart/exit count.
Filesystem/disk usage và tốc độ tăng log.
Network errors, connection count.
Request rate, error rate, duration/latency.
Queue depth, DB pool saturation, dependency failures.
Healthcheck status và thời gian startup.
Healthcheck chỉ trả lời “process/service có phản hồi theo phép thử này không”; nó không thay thế metrics, SLO hoặc alerting.
Resource Limits giải quyết vấn đề gì?
Nếu không có limit, một Container memory leak hoặc fork loop có thể lấy tài nguyên của toàn host. Limits tạo blast-radius boundary:
CPU limit làm process bị throttled khi vượt ngân sách.
Memory limit là hard ceiling; vượt kéo dài có thể dẫn đến OOM kill.
PID limit giảm fork bomb.
File descriptor limit giảm resource exhaustion nhưng phải đủ cho traffic hợp lệ.
Resource Limits trong Docker Compose
Ý nghĩa:
cpus: 1.0: ngân sách tối đa tương đương khoảng một CPU; process có thể bị throttled.
mem_limit: 512m: hard memory ceiling.
mem_reservation: 256m: mức reservation/soft target khi runtime hỗ trợ; không thay thế hard limit.
pids_limit: 200: giới hạn process/thread theo cách kernel tính PID.
nofile: giới hạn file descriptor.
Chạy:
Khả năng hỗ trợ một số field phụ thuộc Compose/runtime/platform. Luôn kiểm tra config đã render và inspect Container thực tế.
Swarm và deploy.resources
Với Docker Swarm service:
deploy.resources mang semantics scheduling/orchestration. Đừng giả định mọi phiên bản local docker compose up xử lý giống Swarm; chọn field theo execution mode và xác minh runtime.
Node.js: memory limit khác V8 heap limit
Container memory gồm nhiều phần ngoài V8 heap:
V8 heap.
Native addon và Buffer.
Thread stack.
Shared library.
Page cache và runtime overhead.
Với Container 512m, không đặt V8 heap đúng 512m. Chừa headroom:
320 chỉ là điểm bắt đầu minh họa. Profile workload thực tế; app dùng nhiều Buffer/native memory cần headroom lớn hơn.
CPU limit và latency
CPU vượt limit không làm Container dừng ngay; scheduler throttles CPU. Dấu hiệu:
CPU luôn sát limit.
CPU throttling tăng.
p95/p99 latency tăng dù request rate không đổi.
Event loop lag tăng.
Healthcheck timeout rồi restart loop.
Giải pháp có thể là tối ưu code, tăng CPU budget, giảm concurrency hoặc scale ngang. Chỉ nhìn CPU percentage không đủ; phải correlation với latency và throttling.
Điều tra OOM Kill
Dấu hiệu thường gặp:
Container exit đột ngột, thường thấy exit code liên quan SIGKILL.
OOM state trong inspect.
Memory tăng dần trước khi restart.
Log kết thúc không có graceful shutdown.
Quy trình:
Sau đó kiểm tra host/kernel log theo quyền hệ thống và platform. Phân biệt:
Limit quá thấp.
Memory leak.
Burst hợp lệ nhưng không có headroom.
Node heap hợp lý nhưng native memory tăng.
Nhiều Container cùng gây memory pressure trên host.
Không chỉ tăng limit rồi bỏ qua trend.
Restart policy không phải monitoring
giúp service tự quay lại sau crash, nhưng có thể che crash loop. Luôn alert theo:
Restart count tăng.
Container không healthy.
Thời gian giữa các lần crash giảm.
OOM kill hoặc non-zero exit.
App cũng phải xử lý SIGTERM, ngừng nhận request mới, đóng connection và flush log có giới hạn trước khi thoát.
Alert nào thực sự hữu ích?
Alert phải actionable, có owner, severity, runbook và đủ context để bắt đầu điều tra.
Anti-pattern cần tránh
Ghi log vào writable layer mà không rotation.
Dùng json-file mặc định vô hạn trên production host.
Log full request body, token hoặc secret.
Pretty log nhiều màu trong production.
Dùng message text không ổn định làm metric/alert key.
Index field cardinality cao như user ID thành label.
Chỉ dùng docker logs mà không có central retention.
Đặt memory limit bằng đúng heap limit.
Không đặt limit cho service public-facing.
Đặt limit cực thấp mà không load test.
Dùng restart policy để che OOM/crash loop.
Coi healthcheck là hệ thống monitoring hoàn chỉnh.
Checklist production
App ghi structured log một event mỗi dòng vào stdout/stderr.
Timestamp UTC, level, service, version và correlation ID nhất quán.
Secret/PII được redact trước khi emit.
Docker logging driver có rotation và giới hạn dung lượng.
Log được chuyển tới central storage với retention rõ ràng.
Collector có buffer, drop metrics và alert.
Dashboard có CPU, memory, restart, disk và network.
App metrics có rate, errors, duration và saturation.
Trace liên kết được với log bằng trace ID.
CPU, memory, PID và file descriptor limits đã được test.
Node heap chừa headroom cho native memory.
Có alert OOM, crash loop, disk growth và SLO burn.
Hướng dẫn security logging và monitoring để phát hiện brute force, credential stuffing và đăng nhập đáng ngờ bằng structured logs, Redis, SIEM và alerting.
Hướng dẫn Docker Hardening thực tế với non-root user, multi-stage builds, minimal image, read-only filesystem, Linux capabilities, seccomp, scanning và supply-chain security.
Docker Compose khi nào không còn đủ? So sánh Kubernetes và Docker Swarm về multi-host, self-healing, scaling, rolling update, networking, secrets và lộ trình migration production.