Dockerfile 最佳实践之善用 ADD/COPY 来加快 Build

好久没有练习 Docker 技术了,最近一个项目重新使我用起了这项技术,并且在之前的基础上有了一个小的认知提升,那就是「善用 ADD/COPY 来加快 Build」。

之前对 Docker Build Image 有一个误区,总以为 Dockerfile 写得越简洁越干净越好,哪知这会造成意外的后果。拿我的 Python Web App 来说吧,有一步是从用 pip 从 requirements.txt 安装软件包,相信用 Python 的朋友都有经历。于是我是这样写 Dockerfile 的:

COPY . /src/
RUN pip install --requirement /src/requirements.txt

乍看好像没啥问题,把当前目录的所有文件复制到 /src 目录下,复制完毕后再通过 RUN 来安装对应的软件包。

但是这里有一个严重的问题:没有充分的利用 Docker 的 Cache 机制,导致只要当前目录有任何一个小改动,不管 requirements.txt 有没有变化都使会 Build Image 的过程中都完整地跑一遍 pip install 的过程,非常消耗时间…

那么这个问题可以解决吗?那就是要理解 Docker 的 Build Image 原理了。Docker 在编译生成最终 Image 的过程中,Dockerfile 里的每一行都会对应的一个 Intermediate Image,或者更通俗的说:Cache 机制。这个机制会根据具体的指令来决定是使用 Cache,还是判断 Cache 失效,重新生成新的 Intermediate Image。

对 ADD 和 COPY 指令来说,一切都比较容易理解了,如果文件产生了变化,那么 Cache 就失效了,然后之后的 Intermediate Image 都需要重新 Build 了。

所以上面的例子要怎么改才能充分利用 Docker 的 Cache 机制?只需要新增一行并调整顺序:

COPY requirements.txt /src/
RUN pip install --requirement /src/requirements.txt
COPY . /src/
  1. 先复制 requirements.txt 到 /src/ 目录,产生一个 Intermediate Image;
  2. pip install 相关软件包,产生一个 Intermediate Image;
  3. 复制全部代码至 /src/ 目录,产生一个 Intermediate Image。

看起来比之前多了一步,但是好处是利用了 Cache,往后,只要 requirements.txt 的内容不发生变化,重新 Build Image 的时候,将会直接跳过前两步,直接进行第三步了——因为前两步检查 Cache 的结果是依然有效。

这样,尽管 Dockerfile 多了一行,却省了很多时间。

这个最新实践是写在官方文档 Best practices for Dockfiles 里面的 Build Cache 那一节的。官方文档真是要好好读啊。

直观的 AI 翻译 一触即达

PopTranslate

您的 Mac 个人 AI 翻译助手 点击弹出 + 轻松实现多种语言的翻译、改写和学习。

2 Comments

tualatrix

经 @ibigbug 告之,可以用 ONBUILD 指令,我去学习一下!

https://twitter.com/ibigbug/status/1009427668910014464

gavin

RUN pip install --requirement /src/requirements.txt -i https://pypi.douban.com/simple

可以用国内镜像,速度杠杠滴

Leave a Comment