CLI AI

Docker 日志占满磁盘:先截断,再限制大小

2026-07-11

truncate -s 0 "$(docker inspect --format '{{.LogPath}}' api)" 会清空正在运行的容器日志并立刻释放空间,不需要重启。这里绝对不要用 rm:守护进程仍然往被删除的文件里写,空间收不回来,而且 docker logs 会一直坏到容器重启为止。

1. 先看看 Docker 到底占了多少

clai
$ clai docker 占用了多少磁盘空间→ docker system dfTYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLEImages          48        14        28.88GB   20GB (69%)Containers      17        10        4.631MB   513.8kB (11%)Local Volumes   38        7         6.349GB   4.084GB (64%)Build Cache     181       0         0B        0B

日志在这张表里根本看不到——Containers 那一行只统计可写层。如果 df 说磁盘满了而 docker system df 很平静,那嫌疑就在日志上。

2. 找出写得最多的容器

clai
$ clai 按从大到小显示每个容器的日志文件大小→ docker ps -q | xargs docker inspect --format '{{.LogPath}} {{.Name}}' | while read -r p n; do printf '%s\t%s\n' "$(du -h "$p" | cut -f1)" "${n#/}"; done | LC_ALL=C sort -rh | head -36.1M	api3.2M	worker1.9M	cache

LogPath 是定位该文件唯一可靠的办法:rootful 和 rootless 安装的路径并不一样。LC_ALL=C 不是装饰:在以逗号作小数点的区域设置里,sort -h 会把 844K 排在 6.1M 前面。

3. 截断正在运行的容器日志

clai
$ clai 不停止 api 容器的情况下清空它的日志→ truncate -s 0 "$(docker inspect --format '{{.LogPath}}' api)"

容器继续往同一个文件描述符里写,数据流不会中断,空间立刻回来。事故处理时你要的就是这条命令。

4. 陷阱:用 rm 代替 truncate

clai
$ clai 删除 api 容器的日志文件→ rm "$(docker inspect --format '{{.LogPath}}' api)"⚠ CAUTION — 这之后 docker logs 会一直坏到容器重启

docker logs 会回答 Error grabbing logs: open …-json.log: no such file or directory,而且文件不会自己回来。守护进程仍然持有被删除文件的句柄,所以空间同样没有释放:输出丢了,问题还在。

5. 让它不再发生

clai
$ clai 启动一个日志按 10 兆轮转、保留三个文件的容器→ docker run -d --log-opt max-size=10m --log-opt max-file=3 --name api alpine sleep 600

单个文件大小乘以文件数量就是上限,这里是 30 MB。给每个话多的容器都加上。

6. 检查运行中的容器有没有上限

clai
$ clai 显示 api 容器的日志配置→ docker inspect -f '{{json .HostConfig.LogConfig}}' api{"Type":"json-file","Config":{"max-file":"3","max-size":"10m"}}

空的 "Config":{} 表示完全没有限制,文件会一直涨到磁盘用完。没带这些选项启动的容器就长这样。

Gotchas

  • 截断只释放当前活动的文件。 一个设了 max-size=1m --log-opt max-file=2 的容器写了 20000 行,docker logs 全都能看到。截断活动文件之后还剩 10122 行——其余在轮转出来的 …-json.log.1 里。轮转文件要删,活动文件要截断。
  • daemon.json 对已存在的容器无效。 /etc/docker/daemon.json 里的 log-opts 只在创建容器时读取。已经在跑的容器保持旧设置,直到你重新创建它们。
  • sort -h 受区域设置影响。 在俄语或德语区域设置下 6.1M 不会被当成数字,最大的日志会落到列表中间。在 sort 前面加 LC_ALL=C。

Related questions

为什么 docker system df 不显示日志? 它统计镜像、容器可写层、卷和构建缓存。json 日志文件就放在容器目录旁边,从来不进这张表。

怎么一次性限制所有容器的日志? 在 /etc/docker/daemon.json 写入 "log-driver": "json-file" 和 "log-opts": {"max-size": "10m", "max-file": "3"},重启守护进程,再重建容器。

能完全不把日志写到磁盘吗? 可以,--log-driver none 关闭采集,但那样 docker logs 什么也看不到。折中办法是 local 驱动,它默认就会轮转。

See also

CliAI 会把上面那句话变成精确的命令,并在执行之前给 rm 那种写法打上 CAUTION 标记。一行安装。