Docker 磁盘占用排查与清理

举报
yd_248971855 发表于 2026/11/03 10:30:59 2026/11/03
【摘要】 Docker 主机磁盘打满排查实战:从 47% 到告警只差一次镜像构建摘要:Docker 主机磁盘使用率告警是最常见的容器运维故障之一,但“清理”远不止一条 docker system prune。本文从一次真实告警切入,拆解 Docker 磁盘占用的四大元凶(镜像、容器可写层、日志、卷),给出精准定位每个元凶的命令链,并说明不同清理策略的风险边界,避免“清完之后服务起不来”的二次事故。 ...

Docker 主机磁盘打满排查实战:从 47% 到告警只差一次镜像构建

摘要:Docker 主机磁盘使用率告警是最常见的容器运维故障之一,但“清理”远不止一条 docker system prune。本文从一次真实告警切入,拆解 Docker 磁盘占用的四大元凶(镜像、容器可写层、日志、卷),给出精准定位每个元凶的命令链,并说明不同清理策略的风险边界,避免“清完之后服务起不来”的二次事故。

一、场景引入

周一早晨收到告警:某台 Docker 主机磁盘使用率 91%。登上去:

$ df -h /
/dev/vda1  100G  91G  4.2G  96% /

这台机器上跑着十几个容器,其中有两个是数据库。此时最危险的动作是直接执行网上搜来的:

docker system prune -a --volumes   # 千万别急着跑

--volumes 会连命名卷一起删——如果数据库数据在卷里没做外部备份,这一敲下去就是删库。正确姿势是先定位、再按风险等级逐项清理。

二、先看大盘:Docker 空间都花在哪

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          45        12        38.2GB    31.5GB (82%)
Containers      18        15        2.1GB     1.2GB (57%)
Local Volumes   9         7         22.4GB    3.1GB (13%)
Build Cache     63        0         4.8GB     4.8GB (100%)

关键看 RECLAIMABLE 列——可回收空间及占比。本例中镜像占 38GB、其中 31.5GB 可回收,是绝对大头;构建缓存 4.8GB 全部可回收。再看详细分布:

$ docker system df -v

逐镜像列出体积、逐容器列出可写层大小、逐卷列出占用,是精确定位的第一手数据。

三、四大元凶逐个排查

元凶一:悬空镜像与未使用镜像(通常是大头)

CI/CD 环境每天构建新版本,旧镜像不断堆积。定位:

# 悬空镜像(<none>:<none>,构建失败或被新版本顶替的残留)
$ docker images -f dangling=true
# 按体积排序看全部镜像
$ docker images --format '{{.Size}}\t{{.Repository}}:{{.Tag}}' | sort -h

清理(安全,不影响运行中容器):

$ docker image prune                # 只删悬空镜像
$ docker image prune -a             # 删除所有未被容器使用的镜像

注意 -a 的边界:有容器正在运行的镜像不会删,但“停止状态的容器”其镜像同样受保护——如果有些容器是临时停着的,它们会连带保护一批旧镜像不被回收。

元凶二:构建缓存

多阶段构建、频繁 docker build 会积累大量中间层缓存:

$ docker builder prune              # 清理全部构建缓存
$ docker builder prune --filter until=48h   # 只清 48 小时前的

构建缓存对下次构建速度有影响,清理后首次构建会变慢,属于“可接受代价”。

元凶三:容器日志(最容易被忽略)

docker system df 的 Containers 统计通常不含 json 日志文件,日志爆盘时 df 明明显示的是容器目录在涨。直接定位:

# 各容器日志文件实际大小(默认路径)
$ du -sh /var/lib/docker/containers/*/*-json.log | sort -h

单个容器的日志动辄几个 GB 很常见。立即止血(truncate 不会影响运行中的容器):

$ truncate -s 0 /var/lib/docker/containers/<容器ID完整串>/<容器ID完整串>-json.log

注意不能直接 rm——文件被 dockerd 持有句柄,rm 后空间不释放,且可能引起句柄异常。根治靠日志轮转配置,/etc/docker/daemon.json:

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

改完 systemctl restart docker(会重启所有容器,安排在维护窗口),此后每个容器日志上限 300MB 封顶。

元凶四:命名卷

$ docker volume ls
$ docker volume prune            # 只删"无容器引用"的卷

绝对不要加 -a 以外的激进参数去删正在使用的卷。数据库卷即使显示“可回收”,回收前也必须确认数据已备份或有外部存储。

四、删了容器但磁盘没释放?

常见“灵异现象”:容器删了、镜像删了,df 还是不降。按顺序查:

# 1. 悬空卷(容器已删,卷还在)
$ docker volume ls -f dangling=true
# 2. 已停止容器的可写层(停止≠删除,可写层还在)
$ docker ps -a --filter status=exited
# 3. overlay2 目录残留
$ du -sh /var/lib/docker/overlay2/* | sort -h | tail -5

第 2 项是最常见原因——docker stop 只是停止,可写层(包括日志配置、临时文件)原封不动,要 docker rm 才释放。

五、安全清理决策表

命令 释放对象 风险等级
docker builder prune 构建缓存 低(仅影响构建速度)
docker image prune 悬空镜像 低
truncate 日志文件 容器日志 低(不影响运行)
docker image prune -a 未使用镜像 中(回滚版本需重新拉取)
docker container prune 停止的容器 中高(确认容器不再需要)
docker volume prune 无引用卷 高(先确认无数据)
docker system prune --volumes 以上 + 卷 极高(删库级)

六、长效机制:别让磁盘再打满

清理只是治标,治本靠三件事:

  1. 日志轮转:部署时就在 daemon.json 配置 max-size,一次配置永久生效;
  2. CI/CD 侧控制镜像数量:构建流水线里加定时清理任务,保留最近 N 个版本;
  3. 监控前置:对 /var/lib/docker 目录做独立告警,85% 触发处理,别等到 95% 才动。

七、总结

Docker 磁盘排查的完整路径:docker system df 看大盘 → df -v 定位元凶 → 按决策表逐项清理 → 日志轮转根治。核心原则一句话:先定位再动手,volumes 永远最后碰,且碰之前先备份。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。