Một buổi sáng thức dậy, bạn nhận được cảnh báo máy chủ chạm ngưỡng 100% dung lượng đĩa. Website báo lỗi 500 hoặc 502 khắp nơi, cơ sở dữ liệu MySQL/PostgreSQL tự động tắt vì không còn khoảng trống để ghi dữ liệu, và thậm chí bạn còn không thể tạo nổi một file tạm khi gõ lệnh trong SSH.
Chạy lệnh kiểm tra dung lượng:
df -hBạn thấy phân vùng root / đã đầy 100%. Tiếp tục dò tìm thư mục ngốn dung lượng nhất, thủ phạm lộ diện: một file có đuôi *-json.log nằm sâu trong /var/lib/docker/containers/... đã âm thầm phình to tới 20GB, 40GB hoặc thậm chí nuốt trọn cả ổ cứng của VPS.
Đây là "nạn nhân" của một thiết lập mặc định nguy hiểm trong Docker: nếu bạn không chỉ định giới hạn, Docker sẽ ghi log ra file vô tội vạ cho tới khi ổ cứng không còn một byte nào trống.
Hai phản xạ sai lầm khi thấy file log Docker quá lớn
Trong lúc hoảng loạn muốn giải phóng ổ cứng ngay lập tức để cứu website, rất nhiều người mắc phải hai sai lầm này:
- Dùng lệnh
rmđể xóa file log: Bạn chạy lệnhrm /var/lib/docker/containers//.log. Tên file biến mất, nhưng khi gõ lạidf -h, dung lượng trống vẫn là 0%! Lý do là tiến trình Docker daemon vẫn đang mở file handle đó để ghi tiếp. Linux sẽ không giải phóng dung lượng ổ cứng cho tới khi tiến trình đang mở file bị tắt hoặc file được làm rỗng. - Gõ
docker system prune -a -fhoặcdocker volume prune: Đây là phản xạ dọn dẹp mù quáng. Lệnh này không xóa file log của container đang chạy, nhưng nó sẽ xóa sạch các image cũ cần dùng để rollback khi có sự cố, và tệ hơn là xóa nhầm các named volume chứa dữ liệu nếu container đang tạm dừng.
Bước 1: Xử lý khẩn cấp để cứu ổ đĩa ngay lập tức
Để lấy lại dung lượng trống ngay trong 30 giây mà không cần khởi động lại Docker daemon hay làm gián đoạn container đang chạy, giải pháp chuẩn nhất là làm rỗng (truncate) file log về 0 byte:
Đầu tiên, tìm chính xác file log nào đang chiếm nhiều dung lượng nhất:
du -ah /var/lib/docker/containers/ | grep '\.log$' | sort -rh | head -n 5Khi đã có đường dẫn file log thủ phạm (ví dụ .../abc1234-json.log), bạn làm rỗng nó bằng lệnh:
truncate -s 0 /var/lib/docker/containers/<container_id>/<container_id>-json.logLệnh truncate -s 0 sẽ rút sạch dữ liệu trong file về 0 byte ngay lập tức mà vẫn giữ nguyên file descriptor. Dung lượng ổ cứng trên máy chủ sẽ được giải phóng ngay trong tích tắc mà không làm lỗi luồng ghi của Docker.
Bước 2: Cấu hình xoay vòng log (Rotation) vĩnh viễn
Lệnh truncate ở bước 1 chỉ là giải pháp tình thế để dập lửa. Nếu không cấu hình giới hạn, vài ngày sau file log đó sẽ lại tiếp tục phình to và làm sập máy chủ lần nữa.
Bạn có hai cách để khống chế dung lượng log vĩnh viễn:
Cách 1: Áp dụng cho toàn bộ máy chủ (Khuyên dùng)
Cách an toàn nhất là cấu hình mặc định cho chính Docker daemon. Bất kỳ container nào sau này được tạo ra trên VPS đều sẽ tự động tuân theo giới hạn này.
Mở hoặc tạo file cấu hình /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
}
}Ý nghĩa cấu hình:
max-size: "20m": Mỗi khi file log đạt tới 20MB, Docker sẽ tự động xoay vòng (đóng file cũ lại và mở file mới).max-file: "3": Docker chỉ giữ tối đa 3 file log cũ (file.log,.log.1,.log.2). Khi file thứ tư xuất hiện, file cũ nhất sẽ tự động bị xóa.- Như vậy, mỗi container trên máy chủ sẽ chỉ được phép chiếm tối đa khoảng 60MB log (20MB × 3), không bao giờ có chuyện một container nuốt trọn ổ đĩa nữa.
Sau khi lưu file, bạn nạp lại cấu hình Docker:
sudo systemctl reload docker || sudo systemctl restart dockerCách 2: Cấu hình riêng cho từng service trong compose.yaml
Nếu bạn muốn tùy biến dung lượng log riêng cho từng dịch vụ (ví dụ container Nginx cần giữ nhiều log hơn container Redis), bạn có thể cấu hình trực tiếp trong file Compose:
services:
web:
image: my-app:1.2.0
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"
compress: "true" # Nén các file log cũ dạng .gz để tiết kiệm thêm chỗBước 3: Bắt buộc phải recreate container để cấu hình có hiệu lực
Đây là điểm mà hơn 90% người quản trị hệ thống bị hớ: Cấu hình log rotation không tự động áp dụng cho các container đang chạy!
Docker gắn cấu hình logging vào container ngay tại thời điểm nó được tạo ra. Dù bạn đã sửa daemon.json và restart Docker, các container cũ vẫn sẽ tiếp tục giữ cấu hình "không giới hạn" ban đầu.
Để cấu hình mới thực sự có hiệu lực, bạn phải tạo lại (recreate) container bằng Compose:
docker compose up -d --force-recreate --no-deps webSau khi container mới khởi động lại, hãy kiểm tra chắc chắn cấu hình log đã được gắn vào container:
docker inspect -f '{{.HostConfig.LogConfig.Type}} {{json .HostConfig.LogConfig.Config}}' <tên_container>Nếu màn hình in ra json-file {"max-file":"3","max-size":"20m"}, bạn đã thành công.
Bước 4: Tìm nguyên nhân gốc rễ sinh ra bão log (Log Storm)
Giới hạn dung lượng xoay vòng giúp máy chủ không bị chết vì hết ổ đĩa, nhưng nó không giải quyết được gốc rễ vấn đề: Tại sao container lại xả log nhiều đến thế?
Nếu một container xả log với tốc độ 50MB/phút thì với hạn mức 60MB, log sẽ bị xoay vòng và xóa liên tục sau mỗi 60 giây. Khi cần mở log ra xem lỗi, bạn sẽ không còn thấy gì vì log cũ đã bị cuốn trôi mất.
Hãy soi nhanh vài chục dòng log gần nhất:
docker compose logs --tail=50 -f webNhững nguyên nhân phổ biến nhất gây ra tình trạng bão log trên máy chủ:
- Quên tắt chế độ Debug trên production: Framework đang in toàn bộ câu lệnh SQL, header HTTP và payload request vào log. Hãy chuyển
APP_DEBUG=falsehoặc đưa log level vềinfo/warn. - Vòng lặp lỗi kết nối (Retry loop không có backoff): Ứng dụng mất kết nối tới Redis hoặc database và liên tục thử lại hàng trăm lần mỗi giây, mỗi lần thử lại in ra một khối thông báo lỗi (stacktrace) dài hàng chục dòng.
- Container bị crash loop do healthcheck sai: Healthcheck đặt khoảng cách quá dày khiến container khởi động lại liên tục và xả toàn bộ boot log lặp đi lặp lại. Bạn có thể xem cách chuẩn hóa tần suất tại bài Healthcheck trong Docker Compose nên kiểm tra gì?.
Tóm lại
Một chiếc máy chủ VPS vận hành bền bỉ không thể để mặc cho log container ghi tự do. Hãy biến việc khai báo max-size và max-file thành tiêu chuẩn bắt buộc ngay từ khi thiết lập dự án theo Checklist đưa ứng dụng Docker Compose lên production.
Và đừng quên bảo vệ dữ liệu nghiệp vụ bằng cách sao lưu tách biệt ra khỏi vòng đời của container như hướng dẫn tại bài Dữ liệu persistent của Docker container cần backup ở đâu?.



