
Docker服务器运行一段时间后,磁盘空间可能被镜像、停止的容器、构建缓存、容器日志和数据卷逐渐占满。严重时会出现镜像拉取失败、容器无法启动、数据库无法写入,甚至SSH登录和系统服务异常。
遇到这种情况,不要直接删除 /var/lib/docker,也不要一开始就执行带有 --volumes 的全量清理命令。正确做法是先确认哪个分区已满,再判断空间由哪类Docker数据占用,最后按照风险从低到高逐项处理。
本文以Linux服务器上的Docker Engine为例,介绍一套可以直接执行的排查与清理流程。
一、先确认磁盘空间和inode是否耗尽
首先查看各分区的容量:
df -hT |
重点关注Docker数据目录所在分区的 Use%。Docker Engine默认把数据保存在 /var/lib/docker,但服务器可能修改过数据目录,可以使用下面的命令确认:
docker info --format '{{.DockerRootDir}}' |
如果磁盘容量还有剩余,但系统仍然提示“no space left on device”,还要检查inode:
df -ih |
大量小文件可能耗尽inode。此时仅删除一个大文件未必能解决问题,需要继续定位产生海量小文件的目录。
| 如果根分区已经达到100%,建议先停止持续写入大量日志的异常服务,避免清理过程中空间继续增长。 |
二、查看Docker各类资源占用
Docker提供了专门的磁盘统计命令:
docker system df |
它会分别显示镜像、容器、本地数据卷和构建缓存占用,并标出理论上可以回收的空间。
需要查看具体对象时执行:
docker system df -v |
输出中需要重点关注:
| 项目 | 常见占用来源 | 清理风险 |
|---|---|---|
| Images | 历史版本镜像、无标签镜像、未使用镜像 | 中 |
| Containers | 已停止容器及其可写层 | 中 |
| Local Volumes | 数据库、上传文件和持久化业务数据 | 高 |
| Build Cache | Dockerfile构建产生的缓存 | 低至中 |
还可以从系统目录角度查看Docker数据目录的一级占用:
sudo du -xhd1 /var/lib/docker 2>/dev/null | sort -h |
如果Docker根目录不是 /var/lib/docker,请替换成 docker info 查询到的实际路径。
三、先做低风险清理
1. 清理悬空镜像
悬空镜像通常没有标签,常见于重复构建和更新镜像之后。先查看:
docker image ls --filter dangling=true |
确认后清理:
docker image prune |
该命令默认只删除悬空镜像,相比直接使用 docker image prune -a 更稳妥。
2. 清理构建缓存
频繁执行 docker build 或持续集成任务的服务器,构建缓存可能占用大量空间。
先查看Docker整体占用:
docker system df |
然后清理当前未使用的构建缓存:
docker builder prune |
执行前Docker会显示警告并要求确认。生产环境中不建议直接添加 -f,保留确认步骤更安全。
3. 检查停止的容器
列出全部容器:
docker container ls -a |
仅查看已停止容器:
docker container ls --filter status=exited |
如果某个停止容器已确认不再需要,可以按名称或ID删除:
docker container rm 容器名称或ID |
需要批量清理所有停止容器时再使用:
docker container prune |
注意,删除容器会同时删除其可写层。没有写入数据卷或绑定目录的数据可能随容器一起丢失。
四、谨慎清理未使用镜像
下面的命令不仅处理悬空镜像,还会删除没有被任何现有容器引用的镜像:
docker image prune -a |
它可能删除用于回滚的旧版本镜像。清理前建议先执行:
docker image ls docker container ls -a |
确认旧镜像可以从镜像仓库重新拉取,并且不再承担故障回滚用途。
也可以使用时间过滤条件,减少误删近期镜像的概率。例如清理创建时间超过168小时且未被使用的镜像:
docker image prune -a --filter "until=168h" |
时间过滤只能缩小清理范围,不能代替人工确认。
五、使用docker system prune前要看清范围
Docker提供了一条综合清理命令:
docker system prune |
默认情况下,它会清理停止的容器、未使用的网络、悬空镜像和未使用的构建缓存。
如果添加 -a:
docker system prune -a |
还会清理所有未被容器引用的镜像,影响范围明显扩大。
不建议在不检查数据的情况下执行:
docker system prune -a --volumes |
--volumes 会把符合清理条件的匿名数据卷纳入范围。数据卷可能保存数据库、网站上传文件、配置或其他持久化数据,误删后通常无法通过重新创建容器恢复。
安全原则:先分别查看和清理镜像、容器、缓存,最后才考虑综合清理;生产服务器不要把带有 --volumes 的命令作为日常定时任务。 |
六、重点排查不断增长的容器日志
镜像和容器清理后空间仍然不足,常见原因是容器日志持续增长。
先查看容器使用的日志驱动:
docker info --format '{{.LoggingDriver}}' |
查看某个容器的日志配置:
docker inspect --format '{{.HostConfig.LogConfig.Type}} {{json .HostConfig.LogConfig.Config}}' 容器名称 |
如果使用 json-file 日志驱动,可以查询Docker记录的日志文件路径:
docker inspect --format '{{.LogPath}}' 容器名称 |
Docker官方不建议使用外部工具直接操作日志驱动管理的内部文件,因为这可能干扰Docker日志系统。与其长期依赖手动截断日志,更可靠的方案是配置日志轮转,然后重新创建容器。
推荐方案:使用local日志驱动
编辑 /etc/docker/daemon.json。如果文件原本已有其他配置,需要把下面字段合并进去,不要直接覆盖整个文件:
{ "log-driver": "local", "log-opts": { "max-size": "10m", "max-file": "3" } } |
检查JSON格式后重启Docker:
sudo systemctl restart docker |
该配置只会自动应用于之后新建的容器。已有容器需要在确认编排文件和数据挂载无误后重新创建,才会使用新的日志配置。
如果不希望修改全局设置,也可以在创建单个容器时指定:
docker run \ --log-driver local \ --log-opt max-size=10m \ --log-opt max-file=3 \ 镜像名称 |
使用Docker Compose时,可以在对应服务中配置:
services: app: image: your-image logging: driver: local options: max-size: "10m" max-file: "3" |
配置完成后重新创建相关服务:
docker compose up -d --force-recreate |
执行前要确认Compose配置、环境变量和数据卷均已保存。
七、数据卷为什么必须最后处理
数据卷拥有独立于容器的生命周期。删除容器后,命名数据卷可能仍然保留,其中经常存放:
- MySQL、PostgreSQL等数据库文件
- WordPress等网站的上传内容
- 应用配置与密钥
- 队列、搜索引擎和监控系统数据
查看数据卷:
docker volume ls |
查看某个数据卷的详细信息:
docker volume inspect 数据卷名称 |
确认数据卷未被使用且内容已经备份后,才能删除指定数据卷:
docker volume rm 数据卷名称 |
批量删除未被容器挂载的数据卷需要格外谨慎:
docker volume prune |
“未被当前容器挂载”不等于“业务不再需要”。例如已经删除的数据库容器可能仍然依赖原来的命名卷进行恢复,因此不能仅根据未挂载状态判断数据是否可以删除。
八、清理后如何验证
完成清理后再次检查系统分区:
df -hT df -ih |
检查Docker占用:
docker system df -v |
检查容器状态:
docker container ls -a |
如果清理后空间没有明显变化,需要继续检查:
- Docker数据目录是否位于其他分区。
- 是否存在仍被进程占用但已经删除的文件。
- 应用是否把日志写入绑定挂载的宿主机目录。
- 数据库、备份文件或系统日志是否才是真正的占用来源。
- 使用containerd镜像存储时,相关数据是否位于单独的存储路径。
查找“已删除但仍被进程占用”的文件可以使用:
sudo lsof +L1 |
确认对应进程和业务影响后,再决定重启服务或释放文件句柄。
九、如何防止Docker再次占满磁盘
完成一次清理只能解决当前问题,还需要建立长期控制措施:
1. 为容器日志设置上限
优先使用带轮转能力的日志驱动,或者把日志发送到集中式日志系统。不要让默认日志无限增长。
2. 定期监控Docker占用
可以定期执行:
docker system df df -hT df -ih |
并为磁盘使用率设置告警。不要等到分区达到100%才处理。
3. 控制镜像版本数量
部署完成后保留必要的当前版本和回滚版本,清理长期不用的历史镜像。镜像仓库中的版本策略也要同步管理。
4. 把持久化数据放入明确的数据卷
数据库和业务文件应使用命名卷或绑定挂载,并建立独立备份。不要依赖容器可写层保存重要数据。
5. 为Docker规划独立磁盘
镜像构建频繁、日志量大或容器数量较多时,可以把Docker数据目录规划到容量充足的独立分区。迁移数据目录前必须停止Docker、完成备份并核对存储驱动,不建议在故障现场临时移动目录。
十、推荐的安全处理顺序
遇到Docker磁盘空间占满,可以按照下面的顺序操作:
- 使用
df -hT和df -ih确认容量或inode问题。 - 使用
docker info确认Docker数据目录。 - 使用
docker system df -v定位镜像、容器、卷和缓存占用。 - 优先清理悬空镜像和无用构建缓存。
- 人工确认后删除停止容器和未使用镜像。
- 排查容器日志,并配置日志轮转。
- 备份和核对业务后,才处理数据卷。
- 清理完成后检查容器状态、磁盘空间和关键业务。
总结
Docker磁盘占满通常不是单一原因造成的。镜像历史版本、停止容器、构建缓存、不断增长的日志以及长期遗留的数据卷,都可能共同占用空间。
最重要的原则是先定位、后清理,并把数据卷和日志文件视为高风险对象。docker system prune 可以提高处理效率,但它不能代替业务确认和数据备份。完成清理后,还应配置日志轮转、磁盘监控和镜像保留策略,避免相同问题反复发生。




