Docker 容器磁盘占用持续增长排查手册
服务器磁盘明明刚扩过容,几天后又被 Docker 吃满,容器还频繁因为磁盘不足重启,这是很多线上环境的常见故障。本文给出一套可复现的排查手册:先定位、再分层、最后清理与预防,避免上来就删镜像把业务删停。
第一步:确认到底是谁在占磁盘
先看主机整体,再看 Docker 内部账本,两者要对得上:
df -h
du -sh /var/lib/docker/* | sort -rh | head -20
docker system df
docker system df -v
docker system df 会分别列出镜像、容器、本地卷和构建缓存的占用。重点看 RECLAIMABLE 一列:它代表可回收空间,但不等于可以马上删。
第二步:分层排查四个大头
1. 容器日志失控
没有配日志轮转的容器最常见:一个写 access 日志的 Web 容器,一周就能写出几十 GB。
du -sh /var/lib/docker/containers/*/*-json.log
ls -lh /var/lib/docker/containers/<容器ID>/*-json.log
根治办法是在 daemon.json 或 compose 里配好日志上限:
{
"log-driver": "json-file",
"log-opts": {"max-size": "10m", "max-file": "3"}
}
改完要重建容器才生效,正在运行的容器不会自动套用新配置。
2. overlay2 可写层膨胀
容器内写入但不属于挂载卷的数据都会进 overlay2 的可写层。典型来源是:应用把缓存、临时文件、上传文件写进了容器内部,而不是卷里。
docker ps -s
docker diff <容器名>
docker ps -s 的 SIZE 是可写层大小,docker diff 能看到容器相对镜像新增和改动的文件。确认后,把数据目录改挂到命名卷或绑定目录,并清理容器内无用的缓存目录。
3. 悬空卷与孤儿卷
容器删了,卷不一定删。长期累积的匿名卷和无主卷是隐形大头:
docker volume ls
docker volume ls -f dangling=true
docker volume inspect <卷名>
只删除确认无业务的悬空卷,不要批量删所有卷:
docker volume prune
生产环境执行前,先用 inspect 确认挂载点和创建时间,数据库卷一律手工核对。
4. 镜像与构建缓存
频繁构建、每次都打新 tag、旧镜像不清理,镜像层会越积越多:
docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -rh | head -20
docker builder du
清理顺序建议:先清构建缓存,再清悬空镜像,最后按时间清理明确废弃的旧版本镜像:
docker builder prune
docker image prune
docker image prune -a --filter "until=720h"
prune -a 会删除未被容器使用的全部镜像,生产节点务必先确认没有待回滚的旧版本。
第三步:安全清理的顺序
不要一上来就执行 docker system prune -a --volumes。推荐顺序是:
- 停止并删除已确认废弃的容器;
- 清理容器日志和构建缓存;
- 清理悬空卷和悬空镜像;
- 重新执行
docker system df和df -h核对回收量; - 观察业务容器是否正常,确认没有误删数据卷。
如果磁盘已经 100%,先删最确定的日志文件恢复一点空间,再做系统性清理,避免在满盘状态下执行大规模 prune 失败。
预防措施
- 日志必须配 max-size 和 max-file,重要日志走集中日志而不是容器本地;
- 业务数据、上传文件、缓存目录一律挂卷,容器本身保持无状态;
- CI 构建用固定清理策略,保留最近 N 个可回滚版本,其余自动清理;
- 每周跑一次
docker system df,并对磁盘使用率设 80% 告警,超过阈值先定位再清理; - 关键节点扩容前先确认是数据增长还是垃圾增长,避免把清理问题变成扩容成本。
总结
Docker 磁盘问题很少是单一原因,常见组合是日志失控加可写层膨胀,再叠加孤儿卷和旧镜像。按“总量、分层、单点确认、安全清理、预防告警”的顺序处理,既能快速恢复空间,也不会在清理时误删业务数据。
- 点赞
- 收藏
- 关注作者
评论(0)