发布时间:2026-09-20 04:30 更新时间:2026-09-20 04:30 阅读量:0
很多站长第一次遇到 Docker 相关的磁盘告警,都是同一种场景:服务器上跑着几个容器,业务本身没写什么大文件,某天却收到系统盘使用率超过 90% 的提醒。登进去用 du -sh /var/lib/docker/* 一层层看下去,最后发现空间全被 /var/lib/docker/containers/ 下面的日志文件吃掉了。这篇就把这件事讲清楚:默认行为是什么、为什么它会无限增长、以及怎么用配置把它限制在合理范围内。
Docker 默认使用 json-file 日志驱动。容器里进程写到标准输出(stdout)和标准错误(stderr)的内容,都会被 Docker 收集起来,按 JSON 格式落盘,路径大致是 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log。这个文件的结构是一行一个 JSON 对象,记录了时间戳、输出流类型和日志内容。
关键点在于:json-file 驱动默认不做任何轮转和容量限制。也就是说,只要容器还在运行、还在往 stdout 打日志,这个文件就会一直追加下去。程序员在代码里 print、console.log,或者 Nginx、PHP-FPM、Java 应用把访问日志、异常堆栈打到控制台,最终都会落到这个文件上。一个请求量稍大的站点,每天产生几百 MB 甚至几 GB 的容器日志并不罕见,跑几周就能把一块 40G 的系统盘填满。
更麻烦的是,磁盘写满之后不只是 Docker 出问题:系统日志写不进去、MySQL 可能拒绝写入、SSH 登录都可能受影响。所以这件事最好在部署阶段就配好,而不是等告警了再救火。
推荐的做法是修改 Docker 守护进程配置,让所有新建容器默认带上日志限制。配置文件是 /etc/docker/daemon.json,如果文件不存在就新建一个,写入下面的内容:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
}
}
两个参数的含义很直白:max-size 表示单个日志文件达到多大就轮转,这里设成 100MB;max-file 表示最多保留几个轮转文件,这里保留 5 个。两者相乘,单个容器最多占用约 500MB 的日志空间,超过之后最旧的日志文件会被删除。这个量级对多数中小型站点够用,你可以按磁盘容量和日志价值自行调整,比如日志量大就设 max-size: 50m、max-file: 3。
写完配置后需要重启 Docker 生效。重启会短暂中断所有容器(除非配置了 live-restore),生产环境建议安排在维护窗口:
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl status docker --no-pager
这里有个容易踩的坑:daemon.json 的日志配置只对新建的容器生效,已经在跑的容器不会自动应用。想让老容器也受限,需要把它们重建一次,比如用 docker compose up -d --force-recreate,或者先 docker rm -f 再用原命令重新跑。另外,如果 daemon.json 里 JSON 格式写错,Docker 会启动失败,改完记得用 docker info 确认服务正常、日志驱动确实是 json-file。
不是所有日志都值得长期保留,某些调试用的容器可能只想留很少的量。这时可以在启动参数或 Compose 文件里单独指定,覆盖全局默认值。命令行写法:
docker run -d \
--name web-demo \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=2 \
nginx:stable
如果用 Docker Compose,则在服务下加一段 logging 配置,效果一样:
services:
web:
image: nginx:stable
logging:
driver: json-file
options:
max-size: "10m"
max-file: "2"
配置完之后,怎么确认真的生效了?可以先看某个容器的日志文件大小,再对比配置值。查看容器日志路径和大小:
docker inspect --format '{{.LogPath}}' web-demo
sudo ls -lh /var/lib/docker/containers/<容器ID>/ | grep json.log
如果看到 -json.log 之外还出现了 -json.log.1、-json.log.2 这类文件,说明轮转已经在工作。反过来,如果单个 log 文件一直涨、始终没有带序号的文件出现,那多半是配置没吃上,回去检查容器是不是在改配置之前创建的。
对于已经被写满的机器,先救急再治本。可以用下面的命令查看各容器日志占用,找出最大的那个:
sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -h | tail -n 10
注意不要直接 rm 正在写入的日志文件。虽然删除后空间会被释放(因为文件句柄仍被占用,和之前讲过的"删了文件空间不释放"是同一类现象),但 Docker 对日志文件的偏移量记录可能错乱,后续日志行为不可预期。更稳妥的做法是先把容器停掉、清理日志,再按上面的方式加上限制后重启;或者用 truncate -s 0 把文件清空(具体效果以你的 Docker 版本和实际环境为准,建议先在测试机验证)。
容器日志写满磁盘,根因通常不是日志本身有问题,而是默认配置没有上限。把 daemon.json 里的 max-size 和 max-file 配上,是成本最低的一道防线;对日志量特别大的服务,再单独覆盖更小的值。配置生效后,建议顺手做两件事:一是把 df -h 和日志目录大小加入日常巡检,二是评估是否需要把日志集中收集到外部系统,本地只留短期缓冲。磁盘空间这件事,永远是提前配好参数,比事后登机救火轻松得多。
| 📑 | 📅 |
|---|---|
| Nginx 与后端长连接调优:keepalive 与 upstream 复用 | 2026-09-20 |
| Docker 容器内 CPU 被限流排查:cfs_quota、cpuset 与 top 显示异常 | 2026-09-19 |
| Nginx gzip 与 Brotli 压缩配置实战:静态资源体积优化 | 2026-09-19 |
| PHP-FPM 进程数怎么调:pm.max_children 与内存估算 | 2026-09-19 |
| Docker容器DNS解析异常排查:resolv.conf与自定义网络 | 2026-09-19 |
| Linux时间与时区排查:date、timedatectl与容器时区一致性 | 2026-09-20 |
| 服务器网卡多队列与中断绑定入门:RPS、RSS 与 irqbalance 怎么取舍 | 2026-09-20 |
| Nginx 上传大文件报 413 与超时:参数与缓冲区排查 | 2026-09-20 |
| Docker容器缺命令:精简镜像补装与临时容器调试 | 2026-09-20 |
| Nginx location 匹配优先级实战:=、^~、~ 命中顺序验证 | 2026-09-21 |