用心打造
VPS知识分享网站

Docker日志占满磁盘怎么办?清理与轮转教程

Docker服务运行一段时间后,系统盘突然只剩几百MB,docker images 看起来却没有多大。继续往下查,才发现某个容器把错误信息每秒写几十次,日志文件已经涨到几十GB。这种故障不只会让容器异常,数据库、SSH和系统日志都可能因为无法写盘一起出问题。

我处理Docker磁盘告警时,不会先执行一串全局清理命令。镜像、数据卷、容器可写层和日志都可能占空间,删错数据卷的代价远高于多花几分钟确认。正确顺序是先找满的文件系统,再定位Docker目录和具体容器,最后才决定清理与长期轮转方案。

下面以Linux上的Docker Engine为例。Docker Desktop、Kubernetes、rootless模式和远程日志驱动的路径不同,操作前要确认环境。生产服务器还应先停止继续产生海量日志的故障请求,避免刚释放的空间立刻再次被写满。

日志占满磁盘

第一步,确认真的是磁盘容量告急

先看文件系统容量和inode:

df -hT
df -ih

Use% 接近100%表示块容量不足;inode接近100%则是小文件数量过多。两者处理方式不同。Docker JSON日志通常造成容量不足,而某些应用缓存或临时目录可能耗尽inode。

接着查看Docker根目录:

docker info --format '{{.DockerRootDir}}'
sudo du -xhd1 /var/lib/docker 2>/dev/null | sort -h

默认常见路径是 /var/lib/docker,但不能直接假定。Docker可能通过 data-root 改到其他磁盘,rootless模式也使用用户目录。du -x 限制在当前文件系统内,能避免扫描挂载进去的其他大盘。

如果 df 显示很满,du 汇总却明显偏小,还要检查已删除但仍被进程占用的文件:

sudo lsof +L1

日志被删除后,写日志的进程没有重新打开文件,磁盘块仍不会释放。此时应优雅重启对应容器或日志进程,而不是反复删除同一路径。

第二步,找出日志最大的容器

先查看每个容器使用的日志驱动和日志文件路径:

docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}'
docker inspect CONTAINER --format 'driver={{.HostConfig.LogConfig.Type}} path={{.LogPath}}'

使用默认 json-file 驱动时,LogPath 通常指向容器目录中的JSON日志。可以按路径统计大小:

docker ps -aq | while read id; do
  name=$(docker inspect -f '{{.Name}}' "$id" | sed 's#^/##')
  path=$(docker inspect -f '{{.LogPath}}' "$id")
  size=$(sudo du -h "$path" 2>/dev/null | cut -f1)
  printf '%-20s %-10s %s\n' "$name" "${size:-0}" "$path"
done

这段命令只读取信息,不会修改容器。结果中某个文件远大于其他文件时,再结合日志内容判断是不是应用错误循环:

docker logs --since 10m --tail 200 CONTAINER

不要直接执行不带 --taildocker logs 读取几十GB文件,终端会长时间输出并增加I/O压力。日志可能包含账号、IP、请求参数和令牌,复制到工单或群聊前要脱敏。

第三步,先控制继续增长的来源

磁盘只剩很少空间时,清理前要先减慢写入。查看容器状态、重启次数和最近错误,判断是错误循环、健康检查过密、访问异常,还是应用把调试级日志留在生产环境。

故障容器不承载关键业务时,可以先停止它:

docker stop --time 30 CONTAINER

关键服务不能直接停止,就优先在负载均衡或应用入口限制触发故障的请求,再把日志级别从debug降到info或warn。改日志级别之前保存最近一段错误样本,避免清理后失去根因证据。

有些容器每隔几秒启动失败并重启,日志只是结果。此时要同时检查退出码、启动命令、依赖服务和重启策略。单纯轮转日志只能延缓磁盘再次被写满,不能修复错误循环。

第四步,紧急释放空间要控制范围

确认目标日志路径与容器后,可以对单个 json-file 日志做截断:

sudo truncate -s 0 /path/from/docker-inspect-json.log

truncate 保留文件本身和文件描述符,只把长度设为0,通常比删除文件更适合紧急处理。执行前先保存必要的末尾日志:

docker logs --since 30m --tail 1000 CONTAINER > container-last.log 2>&1

不要用通配符一次截断所有容器日志,也不要手工编辑Docker维护的日志文件。Docker官方明确提醒,日志文件由守护进程专用管理,外部工具直接操作可能干扰日志系统。紧急截断应作为恢复空间的临时动作,完成后仍要配置受支持的轮转方案。

释放后立即复查:

df -hT
sudo du -h /path/from/docker-inspect-json.log
docker logs --tail 20 CONTAINER

容量没有变化时,运行 lsof +L1 检查删除占用,或确认实际写满的是不是另一个挂载点。

第五步,不要把docker system prune当成日志清理

docker system df -v 可以查看镜像、容器、数据卷和构建缓存占用:

docker system df -v

这些统计不一定完整计入容器JSON日志,因此镜像占用很小不能排除日志问题。docker system prune 主要删除未使用对象,不是日志轮转命令;带 --volumes 时还可能删除未被当前容器引用的数据卷。

确实需要清理镜像或构建缓存时,先列出目标并确认能否重新拉取或构建,再使用范围明确的命令。数据库、上传文件和业务状态常保存在卷中,没有备份和归属确认时,不要为了腾空间删除数据卷。

第六步,为json-file配置自动轮转

全局继续使用 json-file 时,可以编辑Docker守护进程配置文件。常见路径为 /etc/docker/daemon.json,已有内容要合并,不能直接覆盖:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "5"
  }
}

Docker官方文档要求 log-opts 中的数值与布尔值也写成字符串。保存后先验证JSON格式:

jq . /etc/docker/daemon.json

没有jq时可以使用发行版提供的JSON校验工具。然后安排维护窗口重启Docker:

sudo systemctl restart docker
sudo systemctl status docker --no-pager
docker info --format '{{.LoggingDriver}}'

重启Docker可能影响没有启用live-restore的容器,生产环境不要在高峰期直接执行。更重要的是,守护进程的新默认配置只会应用到之后创建的容器,现有容器不会自动继承。需要通过Compose或原始创建参数重建容器,并先确认数据卷、网络和环境变量都已写入可重复的部署配置。

第七步,也可以使用local日志驱动

Docker推荐在不依赖外部日志系统的场景考虑 local 驱动,它默认提供轮转并使用更节省空间的格式。全局配置示例:

{
  "log-driver": "local",
  "log-opts": {
    "max-size": "20m",
    "max-file": "5"
  }
}

也可以只为单个容器指定:

docker run --log-driver local \
  --log-opt max-size=20m \
  --log-opt max-file=5 \
  IMAGE

切换驱动前确认监控、日志采集和审计工具是否依赖JSON文件路径。使用journald、fluentd或其他远程驱动时,应按相应后端设置保留周期和容量告警,不能继续套用本地JSON日志的清理方法。

旧服务器的Docker目录已经混合大量历史容器、手工参数和不明数据卷时,可以先在 萤光云 复现Compose配置和日志策略,再用 LightNode 的按小时计费环境做一次重建验收。只迁移明确归属的数据卷和脱敏配置,不能把混乱目录整体复制过去。

第八步,从应用侧减少无效日志

轮转解决的是上限,应用仍应减少重复输出。检查日志级别、异常重试间隔、健康检查频率和访问日志格式。认证失败、数据库断连或某个文件不存在每秒重复几百次时,应该修复错误与退避策略,而不是长期保留同样的信息。

结构化日志要控制字段长度,不要把完整请求体、二进制内容或大段堆栈在每次请求中重复写出。访问日志可保留状态码、响应时间、请求路径和追踪ID,敏感字段应脱敏。业务审计日志与调试日志最好分开保存,设置不同保留周期。

同时为系统盘设置分级告警,例如容量达到70%、85%和95%时分别通知。等磁盘100%以后再处理,Docker API、数据库和系统服务可能已经无法正常写入,恢复难度会明显增加。

第九步,验证轮转真的生效

重建目标容器后查看实际日志配置:

docker inspect CONTAINER --format '{{json .HostConfig.LogConfig}}'
docker inspect CONTAINER --format '{{.LogPath}}'

确认驱动、max-sizemax-file 与预期一致。然后在测试环境产生可控日志,观察文件达到上限后是否轮转,docker logs --tail 50 是否仍能读取近期内容。不要在生产环境用无限循环快速写日志。

最后持续观察至少一个原故障周期,记录磁盘使用率、日志增长速度、轮转文件数量和容器错误率。容器重建、Docker重启和服务器重启后都要复核一次,证明配置来自正式部署文件,而不是临时命令。

常见问题

删除容器日志会不会导致容器停止?

直接删除由Docker管理的日志文件不受支持,也可能出现空间不释放或日志读取异常。紧急情况下应先确认单个路径并保存证据,再谨慎截断;长期方案仍是配置日志驱动和轮转。

设置daemon.json以后,旧容器为什么还在写大日志?

新的默认日志配置只对新创建的容器生效。旧容器需要按原有Compose或部署参数安全重建,普通的停止再启动不会改变它的日志配置。

max-size和max-file应该设置多大?

要根据错误发生频率、排查所需时间和磁盘容量计算。关键不是照搬20MB,而是确保保留窗口足够调查,同时所有容器的最坏占用不会挤满系统盘。

赞(0)
未经允许不得转载;国外VPS测评网 » Docker日志占满磁盘怎么办?清理与轮转教程
分享到