Docker 镜像瘦身实战:从 1.2G 到 180M

举报
yd_226584033 发表于 2026/10/24 09:44:13 2026/10/24
【摘要】 镜像 1.2G 推送要等几分钟?本文按实际收益排序讲 Docker 瘦身:换 slim 基础镜像、加 .dockerignore、--no-cache-dir 与同层删除、多阶段构建,并解释为什么「最后加一条 rm -rf」不会减小体积。

# Docker 镜像瘦身实战:从 1.2G 到 180M

## 前言

第一次把项目打包成 Docker 镜像,看到 `docker images` 里那个 1.2G 的数字时,我以为自己看错了——一个只有几千行代码的 Python 服务,怎么会有 1.2G?

推送到服务器时这个问题被放大:内网上传还好,一旦走公网,每次发布都要等几分钟,CI 流水线的绝大部分时间都耗在传输上。更麻烦的是容器启动也慢,回滚时尤其明显。

后来我把镜像压到了 180M,整个构建推送流程从几分钟降到十几秒。本文记录具体是怎么做的,以及哪些操作有效、哪些是无效努力。

## 一、先看镜像是怎么胖起来的

用一条命令就能看清:

```bash
docker history your-image:tag
```

它会列出每一层镜像的体积。我当时的输出大致是这样:基础镜像 `python:3.11` 占了 900 多 M,装依赖又加了 200 多 M,最后是代码本身几十 M。

问题就在这里:**我用的是完整版 Python 镜像**,里面带了完整的编译工具链、文档、包管理器的缓存,而这些东西运行时一个都用不到。

## 二、换基础镜像(效果最明显)

最立竿见影的一步,把:

```dockerfile
FROM python:3.11
```

换成:

```dockerfile
FROM python:3.11-slim
```

`slim` 版本删掉了编译工具、文档和多语言支持,只保留运行 Python 必需的内容。我的镜像从 1.2G 直接降到 400M 左右,**一行改动省了 800M**。

如果对体积还要更极致,可以用 `alpine` 版本,但要注意:`alpine` 用的是 musl libc,某些带 C 扩展的包(比如 `psycopg2`、`lxml`)可能装不上或需要额外编译,处理起来比重写 Dockerfile 还麻烦。我的建议是**先上 slim,够用就停**。

## 三、清理包管理器缓存(别让缓存白占空间)

在装依赖的同一层里清理,这一点很关键:

```dockerfile
RUN pip install --no-cache-dir -r requirements.txt
```

`--no-cache-dir` 让 pip 不保存下载缓存。如果用的是 apt:

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    && rm -rf /var/lib/apt/lists/*
```

注意 `rm -rf /var/lib/apt/lists/*` 必须和 `apt-get install` 写在**同一个 RUN 指令**里。Docker 的镜像是分层的,如果分成两行,第一层已经写入的缓存文件在第二层删除时只是被标记为删除,实际体积不会减少。

`--no-install-recommends` 也很重要,它会跳过"推荐但非必需"的依赖包,通常能少装一堆用不到的东西。

## 四、用 .dockerignore 挡住垃圾文件

很多人忽略了这一步。没有 `.dockerignore` 时,`COPY . /app` 会把整个项目目录都塞进镜像:`.git` 目录(可能几百 M)、本地虚拟环境、`__pycache__`、日志文件、测试用的大文件……

一个最小可用的配置:

```
.git
.gitignore
__pycache__
*.pyc
.venv
venv
.env
node_modules
*.log
.pytest_cache
```

我的项目里 `.git` 就占了 70 多 M,加上本地虚拟环境,这一刀下去又省了 100 多 M。

## 五、多阶段构建(编译型项目效果显著)

如果你的项目需要编译(Go、前端构建、Python 的 C 扩展),多阶段构建是标准做法:

```dockerfile
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt

FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/*
COPY . .
CMD ["python", "main.py"]
```

第一个阶段负责编译,产出 wheels;第二个阶段只取编译结果,编译器、中间产物全部丢弃。对纯 Python 项目收益有限,对 Go 项目效果惊人——Go 编译出来的二进制配上 `scratch` 基础镜像,最终镜像可以只有十几 M。

## 六、一个容易踩的坑

我一开始就试过在 Dockerfile 最后加一条 `RUN rm -rf /root/.cache` 来清理,结果镜像体积一点没变。原因前面提过:删除发生在新的层,旧层里的数据还在镜像里躺着。

**记住这条原则:在同一个 RUN 里创建,就在同一个 RUN 里删除。**

至于"合并 RUN 减少层数",现在的 Docker 对层数已经优化得很好,不必为了合并而合并——可读性更重要。

## 小结

按我的收益排序:

1. 换 `slim` 基础镜像 —— 一行,省 60%+
2. 加 `.dockerignore` —— 挡掉 .git、虚拟环境
3. `--no-cache-dir` 和清理 apt 缓存(同层删除)
4. 多阶段构建 —— 编译型项目必做

镜像体积最终从 1.2G 降到 180M,推送时间从几分钟到十几秒。这些改动没有任何一个是"高级技巧",但组合起来的收益很实在,而且全程不到半小时。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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