找出 /var/lib/docker/containers/ 下体积排名前 10 的日志文件
解决 Docker 容器日志撑爆磁盘 的最快终极方案,就是直接修改 /etc/docker/daemon.json 全局限制单日志文件体积与保留数量,并立刻使用 truncate 命令对已超大的日志做安全清零,绝不能粗暴执行 rm -rf。
在生产环境中,90% 的宿主机磁盘告警都是因为开发人员把日志级别调成 DEBUG 且未对 Docker 的 json-file 日志驱动做体积限制。容器在后台疯狂吐日志,几百 GB 的磁盘几小时就被占满,最后导致数据库挂掉、服务响应超时。
下面这套方案是我在数十个生产集群中验证过的排查与治理流程,按步骤操作即可永久解决该问题。
一、 核心方案速览
解决 Docker 日志膨胀问题遵循“先止血、再根治、后防复发”的原则:
- 应急止血(立刻释放空间):不要停容器,直接用
truncate -s 0截断日志文件,空间秒级释放。 - 全局根治(永久生效):配置 Docker Daemon 的
log-opts,限制每个容器的日志大小(如 100M)和滚转数量(如 3 个)。 - 单容器覆盖(灵活调整):在
docker-compose.yml或docker run中对高频输出服务单独设置日志策略。 - 清理残余(兜底防守):清理悬挂镜像(dangling images)与未使用的数据卷(volumes)。
二、 实操细节深度拆解
1. 应急止血:安全清空已有超大日志
很多新手运维看到磁盘满了,习惯性执行 rm -rf /var/lib/docker/containers/*/*.log。这是巨大的坑!
如果容器进程还在运行,它依然持有该日志文件的句柄(File Descriptor),你删了文件,磁盘句柄不释放,df -h 看依然是 100%,必须重启 Docker 或容器才能释放空间,这直接导致服务中断。
正确做法:使用 truncate 截断文件内容,无需重启服务。
第一步:快速定位谁在疯狂写日志
# 找出 /var/lib/docker/containers/ 下体积排名前 10 的日志文件
du -d 2 -h /var/lib/docker/containers/ | sort -h -r | head -n 10
第二步:一键安全清空所有容器日志
运行以下命令,直接将所有 *-json.log 文件体积置为 0:
# 安全清空,句柄不会丢失,磁盘空间立刻释放
find /var/lib/docker/containers/ -name "*-json.log" -exec truncate -s 0 {} +
避坑点:如果不确定是哪个容器,可以结合 docker ps --no-truncate 查出的 Container ID 与路径中的哈希值进行比对。
2. 全局根治:修改 Docker Daemon 配置文件
止血之后,必须在 Docker 引擎层面限制日志增长,否则过几天磁盘依然会被撑爆。
编辑 Docker 全局配置文件(不存在则新建):
vim /etc/docker/daemon.json
写入以下配置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"live-restore": true
}
参数实操解析:
"log-driver": "json-file":Docker 默认日志驱动。"max-size": "100m":单个日志文件最大允许 100MB。超过后自动触发滚转(Rotate)。"max-file": "3":最多保留 3 个日志文件(旧日志自动删除)。即:单个容器最多产生100M * 3 = 300M的日志。"live-restore": true:极其重要! 允许 Docker 守护进程在重启或热加载配置时,容器保持运行状态,避免重启 Docker 导致服务短暂中断。
配置完成后,重载配置(不要直接 systemctl restart docker):
systemctl reload docker
避坑点:此全局配置仅对“新创建的容器”生效! 已经运行的旧容器必须销毁并重新创建(docker stop -> docker rm -> docker run)才能继承配置。
3. 局部覆盖:针对特定服务单挑配置
如果你有些关键服务(如 Java 网关、订单系统)需要保留更多上下文日志排查问题,而一些无所谓的服务(如 Redis、Nginx)日志可以压缩,可以在服务编排文件中单独指定。
在 docker-compose.yml 中配置:
version: '3.8'
services:
payment-service:
image: payment:v1.0.2
container_name: payment-service
restart: always
logging:
driver: "json-file"
options:
max-size: "500m" # 关键业务允许留大一点
max-file: "5"
ports:
- "8080:8080"
redis-cache:
image: redis:6.2-alpine
container_name: redis-cache
logging:
driver: "json-file"
options:
max-size: "10m" # 缓存数据库限制严格一点
max-file: "1"
在 docker run 原生命令中配置:
docker run -d \
--name app-test \
--log-driver json-file \
--log-opt max-size=50m \
--log-opt max-file=2 \
-p 80:80 \
nginx:alpine
三、 高频关联问题与避坑指南
在治理 Docker 容器日志撑爆磁盘 的过程中,你一定会遇到以下几个衍生问题,顺带一并解决:
问题 1:已经执行了 rm -rf 删除了 log 文件,但磁盘空间依旧没有释放
- 原因:进程持有删除文件的句柄,空间被
deleted状态的文件占用。 - 排查命令:
lsof -N | grep deleted # 或直接查占用大量空间但已删除的文件 lsof / | grep deleted | sort -nr -k7 | head -n 10 - 解决办法:
找到输出列表里的
PID(进程ID)和FD(文件描述符),直接向句柄文件写入空内容:# 假设 PID 为 12345,FD 为 4 > /proc/12345/fd/4如果是非核心容器,直接重启该容器即可释放:
docker restart <container_id>。
问题 2:应用在容器内部往 /app/logs/app.log 写日志,根本不吐给 stdout
很多老旧 Java 项目(Log4j/Logback)或 Python 项目没有遵循 云原生 12 因素(12-Factor App)标准,不把日志打到标准输出(stdout/stderr),而是直接写进容器内部的硬盘路径。这会导致 Docker 的 max-size 限制完全失效!
- 排查方法:Docker 的
json-file日志没变大,但是容器目录/var/lib/docker/overlay2/异常巨大。 -
终极解决方案:
- 推进开发改代码:把日志追加器(Appender)改成
ConsoleAppender,直接打到标准输出。 - 挂载宿主机目录 + 宿主机 logrotate:如果改不动代码,把容器内日志目录挂载出来,用 Linux 原生的
logrotate治理。
挂载与 logrotate 实操:
# 运行容器时挂载日志目录 docker run -d -v /data/logs/my-app:/app/logs my-app:latest在宿主机
/etc/logrotate.d/my-app创建切割规则:/data/logs/my-app/*.log { daily rotate 7 missingok notifempty compress copytruncate }注意:必须加上
copytruncate,原理也是清空源文件并保留句柄,避免应用崩溃。 - 推进开发改代码:把日志追加器(Appender)改成
问题 3:排除了日志,磁盘空间依旧被 Overlay2 占满
有时撑爆磁盘的不是 *-json.log,而是各种未清理的镜像碎片、废弃容器和数据卷。
-
排查 Docker 内部空间分布:
docker system df输出示例:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 15 5 12.5GB 8.2GB (65%) Containers 5 5 2.1GB 0B (0%) Local Volumes 10 2 45.3GB 40.1GB (88%) Build Cache 0 0 0B 0B -
安全清理脚本(建议配置 Cron 定时任务):
# 1. 清理无用容器、悬挂镜像(tag 为 <none> 的)、未使用的网络 docker system prune -f # 2. 如果确定没有挂载重要数据的孤立卷,强制清理未使用的 Volume(慎用,确认无无价数据) docker volume prune -f # 3. 删除 7 天前的无用镜像 docker image prune -a --filter "until=168h" -f
四、 结尾总结
面对 Docker 容器日志撑爆磁盘 这类问题,靠临时 rm 文件只能治标,并且极易引发句柄泄露的二次故障。真正落地可行的长效机制必须包含以下三步:
- 应急用
truncate -s 0替代rm,秒级恢复业务; - 全局部署
/etc/docker/daemon.json限制max-size与max-file,从根源掐断日志无限膨胀的可能; - 规范开发落地,强制应用使用标准输出(stdout),杜绝在容器内部盲目写本地日志文件。
自动化运维的本质就是把常见坑点写进初始化脚本。建议将上述 Daemon 的全局配置直接打包进 Jenkins/Ansible 的服务器初始化 Playbook 中,在新机器开荒阶段就将其封堵,从根本上绝后患。
相关文章
- 模拟关键词列表(实际操作读取TXT或CSV)
- 示例:使用 cURL 快速验证线上页面是否包含正确配置的 JSON-LD script 标签
- 找出 /var/lib/docker/containers/ 下体积排名前 10 的日志文件
- Role: 资深技术/行业专家兼内容重构编辑
- 站内专题页面的SEO权重分配:专题页SEO权重分配实战指南
- 解决网站跳出率过高的内容策略:干掉网站高跳出率的硬核内容策略
- 如何挖掘高转化的SEO选题:高转化SEO选题挖掘实操指南
- 英文站Blog引流实战避坑指南
- 搜索引擎算法对优质内容的判别标准:拆解搜索引擎优质内容判别标准
- B2B外贸独立站Topic Cluster内容矩阵搭建实操:外贸独立站Topic Cluster实战手册

