打包通常很慢,Docker构建镜像也一样。docker构建时需要下载和安装系统和Python软件包,编译C扩展,构建资源
为了加快构建速度,Docker实施了缓存:如果你的Dockerfile文件和相关文件未更改,再次构建可以重用本地图像缓存中的某些现有层。
但是,为了利用此缓存,你需要了解它的工作方式,这就是我们将在本文中介绍的内容。
基本规则
构建时Dockerfile,Docker将查看它是否可以使用先前构建的缓存结果:
- 对于大多数命令,如果
命令文本未更改
,则将使用缓存中的版本。 - 对于COPY,如果
复制的文件未更改
,则将使用缓存中的版本。
让我们来看一个使用以下示例Dockerfile:
FROM python:3.7-slim-buster
COPY . .
RUN pip install --quiet -r requirements.txt
ENTRYPOINT ["python", "server.py"]
第一次运行时,所有命令都会运行:
$ docker build -t example1 .
Sending build context to Docker daemon 5.12kB
Step 1/4 : FROM python:3.7-slim-buster
---> f96c28b7013f
Step 2/4 : COPY . .
---> eff791eb839d
Step 3/4 : RUN pip install --quiet -r requirements.txt
---> Running in 591f97f47b6e
Removing intermediate container 591f97f47b6e
---> 02c7cf5a3d9a
Step 4/4 : ENTRYPOINT ["python", "server.py"]
---> Running in e3cf483c3381
Removing intermediate container e3cf483c3381
---> 598b0340cc90
Successfully built 598b0340cc90
Successfully tagged example1:latest
但是,由于没有任何更改,第二次docker build将使用图像缓存:
$ docker build -t example1 .
Sending build context to Docker daemon 5.12kB
Step 1/4 : FROM python:3.7-slim-buster
---> f96c28b7013f
Step 2/4 : COPY . .
---> Using cache <--注意这里
---> eff791eb839d
Step 3/4 : RUN pip install --quiet -r requirements.txt
---> Using cache <--注意这里
---> 02c7cf5a3d9a
Step 4/4 : ENTRYPOINT ["python", "server.py"]
---> Using cache <--注意这里
---> 598b0340cc90
Successfully built 598b0340cc90
Successfully tagged example1:latest
Using cache
这是构建速度更快的结果,无需从网络下载任何软件包pip install即可使用。
如果我们从本地缓存中删除映像,则后续构建将从头开始,因为Docker无法使用不存在的层:
$ docker image rm example1
Untagged: example1:latest
Deleted: sha256:598b0340cc90967501c5c51862dc586ca69a01ca465f48232fc457d3ab122a73
Deleted: sha256:02c7cf5a3d9af1939b9f5286312b23898fd3ea12b7cb1d7a77251251740a806c
Deleted: sha256:d9e9602d9c3fd7381a8e1de301dc4345be2eb2b8488b5fc3e190eaacbb2f9596
Deleted: sha256:eff791eb839d00cbf46d139d8595b23867bc580bb9164b90253d0b2d9fcca236
Deleted: sha256:53d34b2ead0a465d229a4260fee2a845fb8551856d4019cd2e608dfe0e039e77
$ docker build -t example1 .
Sending build context to Docker daemon 5.12kB
Step 1/4 : FROM python:3.7-slim-buster
---> f96c28b7013f
Step 2/4 : COPY . .
---> 63c32b9b1af6
...
如何利用缓存
缓存算法还有一个更重要的规则:
如果无法将缓存用于特定的层,则不会从缓存中加载所有后续层。
在以下示例中,C层在新旧Dockerfiles 之间都没有改变。但是,由于无法从缓存中加载上一层(B_CHANGED),因此仍然无法从缓存中加载:
让我们考虑一下这意味着什么Dockerfile:
FROM python:3.7-slim-buster
COPY requirements.txt .
COPY server.py .
RUN pip install --quiet -r requirements.txt
ENTRYPOINT ["python", "server.py"]
如果我们COPY更改了任何文件,则会使所有以后的层无效:pip install例如,我们需要重新运行。
如果我们的项目代码server.py已更改但requirements.txt没有更改。
我们要做的就是仅复制实际需要运行下一步的那些文件,以最大程度地减少缓存失效的机会。例如:
FROM python:3.7-slim-buster
COPY requirements.txt .
RUN pip install --quiet -r requirements.txt
#先copy requirements.txt ,最后copy项目文件.
COPY server.py .
ENTRYPOINT ["python", "server.py"]
因为server.py仅复制到中pip install,所以创建的图层pip install只要requirements.txt没有更改,仍可以从缓存中加载。
总结
如果你想通过重用以前缓存的版本来进行快速构建,最重要的2个规则:
-
将copy requirements.txt 和 pip install放在项目代码之前可以最大可能的使用到缓存
-
可以观察Using cache来判断是否使用了缓存
最后推荐去看docker官方最佳实践