Docker 不限制日志文件大小磁盘会被撑爆

FreeGuideOnline 最新 2026-07-05

Docker 日志无限增长:磁盘被撑爆的隐患与根治方案

你是否遇到过服务器磁盘突然被占满,却找不到大文件?罪魁祸首很可能就是 Docker 容器的日志。默认情况下,Docker 不会对容器输出的 stdout/stderr 日志做任何大小或数量限制。一旦容器持续运行并输出大量日志,日志文件就会像滚雪球一样膨胀,直到占满整个磁盘。这不仅会导致服务异常,还会影响同一台主机上的其他应用,甚至使系统陷入不可用状态。本教程将带你理解这个问题,并提供几套从临时急救到永久防范的完整解决方案。

1. 为什么 Docker 日志会撑爆磁盘?

当我们使用 docker logs 查看容器输出时,背后依赖的是日志驱动(logging driver)。如果不做任何配置,Docker 默认使用 json-file 驱动,并将日志写入宿主机的 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log 文件中。这种纯追加式的写入方式,加上没有大小轮转机制,意味着:

  • 应用日志输出越多,文件越大。
  • 文件只增不减,除非手动删除或重启容器(旧版 Docker 中重启会清空日志,高版本中重启不会自动清空)。
  • 多个容器同时产生大量日志时,/var/lib/docker 所在分区会迅速被填满。

2. 如何发现“巨型”日志文件?

在排查磁盘空间问题时,可以先确认容器日志的占用情况。

2.1 检查 Docker 根目录磁盘使用

docker system df

该命令会显示镜像、容器、数据卷的总大小。重点关注 Local VolumesBuild Cache 之外,若 Containers 的总大小异常,可能就是日志在作祟。

2.2 找出占用最大的容器日志文件

可以直接进入 Docker 数据目录查看:

du -sh /var/lib/docker/containers/*/*-json.log | sort -hr | head -10

如果输出文件大小动辄上 GB,就需要立即处理。

2.3 使用脚本批量查看

如果希望看到容器名与日志大小的对应关系,可以执行以下命令:

sudo find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \; | awk '{print $5, $9}'

再结合 docker ps -a 中的容器 ID 进行映射。

3. 立即释放磁盘空间(紧急止血)

当磁盘已经接近写满,需要马上恢复服务可用性,不建议直接删除日志文件,因为 Docker 仍持有文件句柄,删除后空间不会真正释放。

正确做法:

  1. 清空日志内容而不删除文件

    sudo truncate -s 0 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log
    

    <容器ID> 替换为实际值。执行后日志文件会被清零,且 Docker 仍然可以正常写入,磁盘空间立即回收。

  2. 重启容器(谨慎使用) 在部分配置下,docker restart 会重新创建日志文件,旧的日志文件会被重命名(如 -json.log.1)。但默认的 json-file 驱动如果没有设置 max-size,新文件仍会无限增长,且旧文件不会自动删除,依然占用空间。所以重启后用 truncate 把旧文件也清掉更稳妥。

4. 永久限制日志大小:三种方案

要根治问题,必须对日志添加大小和文件数量限制。可以从 Docker 守护进程级别或容器级别进行配置。

4.1 修改 Docker Daemon 全局配置(影响所有容器)

编辑 Docker 守护进程配置文件 /etc/docker/daemon.json(如不存在则新建),加入以下内容:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
  • max-size:单个日志文件的最大大小,超过后自动轮转。常用单位 kmg
  • max-file:保留的轮转日志文件数量。例如设置为 3,会保留 -json.log-json.log.1-json.log.2,旧文件会被自动删除。

保存后重启 Docker 服务:

sudo systemctl restart docker

注意: 该配置仅对新创建的容器生效,已运行的容器不会自动继承。需重建容器才可应用。

4.2 在 docker rundocker-compose 中为单个容器指定

如果你不想影响全局,或需要针对不同容器设置不同大小,可以在启动容器时添加日志选项。

命令行方式:

docker run -d \
  --log-opt max-size=50m \
  --log-opt max-file=5 \
  --name myapp \
  your-image

Docker Compose 方式:docker-compose.yml 的 service 下添加 logging 字段:

services:
  myapp:
    image: your-image
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

然后重新创建容器:

docker-compose up -d

4.3 使用其他日志驱动

如果业务场景不需要使用 docker logs 查看日志,或者希望将日志统一发送到集中式平台(如 ELK、Loki、syslog),可以切换日志驱动,从根源上避免本地文件膨胀。常用替代驱动:

  • syslog:将日志发送到宿主机的 syslog 服务。
  • journald:写入 systemd journal,由 journal 自行管理轮转。
  • fluentd / gelf / loki:直接发送到远程日志收集系统,本地不保留文件。

修改 Daemon 全局驱动,或容器级 --log-driver 即可。例如使用 journald

docker run --log-driver=journald your-image

但要注意,切换后 docker logs 将无法查看日志。

5. 如何安全清理已有容器的历史日志?

假设你已经通过以上配置重建了容器,但宿主机上还残留着过去未轮转的巨型日志文件,可以按以下步骤清理:

  1. 找出所有容器 ID 对应的废弃日志文件(这些容器可能已被删除,但日志仍留在磁盘):
    sudo find /var/lib/docker/containers/ -name "*-json.log*" -type f
    
  2. 确认这些文件对应的容器是否还在运行。对于已停止或已经不再需要的容器,可以直接删除整个容器目录(需先删除容器):
    docker rm <容器ID>
    # 然后手动删除残留目录
    sudo rm -rf /var/lib/docker/containers/<容器ID>
    
  3. 对于仍在使用中的容器,应使用 truncate -s 0 清空文件,而不是直接 rm,否则可能导致 Docker 写入错误。

6. 设置监控与告警(避免未来再次踩坑)

  1. 磁盘使用监控
    在服务器上部署简单的磁盘监控,如 node_exporter + Prometheus + Grafana,或使用云厂商的监控报警服务。当 /var/lib/docker 所在分区使用率超过 80% 时告警。

  2. 日志轮转自动验证
    定期检查容器的日志选项是否生效:

    docker inspect --format='{{.HostConfig.LogConfig}}' <容器名>
    

    输出中应显示 max-sizemax-file 配置。

  3. 使用 cron 任务兜底
    编写一个脚本,每日查找大于特定阈值(如 500M)的 -json.log 文件并发出通知,或自动进行 truncate(谨慎操作,确保不影响业务)。

7. 总结

Docker 默认无限制日志写入是一个极易被忽略但后果严重的配置缺陷。你应当始终:

  • 在生产环境中 设置日志大小限制,无论全局还是单容器。
  • 定期审计 宿主机磁盘占用,尤其是 /var/lib/docker/containers 下的日志文件。
  • 将日志收集与容器引擎分离,使用集中式日志平台彻底摆脱本地文件依赖。

遵循以上实践,既能避免磁盘被撑爆的危机,又能建立一套可观测、可维护的日志体系。下次在启动容器时,别忘了加上 --log-opt max-size=100m —— 这小小的参数可以为你省去半夜处理磁盘故障的噩梦。