Docker 容器日志过大占用磁盘?推荐原生配置而非 logrotate
最稳妥的方案是直接配置 Docker 自带的日志轮转选项(max-size 和 max-file),而不是依赖系统的 logrotate 工具去切割 Docker 管理的日志文件。
先说结论:优先修改 Docker 守护进程配置或容器启动参数,让 Docker 自己管理日志大小。
- 适合:所有使用默认 json-file 日志驱动的 Docker 环境
- 先准备:备份 daemon.json 文件,确认当前磁盘占用情况
- 验收:检查日志文件是否按预期轮转,磁盘空间不再持续增长
为什么不建议直接用 logrotate
Docker 默认使用 json-file 日志驱动,守护进程会持有日志文件的句柄。如果使用系统 logrotate 直接切割(move/rename),Docker 进程可能仍然向旧文件句柄写入数据,导致日志丢失或磁盘空间无法释放。官方推荐的方式是通过 Docker 自身的 logging options 来控制。
方案一:配置全局日志轮转(推荐)
修改 Docker 守护进程配置,对所有新创建的容器生效。
1. 编辑配置文件
编辑 /etc/docker/daemon.json。如果文件不存在则新建,注意如果文件中已有其他配置,需合并 JSON 格式,避免语法错误:
sudo vim /etc/docker/daemon.json
写入以下内容:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
2. 重启 Docker 服务
警告:此操作会重启 Docker 服务,导致所有运行中的容器短暂中断。请在业务低峰期操作。
sudo systemctl daemon-reload
sudo systemctl restart docker
方案二:针对单个容器配置
如果不想影响所有容器,可以在启动容器时添加参数。注意:此配置仅对新建容器生效,现有容器通常需要重建才能应用。
docker run -d `--log-opt` max-size=10m `--log-opt` max-file=3 nginx
备选方案:强制使用 logrotate(高风险)
如果因合规等原因必须使用 logrotate,需配置 copytruncate 模式,但仍存在切割瞬间日志丢失的风险。
创建配置文件 /etc/logrotate.d/docker-containers:
/var/lib/docker/containers/*/*.log {
copytruncate
daily
rotate 3
compress
missingok
notifempty
}
风险提示:copytruncate 会在复制后清空原文件,但复制和清空之间存在时间窗口,此期间的日志可能丢失。且 Docker 可能因文件 inode 变化出现异常。除非必要,否则不建议使用。
怎么验证是否生效
1. 检查文件数量
进入容器日志目录,观察日志文件是否维持在设定数量内(例如 max-file 为 3,则最多看到 3 个文件):
ls -lh /var/lib/docker/containers/<容器 ID>/*.log
2. 检查容器配置
使用 inspect 命令确认容器的 LogPath 和配置是否生效:
docker inspect <容器 ID> | grep -A 10 LogPath
3. 观察磁盘空间
运行一段时间后,再次使用 df 或 du 命令确认磁盘空间不再异常增长。
清理旧日志文件
配置生效后,只会限制新生成的日志,已有的超大日志文件需要手动清理。
# 查找大于 100M 的日志文件
find /var/lib/docker/containers/ -name "*.log" -size +100M
# 手动清理前请确认业务无需保留,或先备份
# sudo rm /path/to/old.log
常见坑
- daemon.json 语法错误:JSON 格式严格,多一个逗号或少一个括号都会导致 Docker 无法启动,修改前务必备份。
- 重启影响业务:修改全局配置需要重启 Docker 服务,会导致所有容器短暂中断,建议在业务低峰期操作。
- 旧日志不会自动清理:配置生效后,只会限制新生成的日志,已有的超大日志文件需要手动清理或等待轮转覆盖。
- 不要混用策略:除非你非常清楚如何配置 copytruncate,否则不要同时使用系统 logrotate 和 Docker 自带轮转,避免冲突。