Skip to main content

Command Palette

Search for a command to run...

优化 Dockerfile,缩减镜像尺寸

Updated
3 min read

原文:Refactoring a Dockerfile for image size

Docker 社区最近有一篇关于镜像文件尺寸的文章Docker社区都提倡更小的镜像。下面列出今天 Docker Hub 上的 Top 10 镜像的尺寸( Latest ):

镜像名称尺寸(MB)
busybox1
ubuntu188
swarm17
nginx134
registry423
redis151
mysql360
mongo317
node643
debian125

使用较小的基础镜像(例如 Alphine Linux, BusyBox 等)有很多好处。这方面有不少相关文档:

所以我假设你已经试用了其中的一个为基础镜像。接下来的事情就取决于操作者控制镜像尺寸的能力了。特别的,我们会验证一些缩减镜像大小的手段的效果,例如把多个 RUN 指令中的命令集中到一行,一些关于 apt-get 的技巧(例如移除 apt-get 缓存以及 --no-install-recommends

在同一行中进行清理工作

Docker 镜像的基础是一种层次化文件系统。每一层都只是包含同下面一层不同的部分。在最上方只能看到一个统一视图,而无法获知他的构建历史。Dockerfile 的每一行都会在顶部建立一个新的层。

例如我们以这样一个 Dockerfile 片段开始:

ADD https://storage.googleapis.com/golang/go1.5.3.src.tar.gz /tmp

# do some things with that file

RUN rm /tmp/go1.5.3.src.tar.gz

你可以能会觉得删除 .tar.gz 文件是个负责任的好办法。但是包含这一文件的层还遗留在镜像之中。rm 操作只是对最终镜像隐藏了这一文件,使用 docker pull 获取这一镜像时还是会下载这些内容的。

更好的办法就是把这些操作集中到一行之中,这样就不会提交多个层了。例如,对上面的指令进行简单的改写:

RUN curl -o \
        /tmp/go.1.5.3.src.tar.gz \
        https://storage.googleapis.com/golang/go1.5.3.src.tar.gz && \
      <do some things with the file> && \
      rm /tmp/go1.5.3.src.tar.gz

这样看起来有点丑,不过能够优化镜像尺寸。如果你讨厌这种写法,可以建立一个脚本,然后用 ADDRUN 来在 Dokerfile 中运行。

用正确的方式移除 apt/yum 缓存

多数 Dockerfile 作者都知道应该 apt-get remove 所有不必要的包。一个例子就是,用 curl/wget 来进行下载安装其他软件。可以事后使用 apt-get remove curl,但是同上面的例子一样,curl 所在的层已经被封装到镜像之中,因此也应该把删除(包括相关的自动安装的依赖包)工作放到同一行中。


一个实际的例子。

这是一个简化版本的用于运行 Python 服务的 Dokerfile,我们将对他进行优化。

FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl python-pip

RUN pip install requests

ADD ./my_service.py /my_service.py
ENTRYPOINT ["python", "/my_service.py"]

myservice.py 是一个 Python 脚本:

#!/usr/bin/python
print 'Hello, world!'

接下来 build 并检查尺寸:

$ sudo docker build -t size . $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE size latest da8a9be731ac 4 seconds ago 360.5 MB ubuntu 14.04 6cc0fc2a5ee3 2 weeks ago 187.9 MB

188 MB 的基础镜像已经很吓人了,不过更值得注意的是,只是一个 hello-world 的 Python 脚本为什么会导致镜像尺寸倍增。这 360.5 MB 中到底有什么?其中包含了最上一层(本例中是 da8a9be731ac),以及用于建立顶层的所有的层的内容。

添加一个清理层

我们也许应该做一些清理工作,我们试试这样的 Dockerfile :

FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl python-pip

RUN pip install requests

## Clean up
RUN apt-get remove -y python-pip curl
RUN rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT ["python", "/my_service.py"]

Build,然后再看尺寸:

$ sudo docker build -t size . $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE size latest c6dacdd00660 2 seconds ago 361.3 MB ubuntu 14.04 6cc0fc2a5ee3 2 weeks ago 187.9 MB

事与愿违,镜像更大了。

在同一层进行清理

接下来试试把 APT 操作进行合并:

FROM ubuntu:14.04
RUN apt-get update && \
    apt-get install -y curl python-pip && \
    pip install requests && \
    apt-get remove -y python-pip curl && \
    rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT ["python", "/my_service.py"]

Build 然后查看镜像:

$ sudo docker build -t size . $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE size latest e531f8674f33 9 seconds ago 338 MB ubuntu 14.04 6cc0fc2a5ee3 2 weeks ago 187.9 MB

果然小了一点点 —— 只是一点点。

进一步优化 APT

apt-get install 过程中加入了很多 推荐 内容。推荐包只是简单的加入了一些可有可无的依赖。有些用户会因为特殊的应用方式,或者环境要求才需要这些东西,换句话说,这些推荐内容并非必要。

在 Ubuntu 14.04 中运行 PIP,很容易就可以得出结论:删除推荐包并不会有什么副作用。这一点在产品发布之前是完全可以确认的。可以在 Docker Hub 上看看 redismysqlmongopostgreselasticsearch 等的镜像,使用这一技巧来缩减镜像尺寸。

实际操作一下带有 --no-install-recommends 选项的 APT-GET:

FROM ubuntu:14.04
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl python-pip && \
    pip install requests && \
    apt-get remove -y python-pip curl && \
    rm -rf /var/lib/apt/lists/*

ADD ./my_service.py /my_service.py
ENTRYPOINT ["python", "/my_service.py"]

Build,再次检查尺寸:

REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE size latest fddc30aee4dc 6 seconds ago 229.2 MB ubuntu 14.04 6cc0fc2a5ee3 2 weeks ago 187.9 MB

这次我们把镜像缩小了 120 MB。


Dockerfile 的语法非常简单,也同样有优化的需求,因此在组织中应用 Docker 时,需要为 Dockerfile 建立健全相应的策略来优化这一过程。

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts