首页 帮助中心 Docker容器日志占满磁盘?日志清理与大小限制设置
Docker容器日志占满磁盘?日志清理与大小限制设置
时间 : 2026-07-23 14:38:40
编辑 : 华纳云
阅读量 : 7

  服务器磁盘告警,du -sh一查,发现/var/lib/docker/containers占了上百G。这种情况我每年至少帮人处理七八回,而且每次都是同一个原因:容器日志没限制。

  Docker默认的日志驱动是json-file,这个驱动会把容器的标准输出和标准错误全部写到宿主机的JSON文件里,而且默认不轮转、不限制大小。一个容器跑个一星期,日志文件干到几十G是家常便饭。如果你的容器里跑的是Java应用,GC日志加上业务日志全打stdout,那磁盘撑爆的速度比你想象的要快得多。

  这篇文章直接给方案:怎么查、怎么清、怎么从根本上限制,一次解决。

  先看看磁盘到底被谁吃了?

  别急着删东西,先搞清楚是什么占的空间。

# 查看磁盘整体使用情况
df -h

# 定位Docker目录的大小
du -sh /var/lib/docker/

# 进一步看是哪个子目录大
du -sh /var/lib/docker/containers/* | sort -rh | head -10

  第二条命令会列出所有容器ID目录的大小,按从大到小排,最大的那几个就是罪魁祸首。记下容器ID,后面有用。

  如果你用的是devicemapper存储驱动(老版本Docker常见),日志路径可能不太一样,但绝大多数场景下json-file的日志都在 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log 这个文件里。

  确认一下某个容器的日志文件到底有多大:

ls -lah /var/lib/docker/containers/<容器ID>/<容器ID>-json.log

  看到文件大小的时候别吃惊,我见过最大的是单文件280G,直接把整个数据盘写爆了。

  临时清理:先让磁盘喘口气

  磁盘告警的时候,最紧急的任务是马上释放空间,让服务先恢复。这时候直接用truncate命令清空日志文件,不要用rm删除

  为什么要用truncate而不是rm?因为容器运行时,Docker会一直持有这个日志文件的文件句柄。你用rm删了文件,磁盘空间并不会立即释放,要等到容器停止或者进程退出才行。而truncate是直接把文件内容截断,空间实时释放,效果立竿见影。

# 先把文件内容清空,保留文件本身
truncate -s 0 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log

  清空之后再看磁盘使用率,应该马上就降下来了。

  如果你不确定具体是哪个容器,或者想一次性清空所有容器的日志,可以用这条命令:

find /var/lib/docker/containers/ -name "*-json.log" -exec truncate -s 0 {} \;

  这条命令会找到所有容器的json.log文件,逐一清空。执行之前最好先确认一下有哪些日志文件特别大:

find /var/lib/docker/containers/ -name "*-json.log" -exec ls -lh {} \;

  看到过大的文件再决定要不要全清,别把想保留的日志也清掉了。

  根本解决:配置日志轮转和大小限制

  手动清空只是救急,治本必须给Docker配置日志轮转策略。Docker提供了两种方式:一种是修改daemon.json做全局默认配置,一种是在docker-compose里针对单个容器配置。两种都用得上。

  方案一:修改Docker Daemon全局配置

  编辑 /etc/docker/daemon.json,如果文件不存在就新建一个:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3",
    "compress": "true"
  }
}

  配置解释:

  max-size: "100m":单个日志文件最大100MB,超过这个大小就轮转。

  max-file: "3":保留最近3个轮转文件。算下来日志总大小上限就是100MB × 3 = 300MB。

  compress: "true":轮转后的旧文件自动压缩成gzip格式,进一步节省空间。

  改完之后需要重启Docker服务让配置生效:

systemctl daemon-reload
systemctl restart docker

  注意:这个配置只对重启之后新建的容器生效,已经存在的容器不会自动应用新配置。已经在跑的容器需要重建才会用新的日志策略。

  另外,daemon.json 里可能已经有其他配置项(比如registry-mirrors、insecure-registries),千万别直接覆盖,用编辑器追加内容进去,保证JSON格式正确。改完后用 docker info | grep "Logging Driver" 确认当前的日志驱动已经变成json-file。

  方案二:docker-compose里单独配置

  如果你用docker-compose管理容器,可以在每个服务的配置里单独指定日志限制,这个方式更灵活,不用重启整个Docker服务:

version: '3.8'
services:
  web:
    image: nginx:latest
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "2"
    ports:
      - "80:80"

  这样只对web这个容器生效,其他容器不受影响。适合那种日志量特别大的服务单独给大一点的配额,普通的服务给个小配额。

  方案三:docker run时直接指定

  如果你习惯用docker run启动容器,可以在命令行里加上日志参数:

docker run -d \
  --log-driver json-file \
  --log-opt max-size=50m \
  --log-opt max-file=2 \
  nginx:latest

  这种方式适合临时测试或者少量容器管理的场景,生产环境大规模部署不太方便。

  对已存在的容器如何应用新配置?

  这是一个比较常见的问题:daemon.json改了,但老容器还在用旧配置,日志文件还在疯涨。

  解决办法是重建容器。如果你的容器是有状态的服务(比如数据库),操作要谨慎。对于无状态的服务,重建很简单:

docker-compose down
docker-compose up -d

  对于单独运行的容器,先停止再重新创建:

docker stop <容器名或ID>
docker rm <容器名或ID>
docker run ... # 带新的日志参数重新创建

  如果容器用的是volume持久化数据,重建不会有数据丢失。但如果是数据库容器,建议先做好备份再操作。

  还有一种更进阶的做法:不用重建容器,而是用logrotate配合cron来轮转Docker的日志文件。这个方案的逻辑是在宿主机层面,用系统自带的logrotate工具定期对Docker的json.log文件做轮转和压缩。考虑到Docker本身已经提供了完善的日志管理机制,一般没必要再用logrotate绕一圈。除非你有特殊需求,比如想保留更长时间的日志归档,或者想对日志做额外的处理(比如上传到对象存储),这种场景下可以组合使用。

  日志驱动的选择:不只是json-file

  Docker支持的日志驱动远不止json-file。如果你的环境对日志管理有更高的要求,可以考虑切换驱动。

  syslog驱动:把所有容器的日志统一发给syslog,再由syslog负责轮转和管理。适合老派运维风格,日志集中到系统日志里统一处理。

  fluentd驱动:直接把日志发到fluentd日志收集器,然后再转给Elasticsearch或者其他存储。这是云原生环境下比较流行的方式,尤其配合EFK/ELK栈做日志分析的时候,省去了在宿主机上存日志的环节。

  gelf驱动:发给Graylog,也是日志分析方向的。

  none驱动:不要日志,完全不记录。测试环境用可以,生产环境慎用。

  切换驱动只需要在daemon.json里改 log-driver 的值,同时配上对应的 log-opts

{
  "log-driver": "fluentd",
  "log-opts": {
    "fluentd-address": "localhost:24224"
  }
}

  一些容易被忽略的细节

  journald日志也别忘:如果你的系统用了journald,并且Docker容器把日志打到了journald里,那systemd-journald本身也可能有日志占空间的隐患。检查journald的占用:

journalctl --disk-usage

  如果占用太大,调整 /etc/systemd/journald.conf 里的 SystemMaxUse 参数。

  docker system prune的局限:很多人以为 docker system prune -a 会清理日志文件,但实际并不会。这个命令清理的是:停止的容器、未使用的网络、悬空的镜像、构建缓存,日志文件不在这之列。想单独清理日志,得用上面说的truncate或者配置自动轮转。

  查看当前容器的日志配置:想知道某个容器当前使用的是哪个日志驱动、限额是多少,用inspect命令:

docker inspect <容器ID> | jq '.[0].HostConfig.LogConfig'

  返回结果里会显示driver和options,方便确认配置是否生效。

  容器日志管理这件事,说大不大说小不小。配置好了,它安安静静地在角落里轮转压缩,你根本感觉不到它的存在。配置不好,它能在你睡觉的时候把磁盘撑爆,然后你被监控告警吵醒,半夜起来连服务器做应急处理。哪种体验更好,你自己选。

相关内容
客服咨询
7*24小时技术支持
技术支持
渠道支持