Docker 容器镜像瘦身,减少磁盘占用
很多朋友用 Docker 跑了一段时间后,发现磁盘空间越来越少。docker images 一查,十几 GB 甚至几十 GB 的镜像堆在那里,删又不敢乱删。
其实 Docker 容器镜像瘦身并不复杂,下面我从原因讲起,带你一步步减少磁盘占用。
为什么 Docker 镜像越来越臃肿?
Docker 镜像由一层层只读层组成。
每次 docker build、docker pull 或者运行容器后残留的临时层,都会占用磁盘。
常见元凶包括:
- 基础镜像过大:比如 Ubuntu 基础镜像有 200+ MB,而 Alpine 只有 5 MB。
- 未清理的构建缓存:
docker build产生的中间层不会自动删除。 - 悬挂镜像(dangling images):无标签的重复镜像。
- 停止的容器和未使用的网络/卷:这些对象的文件仍然留在磁盘。
了解原因后,我们直接动手操作。
第一步:检查当前磁盘占用情况
打开终端,先看看 Docker 占了多少空间:
docker system df
输出会显示镜像、容器、本地卷、构建缓存各自的占用。
如果想看更详细的信息,用:
docker system df -v
记录下当前总占用,便于后面对比效果。
第二步:清理无用的镜像、容器和构建缓存
重要提示:下面的操作会删除所有未被使用的对象,包括停止的容器、悬挂镜像、未使用的网络和构建缓存。
如果你的某些容器需要保留日志或数据,请先确保卷(volume)已挂载,或者先把容器停止(docker stop)但不要删除。
执行清理命令:
docker system prune -a --volumes
参数说明:
-a:删除所有未被使用的镜像(不只是悬挂镜像)。--volumes:一并清理未使用的匿名卷(慎用,确认不需要的数据)。- 不加
--volumes的话,卷不会被清理,更安全。
执行后会让你确认,输入 y。
清理完再跑一次 docker system df,你会发现磁盘占用明显下降。
第三步:给现有镜像“减肥”——多阶段构建
如果你自己写 Dockerfile,强烈推荐多阶段构建。
它允许你在一个 Dockerfile 中使用多个 FROM 语句,只有最后一个阶段的东西会进入最终镜像。
举例:编译 Go 程序时,先在一个带 Go 环境的镜像里编译,再把编译产物复制到一个空镜像(如 scratch 或 alpine)中。
# 第一阶段:编译
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 第二阶段:运行
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
这样最终镜像只有几十 MB,而不是几百 MB。
如果你用的是现成镜像,考虑替换基础镜像。
例如将 node:18 换成 node:18-alpine。alpine 版本比标准版小很多,且功能基本一致。
第四步:高频问题解答
Q:docker system prune -a 会不会删掉正在运行的容器使用的镜像?
不会。
Docker 会保留被任何容器(包括停止的容器)引用的镜像和层。
只有完全未被使用的镜像才会被清理。
Q:清理后重新拉取镜像会不会又占大量空间?
会的,但你可以通过配置注册表镜像加速,或者使用 docker pull 时指定 --platform 避免拉取多余架构。
同时,多阶段构建能让后续拉取的基础镜像更小。
Q:如何只清理构建缓存而不动镜像?
使用 docker builder prune。
这个命令只会删除构建过程中生成的缓存层,不会影响已拉取的镜像和运行中的容器。
第五步:验证效果并养成定期维护习惯
再次运行 docker system df,对比第一步记录的数字,你应该能看到明显减少。
为了保持长期清爽,建议:
- 每周运行一次
docker system prune -f(不带-a,只清理悬挂镜像和停止容器)。 - 每月运行一次带
-a的清理。 - 写 Dockerfile 时优先用 alpine 或 slim 版本,并采用多阶段构建。
- 使用
docker image prune -a或docker system df监控磁盘。
如果你正在处理 Docker 容器镜像瘦身,减少磁盘占用,建议先按本文步骤完整执行,再根据自己的环境做微调;
遇到异常时优先回看避坑和高频问题部分。