想必每一位和 Docker 打过交道的朋友,都可能遇到过“磁盘空间不足”的红色警报。明明服务器上没跑几个应用,怎么磁盘就悄悄地被占满了呢?
别慌,这其实是 Docker “热情好客”的副作用。它会默默地帮你保留很多“可能还有用”的东西,比如停止的容器、旧版本的镜像、以及挂掉的数据卷。时间一长,这些“囤积物”就成了吃掉你磁盘空间的“大户”。
今天,我们就来聊聊如何“断舍离”,给你的 Docker 来一次彻底的大扫除,让服务器“瘦身健体”,重新焕发活力!
诊断:你的磁盘空间去哪了?
在动手清理之前,我们得先搞清楚“敌人”藏在哪里。Docker 很贴心地提供了一个命令,让我们对磁盘占用情况一目了然。
docker system df
这个命令会像一份体检报告一样,告诉你镜像(Images)、容器(Containers)、本地数据卷(Local Volumes)和构建缓存(Build Cache)分别占用了多少空间,以及有多少是可以被回收的(RECLAIMABLE)。
通过这份报告,你就能知道谁是占用空间最多的“元凶”,然后我们就可以“对症下药”了。
清理:一键“瘦身”与“精准打击”
知道了问题所在,接下来就是动刀子的环节了。我们既可以“一键清扫”,也可以进行“精准点杀”。
1. 终极武器:docker system prune
这是 Docker 官方提供的“大扫除”工具,也是最简单粗暴、最常用的方法。 它可以一键清理掉那些已经停止的容器、悬空镜像(dangling images,即没有标签的镜像)、未被任何容器使用的网络和构建缓存。
docker system prune
案例: 假设你是一个开发人员,日常会构建很多测试镜像。每次构建新版本,旧版本的镜像虽然不再使用,但依然存在。久而久之,这些悬空镜像就会越积越多。运行 docker system prune 就可以快速将它们全部清理掉。
如果你想玩得更“狠”一点,可以加上 -a (all) 参数。
docker system prune -a
这个命令会把所有当前没有被任何容器使用的镜像都删掉,而不仅仅是悬空镜像。 注意: 这个命令威力巨大,执行前请三思,确保那些暂时没用但将来还可能用到的镜像不会被“误杀”。
2. “精准打击”:分类清理
有时候我们不想“一锅端”,只想清理某一类特定的资源。没问题,Docker 也为我们准备了“单兵作战”的武器。
清理已停止的容器:
docker container prune这个命令会删除所有已经停止运行的容器,释放它们占用的文件系统资源。
清理无用的镜像:
docker image prune这条命令专门用来删除悬空镜像。 如果想删除所有未使用的镜像,同样可以加上
-a参数。docker image prune -a清理无用的数据卷:
数据卷是用来持久化数据的,但有时候容器删了,数据卷却被遗忘了。docker volume prune这个命令可以帮你找到并删除那些不再被任何容器使用的数据卷。
清理无用的网络:
与数据卷类似,自定义的网络在容器删除后也可能被遗留下来。docker network prune
案例解析: 假设你有一个应用,之前使用了命名数据卷来存储数据库文件。后来你决定废弃这个应用,并删除了相关的容器。但如果你不手动清理,那个数据卷会一直存在,占用着磁盘空间。这时候 docker volume prune 就派上用场了。
预防:从源头“减负”
与其等磁盘满了再去清理,不如从一开始就养成好习惯,从源头上减少 Docker 的“囤积”。
1. 编写“苗条”的 Dockerfile
镜像是占用空间的大头。一个臃肿的镜像,不仅拖慢构建和部署速度,还会增加安全风险。 我们可以通过一些技巧来给镜像“瘦身”:
选用更小的基础镜像: 比如使用
alpine版本的镜像,而不是完整的ubuntu。alpine镜像通常只有几 MB 大小,非常轻量。使用多阶段构建 (Multi-stage builds): 这绝对是减小镜像体积的“神器”。 你可以将编译和运行环境分开。比如在一个阶段使用包含完整编译工具的镜像来构建你的应用,然后在另一个阶段只把编译好的产物拷贝到一个干净、轻量的运行环境中。
代码示例(一个简单的 Go 应用):
# ---- 构建阶段 ---- FROM golang:1.19-alpine AS builder WORKDIR /app COPY . . RUN go build -o myapp . # ---- 运行阶段 ---- FROM alpine:latest WORKDIR /app COPY /app/myapp . CMD ["./myapp"]解析: 在这个例子中,
builder阶段包含了完整的 Go 语言编译环境,体积较大。但最终我们生成的镜像是基于alpine的,只包含了编译好的二进制文件myapp,体积大大减小。合并指令并清理缓存: 在 Dockerfile 中,每一个
RUN,COPY,ADD指令都会创建一个新的镜像层。 我们可以将多个命令用&&连接起来,并在同一层中清理掉不再需要的包和缓存,从而减少镜像层数和体积。# 不推荐的写法 RUN apt-get update RUN apt-get install -y curl # 推荐的写法 RUN apt-get update && \ apt-get install -y curl && \ rm -rf /var/lib/apt/lists/*在安装完
curl后立即清理 apt 缓存,可以有效减小这一层的大小。
2. 使用 .dockerignore 文件
类似于 .gitignore,你可以在项目根目录下创建一个 .dockerignore 文件,告诉 Docker 在构建镜像时忽略掉哪些文件或目录(比如 node_modules、日志文件、临时的构建产物等)。这样可以避免将不必要的文件打包进镜像,同时也能加快构建速度。
终极手段:迁移 Docker 存储目录
如果你的服务器系统盘本身就不大,即使你经常清理,也可能很快就捉襟见肘。这种情况下,可以考虑将 Docker 的默认存储目录 /var/lib/docker 迁移到一个更大的磁盘分区上。
操作步骤(以 Linux 为例):
停止 Docker 服务:
systemctl stop docker创建新的存储目录并迁移数据:
# 假设你的大容量磁盘挂载在 /data mkdir -p /data/docker rsync -avz /var/lib/docker/ /data/docker/修改 Docker 配置文件:
编辑或创建/etc/docker/daemon.json文件,指定新的存储路径。{ "data-root": "/data/docker" }重启 Docker 服务:
systemctl daemon-reload systemctl restart docker确认迁移成功后,删除旧目录:
# 确认 docker info 中的 "Docker Root Dir" 已是新路径 docker info # 确认无误后删除 rm -rf /var/lib/docker
通过以上这些“诊断”、“清理”和“预防”的组合拳,相信你已经能够轻松应对 Docker 磁盘空间不足的问题了。让我们的 Docker 环境保持“干净整洁”,才能更高效、更稳定地为我们的应用服务!