❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.

Bài 13, bạn đã học cách monitor container với health check, theo dõi resource usage bằng docker stats, và setup monitoring stack với cAdvisor + Uptime Kuma. Giờ bạn đã biết container nào đang “khoẻ”, container nào đang “ốm”.

Docker Logging - Quản lý log hiệu quả
Minh họa: Docker Logging – Quản lý log hiệu quả

Nhưng khi container gặp lỗi, câu hỏi tiếp theo luôn là: “Lỗi gì? Ở đâu? Khi nào?”: và câu trả lời nằm trong log.

Bài này sẽ hướng dẫn bạn quản lý Docker log hiệu quả: từ cách xem log, giới hạn log size tránh đầy disk, chọn log driver phù hợp, đến setup Dozzle để xem log qua giao diện web.

Docker logging hoạt động thế nào?

Trước khi đi vào chi tiết, bạn cần hiểu cơ chế logging của Docker:

Luồng log trong Docker

Khi ứng dụng bên trong container ghi log ra stdout (standard output) hoặc stderr (standard error), Docker daemon sẽ bắt lấy output đó và chuyển cho log driver xử lý.

Ứng dụng trong container
        │
        ▼
  stdout / stderr
        │
        ▼
   Docker Daemon
        │
        ▼
    Log Driver
        │
        ▼
   Log Storage
  (file, syslog, journald...)

Mặc định, Docker sử dụng json-file driver, log được lưu dưới dạng JSON, mỗi dòng một JSON object chứa timestamp, stream (stdout/stderr) và nội dung log.

Log file nằm ở đâu?

Với json-file driver, log được lưu tại:

/var/lib/docker/containers/<container-id>/<container-id>-json.log

Bạn có thể tìm chính xác đường dẫn log file của một container bằng lệnh:

docker inspect --format='{{.LogPath}}' my_container

Nội dung file log trông như thế này:

{"log":"192.168.1.1 - - [14/Mar/2026:10:30:00 +0000] \"GET / HTTP/1.1\" 200 612\n","stream":"stdout","time":"2026-03-14T10:30:00.123456789Z"}
{"log":"192.168.1.1 - - [14/Mar/2026:10:30:01 +0000] \"GET /favicon.ico HTTP/1.1\" 404 555\n","stream":"stdout","time":"2026-03-14T10:30:01.234567890Z"}

Mỗi dòng là một JSON object với 3 trường: log (nội dung), stream (stdout hay stderr), và time (timestamp).

Xem log container

Docker logs xem log container
docker logs –tail và –timestamps xem log container

Docker cung cấp lệnh docker logs để xem log container. Đây là công cụ bạn sẽ dùng hàng ngày khi debug.

Xem toàn bộ log

docker logs my_container

Lệnh này sẽ in ra toàn bộ log từ khi container khởi động. Với container chạy lâu, output có thể rất dài, nên thường bạn sẽ dùng thêm các option bên dưới.

Xem N dòng cuối

# Xem 100 dòng log cuối cùng
docker logs --tail 100 my_container
# Xem 50 dòng cuối
docker logs --tail 50 my_container

Đây là cách dùng phổ biến nhất, bạn chỉ cần xem log gần đây, không cần cuộn qua hàng triệu dòng.

Follow log (real-time)

# Theo dõi log real-time (giống tail -f)
docker logs -f my_container
# Kết hợp: xem 50 dòng cuối rồi follow tiếp
docker logs --tail 50 -f my_container

Flag -f (follow) sẽ giữ terminal mở và hiển thị log mới ngay khi chúng xuất hiện. Nhấn Ctrl+C để thoát.

Xem log theo thời gian

# Log trong 1 giờ gần nhất
docker logs --since 1h my_container

# Log trong 30 phút gần nhất docker logs --since 30m my_container

# Log từ một thời điểm cụ thể docker logs --since "2026-03-14T10:00:00" my_container

# Log trong khoảng thời gian docker logs --since 2h --until 1h my_container

Rất hữu ích khi bạn biết lỗi xảy ra vào khoảng thời gian nào, chỉ cần lọc đúng khoảng đó thay vì đọc toàn bộ log.

Xem log với Docker Compose

Nếu bạn dùng Docker Compose (và ở bài này mình giả sử bạn đã quen rồi), có các lệnh tương tự:

# Xem log tất cả services trong stack
docker compose logs

# Follow log tất cả services docker compose logs -f

# Xem log của một service cụ thể docker compose logs nginx

# Follow log một service, 100 dòng cuối docker compose logs --tail 100 -f nginx

# Xem log nhiều services docker compose logs nginx php mysql

Khi dùng docker compose logs, mỗi service sẽ có màu khác nhau và prefix tên service, giúp bạn dễ phân biệt log đến từ đâu.

Vấn đề: Log đầy disk!

Đây là một trong những “bẫy” phổ biến nhất với Docker mà nhiều người mới không biết cho đến khi… hết disk space.

Chuyện gì xảy ra?

Mặc định, Docker không giới hạn kích thước log file. Container cứ chạy, log cứ ghi, file cứ phình to. Một container Nginx chạy vài tháng trên website có traffic trung bình có thể sinh ra file log 10GB+ dễ dàng.

Khi disk đầy, mọi thứ bắt đầu “chết”: database crash, container không start được, thậm chí SSH vào server cũng khó khăn.

Kiểm tra log size

Để kiểm tra kích thước log file của một container:

# Tìm đường dẫn log file
docker inspect --format='{{.LogPath}}' my_container
# Kiểm tra kích thước
du -sh $(docker inspect --format='{{.LogPath}}' my_container)

Hoặc kiểm tra tất cả container cùng lúc:

# Liệt kê log size của tất cả containers
docker ps -q | xargs -I {} sh -c 'echo "$(docker inspect --format="{{.Name}}" {}) $(du -sh $(docker inspect --format="{{.LogPath}}" {}) 2>/dev/null)"'

Nếu thấy file log nào lên đến hàng GB, đó là dấu hiệu bạn cần config giới hạn log ngay.

Xoá log nhanh (tạm thời)

Nếu disk đang đầy và bạn cần xử lý gấp:

# Truncate log file (xoá nội dung, giữ file)
sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' my_container)

Lưu ý: Đây chỉ là giải pháp tạm. Nếu không config giới hạn, log sẽ lại phình to. Phần tiếp theo sẽ hướng dẫn bạn giải quyết triệt để.

Giới hạn log size

Cấu hình log driver Docker
daemon.json giới hạn log size và kiểm tra log files trên disk

Đây là việc bắt buộc phải làm trên mọi server chạy Docker. Có 3 cấp độ config:

1. Per container (khi docker run)

docker run -d \
  --name nginx \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  nginx:alpine
  • max-size=10m: mỗi file log tối đa 10MB
  • max-file=3: giữ tối đa 3 file log (rotate tự động)

Với config này, tổng dung lượng log tối đa là 30MB (3 file × 10MB). Khi file log đạt 10MB, Docker sẽ tự động rotate, tạo file mới và giữ lại 3 file gần nhất.

2. Trong docker-compose.yml

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
app:
    image: my-app:latest
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "5"

Bạn có thể set logging config riêng cho từng service. Service nào sinh nhiều log hơn (ví dụ app server) thì cho max-size lớn hơn.

3. Global – áp dụng cho tất cả containers

Đây là cách mình khuyên dùng nhất: set mặc định cho toàn bộ Docker daemon, mọi container mới tạo đều tự động được áp dụng.

Tạo hoặc sửa file /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json

Thêm nội dung:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Restart Docker daemon để áp dụng:

sudo systemctl restart docker

Lưu ý quan trọng:

  • Config này chỉ áp dụng cho container mới tạo sau khi restart. Container đang chạy không bị ảnh hưởng.
  • Nếu container đã có logging config riêng (trong docker-compose.yml hoặc docker run), config riêng sẽ override config global.
  • Nếu file daemon.json đã có nội dung khác, hãy merge thêm: đừng ghi đè toàn bộ.

Log drivers

Docker hỗ trợ nhiều log driver khác nhau, mỗi loại phù hợp với một use case riêng. Dưới đây là các driver phổ biến nhất:

json-file (mặc định)

Log được lưu dạng JSON, mỗi dòng một JSON object. Đây là driver mặc định và phù hợp với hầu hết trường hợp.

  • Ưu điểm: Đơn giản, dễ đọc, hỗ trợ docker logs
  • Nhược điểm: Không nén, tốn disk nếu không giới hạn
  • Phù hợp: VPS cá nhân, project nhỏ-vừa

local

Tương tự json-file nhưng log được nén tự động, giảm đáng kể dung lượng disk.

  • Ưu điểm: Nén tốt, performance cao hơn json-file, hỗ trợ docker logs
  • Nhược điểm: Log file không đọc trực tiếp được (đã nén)
  • Phù hợp: Server cần tiết kiệm disk, traffic cao
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

syslog

Gửi log đến syslog daemon của hệ thống hoặc remote syslog server.

  • Ưu điểm: Tập trung log, tích hợp với hệ thống sẵn có
  • Nhược điểm: Không hỗ trợ docker logs, cần syslog server
  • Phù hợp: Môi trường enterprise, cần tập trung log nhiều server

journald

Tích hợp với systemd journal: hệ thống log mặc định trên hầu hết Linux distro hiện đại.

  • Ưu điểm: Tích hợp sẵn, hỗ trợ docker logs, query mạnh mẽ với journalctl
  • Nhược điểm: Chỉ hoạt động trên hệ thống có systemd
  • Phù hợp: Server Linux muốn quản lý log tập trung qua journalctl

Bảng so sánh log drivers

DriverNéndocker logsRemotePhù hợp
json-fileMặc định, đơn giản
localTiết kiệm disk
syslog:Enterprise, tập trung log
journaldLinux systemd
fluentd,Log pipeline phức tạp
none,Không cần log

Khuyến nghị: Với VPS cá nhân hoặc project nhỏ-vừa, json-file hoặc local là đủ. Chỉ cần nhớ set max-sizemax-file. Khi nào scale lên nhiều server mới cần nghĩ đến syslog hay fluentd.

Dozzle – Xem log tập trung qua web

Xem log qua terminal thì nhanh, nhưng khi bạn có nhiều container và muốn theo dõi log một cách trực quan hơn, Dozzle là lựa chọn tuyệt vời.

Dozzle là gì?

Dozzle là một real-time log viewer cho Docker, chạy hoàn toàn trên web browser. Đặc điểm:

  • Nhẹ: Container chỉ chiếm ~8MB RAM
  • Không lưu data: Dozzle chỉ stream log real-time, không lưu trữ gì cả
  • Giao diện đẹp: Chọn container, filter, search, xem nhiều container cùng lúc
  • Zero config: Deploy xong là dùng được ngay

Deploy Dozzle bằng Docker Compose

Tạo file docker-compose.yml cho Dozzle:

services:
  dozzle:
    image: amir20/dozzle:latest
    container_name: dozzle
    ports:
      - "9999:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped
    environment:
      - DOZZLE_LEVEL=info
      - DOZZLE_TAILSIZE=300
docker compose up -d

Truy cập http://your-server-ip:9999: bạn sẽ thấy giao diện Dozzle với danh sách tất cả container đang chạy.

Các tính năng chính

  • Container list: Sidebar hiển thị tất cả container, click để xem log
  • Real-time streaming: Log hiển thị ngay khi phát sinh, không cần refresh
  • Search & Filter: Tìm kiếm trong log, filter theo regex
  • Multi-container view: Xem log nhiều container cùng lúc trên một màn hình: rất tiện khi debug vấn đề liên quan nhiều service
  • Log level highlighting: Tự động highlight ERROR, WARN với màu khác nhau
  • Fuzzy search container: Gõ tên container để tìm nhanh

Bảo mật Dozzle

Dozzle đọc Docker socket nên có quyền truy cập rất cao. Một số lưu ý:

  • Không expose ra public internet: chỉ dùng qua VPN hoặc đặt sau reverse proxy có authentication
  • Mount Docker socket với :ro (read-only): Dozzle chỉ cần đọc, không cần ghi
  • Dozzle hỗ trợ built-in authentication: bạn có thể config username/password

Ví dụ Dozzle với authentication cơ bản:

services:
  dozzle:
    image: amir20/dozzle:latest
    container_name: dozzle
    ports:
      - "9999:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./dozzle-users.yml:/data/users.yml
    restart: unless-stopped
    environment:
      - DOZZLE_AUTH_PROVIDER=simple

Tạo file dozzle-users.yml:

users:
  admin:
    name: "Admin"
    password: "$2a$11$..." # bcrypt hash của password
    email: admin@example.com

Tạo password hash bằng lệnh:

# Tạo bcrypt hash cho password
docker run --rm httpd:2 htpasswd -nbB "" "your_password" | cut -d: -f2

Structured logging

Khi ứng dụng của bạn lớn dần, log dạng text thường (plain text) sẽ trở nên khó parse và phân tích. Structured logging : ghi log dưới dạng JSON , giải quyết vấn đề này.

So sánh: Plain text vs Structured log

Plain text log:

[2026-03-14 10:30:00] ERROR: Failed to connect to database at 192.168.1.50:3306 - Connection refused

Structured (JSON) log:

{
  "timestamp": "2026-03-14T10:30:00.000Z",
  "level": "error",
  "message": "Failed to connect to database",
  "host": "192.168.1.50",
  "port": 3306,
  "error": "Connection refused",
  "service": "user-api",
  "request_id": "abc-123"
}

Với structured log, bạn có thể dễ dàng:

  • Filter: Lọc tất cả log có level=error
  • Search: Tìm tất cả log liên quan đến request_id=abc-123
  • Aggregate: Đếm số lượng error theo service
  • Alert: Tự động cảnh báo khi error rate tăng đột biến

Ví dụ: Node.js với Winston

const winston = require('winston');

const logger = winston.createLogger({ format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ // Log ra stdout — Docker sẽ capture new winston.transports.Console() ] });

// Sử dụng logger.info('User logged in', { userId: 42, ip: '192.168.1.1' }); logger.error('Database connection failed', { host: 'db', port: 3306 });

Output sẽ là JSON, Docker capture qua stdout, và bạn có thể dùng bất kỳ tool nào để parse.

Ví dụ: Python với structlog

import structlog
import sys

structlog.configure( processors=[ structlog.processors.TimeStamper(fmt="iso"), structlog.processors.JSONRenderer() ], logger_factory=structlog.PrintLoggerFactory(sys.stdout), )

logger = structlog.get_logger()

# Sử dụng logger.info("user_logged_in", user_id=42, ip="192.168.1.1") logger.error("db_connection_failed", host="db", port=3306)

Nguyên tắc: Ứng dụng chỉ cần ghi log ra stdout/stderr dưới dạng JSON. Docker lo phần còn lại, capture, lưu trữ, rotate.

Best practices cho Docker logging

Tổng hợp lại những “quy tắc vàng” khi quản lý log trong Docker:

1. Luôn set max-size và max-file

Không bao giờ chạy Docker production mà không giới hạn log. Config trong /etc/docker/daemon.json là cách đơn giản nhất, set một lần, áp dụng cho tất cả.

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

2. Log to stdout/stderr

Ứng dụng trong container nên ghi log ra stdout/stderr, không ghi ra file bên trong container. Lý do:

  • Docker chỉ capture được stdout/stderr
  • Log file trong container sẽ mất khi container bị xoá
  • Không thể dùng docker logs để xem log file
  • Log file trong container không được rotate bởi Docker

Ví dụ: image Nginx chính thức đã symlink access log và error log đến stdout/stderr:

# Bên trong container Nginx
ln -sf /dev/stdout /var/log/nginx/access.log
ln -sf /dev/stderr /var/log/nginx/error.log

3. Dùng structured logging

Với ứng dụng tự viết, hãy dùng JSON format cho log. Dễ parse, dễ filter, dễ tích hợp với các log management tool. Phần trên đã có ví dụ với Winston (Node.js) và structlog (Python).

4. Không log sensitive data

Tuyệt đối không ghi log các thông tin nhạy cảm:

  • Passwords, API keys, tokens
  • Thông tin cá nhân (số CMND, số thẻ tín dụng…)
  • Session cookies, JWT tokens
  • Database connection strings chứa password

Log file thường ít được bảo vệ hơn database, nếu ai đó access được log, họ sẽ có toàn bộ thông tin nhạy cảm.

5. Log có context

Mỗi dòng log nên có đủ thông tin để bạn hiểu chuyện gì đang xảy ra mà không cần đọc dòng khác:

  • Timestamp: khi nào?
  • Level: info, warn, error?
  • Service name: từ service nào?
  • Request ID: thuộc request nào? (rất quan trọng trong microservices)
  • Message: chuyện gì xảy ra?

📚 Serie Docker từ A đến Z

  1. Bài 1: Docker là gì? Tại sao nên dùng Docker trên VPS
  2. Bài 2: Cài đặt Docker và Docker Compose trên VPS Ubuntu
  3. Bài 3: Làm quen với Docker – Các lệnh cơ bản cần biết
  4. Bài 4: Docker Image & Dockerfile – Tự tạo Image riêng
  5. Bài 5: Docker Volume & Network – Quản lý dữ liệu và mạng
  6. Bài 6: Docker Compose là gì? Cài đặt và cú pháp cơ bản
  7. Bài 7: Deploy WordPress + MySQL + phpMyAdmin bằng Docker Compose
  8. Bài 8: Deploy LEMP Stack (Nginx + PHP-FPM + MariaDB) bằng Docker Compose
  9. Bài 9: Biến môi trường & file .env trong Docker Compose
  10. Bài 10: Reverse Proxy với Nginx Proxy Manager + SSL tự động
  11. Bài 11: Deploy ứng dụng Node.js / Python với Docker Compose
  12. Bài 12: Backup & Restore dữ liệu Docker Volume
  13. Bài 13: Monitoring Docker với Portainer, Uptime Kuma và cAdvisor
  14. Bài 14: Docker Logging – Quản lý log hiệu quả (đang đọc)
  15. Bài 15: Bảo mật Docker trên VPS
  16. Bài 16: CI/CD đơn giản – Auto deploy với Webhook + Docker Compose
  17. Bài 17: Docker Compose trong thực tế – Tổng hợp project mẫu

Tổng kết

Qua bài này, bạn đã nắm được:

  • Docker logging hoạt động thế nào: từ stdout/stderr qua Docker daemon đến log driver
  • Cách dùng docker logs để xem, filter và follow log
  • Vấn đề log đầy disk và cách giới hạn log size (per container, compose, global)
  • Các log driver phổ biến và khi nào dùng loại nào
  • Deploy Dozzle để xem log qua giao diện web
  • Structured logging: tại sao nên dùng JSON format
  • Best practices để quản lý log hiệu quả và an toàn

Việc cần làm ngay: Nếu bạn chưa config daemon.json với max-sizemax-file, hãy làm ngay bây giờ. Đây là thay đổi nhỏ nhưng tránh được rất nhiều rắc rối sau này.

Bài 15, mình sẽ hướng dẫn bạn bảo mật Docker : từ Docker socket security, user namespace, read-only containers, đến network policies. Container chạy ổn rồi, log quản lý rồi , giờ đến lúc khóa chặt nó lại! 🔒

👈 Bài trước: Monitoring Docker với Portainer, Uptime Kuma và cAdvisor

👉 Bài tiếp: Bảo mật Docker trên VPS

Chia sẻ:
Bài viết đã được kiểm duyệt bởi AZDIGI Team

Về tác giả

Thạch Phạm

Thạch Phạm

Đồng sáng lập và Giám đốc điều hành của AZDIGI. Có hơn 15 năm kinh nghiệm trong phổ biến kiến thức liên quan đến WordPress tại thachpham.com, phát triển website và phát triển hệ thống.

Hơn 10 năm phục vụ 80.000+ khách hàng

Bắt đầu dự án web của bạn với AZDIGI