Docker日志太大:限制大小与安全清理

Docker 应用运行一段时间后磁盘越来越满,先确认增长的是容器输出日志,还是应用写进目录的文件。本文适用于 Linux 服务器本机的 Docker Engine,目标容器由 Compose 管理,日志驱动为 json-file或local。操作会涉及重建目标容器,应安排业务可以短暂中断的时间。

先找到写日志的容器

在服务器终端查看容器名称,把下面的占位文字换成实际名称:

docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'
log_container='替换为实际容器名'
docker inspect --format '{{json .HostConfig.LogConfig}}' "$log_container"
docker inspect --format '{{.LogPath}}' "$log_container"
docker inspect --format '{{range .Mounts}}{{println .Type .Source "->" .Destination}}{{end}}' "$log_container"

第一项检查输出中的 Type和Config。json-file没有配置 max-size时,默认不会按大小轮转;local有自己的默认轮转配置。其他驱动应按各自的存储方式排查,不直接套用本篇。

LogPath是 Docker 管理日志的位置。需要确认当前文件大小时,只读取大小信息:

log_path=$(docker inspect --format '{{.LogPath}}' "$log_container")
if [ -n "$log_path" ]; then sudo du -h -- "$log_path"; fi

这个数字不包含所有轮转文件。查看日志内容使用 docker logs,不要用编辑器改写日志文件,也不要直接删除、截断 Docker 的日志文件或容器目录。

如果大文件在挂载的 /app/logs、/var/log等目录,可能是程序自己写的日志。Docker 的 max-size只管理收集到的标准输出、标准错误;应用文件要在程序中设置保留天数和轮转,按刚才查到的挂载路径确认归属。

给目标服务增加大小限制

进入部署时使用的 Compose 项目目录,保存当前 Compose 文件和环境配置的副本。本例服务名是 web,后文每一处都要换成实际服务名,且以单副本服务为例。

把 logging加入现有服务定义,保留原来的镜像、端口、卷、网络和环境变量。下面只展示放置位置,不能用它覆盖整个文件:

services:
  web:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

本例保持原有 json-file驱动,单个文件达到 10m后轮转,保留最多 3 个文件。max-file需要配合 max-size使用。如果原来使用 local,保留 driver: local,这两个选项同样适用。

这些值是容量示例,应按排障所需的日志时长调整。文件元数据、压缩和写入过程都会影响实际占用,不能把配置值理解成整台服务器的精确磁盘上限。已有日志采集器时,先确认兼容性再更换驱动。

重建之前,先保住数据和旧日志

重建会替换容器的可写层。先核对数据库、上传文件和其他业务数据都在已确认的持久卷或挂载目录中,完成可恢复的备份。可用下面的命令查看可写层有哪些变化,但不能仅凭它判断哪些是业务数据:

docker diff "$log_container"
docker inspect --format '{{.Image}}' "$log_container"
docker logs --since 30m --tail 2000 --timestamps "$log_container"

记录现有镜像 ID,确认 Compose 使用的仍是对应版本;要保留的旧日志先导出到另一块有空间的磁盘或本地电脑。数据只存在容器内部时,先迁出,方法见数据卷与目录挂载教程。磁盘已经完全写满时,要先腾出维护空间,不能指望重建操作一定能成功。

重建一个服务,再确认限制真正生效

在原项目目录操作。如果原启动命令带有 -f或-p,下面每条 docker compose命令都要带上相同参数,避免误创建第二套项目。确认配置副本、镜像和备份齐全后执行:

docker compose config -q &&
docker compose up -d --no-deps --no-build --pull never --force-recreate web &&
docker compose ps -a &&
log_container=$(docker compose ps -a -q web) &&
test -n "$log_container" &&
docker inspect --format 'Image={{.Image}} Log={{json .HostConfig.LogConfig}}' "$log_container" &&
docker compose logs --since 5m --tail 100 web &&
docker_root=$(docker info --format '{{.DockerRootDir}}') &&
test -n "$docker_root" &&
df -h "$docker_root"

这组命令通过 &&连接,前一步成功才继续;配置检查或重建报错时,先处理错误,不跳过门槛继续执行。重建只指定目标服务,--pull never和--no-build避免顺带拉取或构建镜像。命令成功仍不等于业务正常,应核对镜像 ID、日志驱动及两个限额,然后实际访问应用、读取一份原有数据,确认业务恢复。

旧容器被替换后,再检查磁盘可用空间;挂载目录中的应用日志仍需单独处理。保留必要日志之前,不要运行批量清理,也不要加 down -v删除卷。新容器异常时,恢复之前的 Compose 和环境配置,使用原镜像重建,回退思路见Docker 应用更新与回退。

为什么改了daemon.json还是一直涨

Docker 的默认日志设置只影响之后新建的容器。修改 daemon.json并重启 Docker,不会自动替换旧容器的日志选项;单纯 docker restart也不等于重建。本次只处理一个应用时,优先在该服务的 Compose 配置里设置并重建,范围更明确。

轮转生效后仍要检查日志为什么暴增。反复重试、调试级别日志或持续报错应从应用配置修复,否则只是把占用限制住,故障还在重复发生。