共计 2613 个字符,预计需要花费 7 分钟才能阅读完成。
一、问题背景:硬盘又哭了
你是不是也遇到过这种情况:某天打开服务器一看,硬盘空间莫名其妙只剩下几个 G 了。一查才发现,Docker 这家伙悄悄占了几十个 G,甚至上百 G 的空间。
这事儿其实挺常见的。Docker 用着用着,就像家里的储物间一样,堆满了各种 " 可能以后用得上 " 的东西:
- 早就不用的旧镜像还躺在那里
- 测试完就停掉的容器尸体遍地
- 各种构建过程中产生的临时文件
- 已经悬空 (dangling) 的镜像层
最要命的是,Docker 默认不会主动清理这些东西。它就像一个勤俭持家的老人,啥都舍不得扔。
二、解决方案:对症下药
2.1 先看看到底占了多少空间
开工之前,咱得先摸清家底:
docker system df
这命令会给你一个清晰的报告,类似这样:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 15 5 8.5GB 6.2GB (72%)
Containers 20 3 2.1GB 1.8GB (85%)
Local Volumes 10 2 3.2GB 2.8GB (87%)
Build Cache 0 0 0B 0B
看到那个 RECLAIMABLE(可回收)没?那就是可以安全清理的空间。
2.2 终极大招:一键清理
如果你不想搞太复杂,直接上这个:
docker system prune -a --volumes
警告:这个命令会删除:
- 所有停止的容器
- 所有没有被容器使用的网络
- 所有没有被使用的镜像(不只是悬空镜像)
- 所有没有被使用的卷
执行前它会问你确认,输入 y 就开始清理了。
适用场景:测试环境、个人开发机器,或者你确定那些镜像不要了。
2.3 温柔版:分步清理
如果是生产环境,还是稳一点比较好:
第一步:清理停止的容器
docker container prune
这只删除已经停止的容器,不影响运行中的服务。
第二步:清理悬空镜像
docker image prune
悬空镜像就是那些没有标签的中间层镜像,通常是构建过程中产生的。
第三步:清理未使用的镜像
docker image prune -a
加了 -a 参数后,会删除所有没被容器使用的镜像。慎用!
第四步:清理数据卷
docker volume prune
这个要特别小心,数据卷里可能有数据库数据等重要内容。
2.4 进阶技巧:定向清理
有时候你只想删除特定的东西:
删除指定时间之前的容器:
docker container prune --filter "until=24h"
删除特定镜像:
docker rmi 镜像 ID
# 或者强制删除
docker rmi -f 镜像 ID
批量删除未使用的镜像:
docker images | grep "none" | awk '{print $3}' | xargs docker rmi
2.5 查看清理效果
清理完再跑一次:
docker system df
看着回收的空间数字往下掉,是不是有种收拾完房间的爽快感?
三、原理说明:为什么会占这么多空间
3.1 Docker 的存储机制
Docker 使用了一种叫 " 分层存储 " 的机制。每个镜像都由多个只读层组成,容器运行时会在最上面加一个可写层。
这种设计很聪明,可以节省空间(多个容器共享相同的基础层),但也容易产生垃圾:
- 你拉取了一个镜像的多个版本,旧版本不会自动删除
- 构建镜像时,每个指令都会创建一层
- 容器停止后,它的可写层还在占空间
3.2 Ubuntu 24.04 的特殊性
Ubuntu 24.04 使用的是较新的存储驱动(通常是 overlay2),虽然效率更高,但对于文件系统的占用计算可能有点 " 诚实过头 "。
另外,Ubuntu 24.04 的默认文件系统是 ext4,inode 的占用也要考虑进去。如果你创建了大量小文件的镜像,可能 inode 先用完,而不是实际空间。
可以用这个命令查看:
df -ih
四、常见问题
Q1:清理后空间还是没释放怎么办?
这可能是因为 Docker 使用了 thin pool 或者其他存储驱动的特性。试试重启 Docker 服务:
sudo systemctl restart docker
如果还不行,检查一下是不是容器日志占了空间:
sudo du -sh /var/lib/docker/containers/*/*-json.log
日志太大的话,可以配置日志轮转:
// /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Q2:误删了重要镜像怎么办?
赶紧重新拉取:
docker pull 镜像名: 标签
所以,清理前最好先备份一下镜像列表:
docker images > docker_images_backup.txt
Q3:能不能设置自动清理?
当然可以!创建一个定时任务:
sudo crontab -e
添加这一行(每周日凌晨 3 点清理):
0 3 * * 0 docker system prune -f
-f 参数表示不需要确认,直接清理。
Q4:生产环境能用 prune 吗?
可以,但要慎重:
-
- 千万别用
-a --volumes,会把正在用的镜像都标记为可删除
- 千万别用
- 只用
docker system prune -f(不带 -a),它只清理悬空资源 - 最好在业务低峰期执行
- 提前做好备份和镜像清单
Q5:为什么我的 Docker 目录在 /var/lib/docker 占了很多空间?
这是 Docker 的默认数据目录。如果根分区空间不够,可以考虑迁移 Docker 目录:
# 停止 Docker
sudo systemctl stop docker
# 迁移数据
sudo mv /var/lib/docker /home/docker
# 创建软链接
sudo ln -s /home/docker /var/lib/docker
# 启动 Docker
sudo systemctl start docker
或者修改配置文件指定新路径:
// /etc/docker/daemon.json
{"data-root": "/home/docker"}
总结
Docker 空间清理其实不难,关键是要:
-
- 定期检查:养成习惯,每隔一段时间跑一次
docker system df
- 定期检查:养成习惯,每隔一段时间跑一次
-
- 按需清理:测试环境可以激进点,生产环境要保守
-
- 做好备份:清理前记录一下现有的镜像和容器
-
- 配置日志:防止日志文件无限增长
-
- 自动化:设置定时任务,省心省力
记住一句话:磁盘空间就像钱包,总是在你不注意的时候就空了。定期清理,服务器才能跑得更欢快!
微信公众号文章:mp.weixin.qq.com/s/jqDizYje-SvThQ2opxFH0A
有问题欢迎留言讨论,如果这篇文章帮到了你,别忘了点个「在看」!