Docker镜像构建缓存未命中问题:CI/CD中如何复用远程镜像层?
问题:复用远程Docker镜像层缓存失败
我正尝试提升CI/CD流程的速度,其中一个步骤是构建Docker镜像。镜像构建完成后我会将其推送到镜像仓库,以便在后续CI/CD迭代中先拉取该镜像,复用Docker构建镜像的层缓存,从而减少构建耗时——按预期,若前面的Dockerfile指令未变更,Docker不应重复执行相同的镜像层构建步骤。
以下是实际测试示例:
目录结构
ls Dockerfile somefile.txt
Dockerfile内容
cat Dockerfile FROM ruby:2.7.4-slim ENTRYPOINT irb
首次构建
docker build -t my-registry/my-docker-cache . Sending build context to Docker daemon 2.56kB Step 1/2 : FROM ruby:2.7.4-slim ---> db4073acbaac Step 2/2 : ENTRYPOINT irb ---> Running in 14055ed3e5d1 Removing intermediate container 14055ed3e5d1 ---> f4f317dde34d Successfully built f4f317dde34d Successfully tagged my-registry/my-docker-cache:latest
一切符合预期:无缓存,所有步骤均执行。
本地重复构建
docker build -t my-registry/my-docker-cache . Sending build context to Docker daemon 2.56kB Step 1/2 : FROM ruby:2.7.4-slim ---> db4073acbaac Step 2/2 : ENTRYPOINT irb ---> Using cache ---> f4f317dde34d Successfully built f4f317dde34d Successfully tagged my-registry/my-docker-cache:latest
结果符合预期:步骤2显示Using cache,未重复执行。
推送镜像到仓库
docker push my-registry/my-docker-cache aaf6670012a0: Mounted from previous-image-in-other-experiments e21a639a3286: Mounted from previous-image-in-other-experiments f01aae87d116: Mounted from previous-image-in-other-experiments 04f100f96a69: Mounted from previous-image-in-other-experiments e1bbcf243d0e: Mounted from previous-image-in-other-experiments latest: digest: sha256:317cbcbb751fc90e3656818a7942ddd67fb8cb9c24841f57cce272bc47c02ce5 size: 1366
删除本地镜像并拉取远程镜像
docker rmi my-registry/my-docker-cache Untagged: my-registry/my-docker-cache:latest Untagged: my-registry/my-docker-cache@sha256:317cbcbb751fc90e3656818a7942ddd67fb8cb9c24841f57cce272bc47c02ce5 Deleted: sha256:f4f317dde34ddba589867c3d81af9cd6fe30732afc0173a53740c271d2b70ed3
docker pull my-registry/my-docker-cache Using default tag: latest latest: Pulling from my-docker-cache eff15d958d66: Already exists 923e91ae3a1b: Already exists 2aa5d3a4a151: Already exists bc64adf2d0b2: Already exists bfc5cca7d80e: Already exists Digest: sha256:317cbcbb751fc90e3656818a7942ddd67fb8cb9c24841f57cce272bc47c02ce5 Status: Downloaded newer image for my-registry/my-docker-cache:latest my-registry/my-docker-cache:latest
再次构建(未复用缓存)
docker build -t my-registry/my-docker-cache . Sending build context to Docker daemon 2.56kB Step 1/2 : FROM ruby:2.7.4-slim ---> db4073acbaac Step 2/2 : ENTRYPOINT irb ---> Running in b779e2e702bf Removing intermediate container b779e2e702bf ---> 73464e25f559 Successfully built 73464e25f559 Successfully tagged my-registry/my-docker-cache:latest
我原本预期步骤2会显示Using cache并不执行,但实际却重新执行了该步骤。虽然ENTRYPOINT步骤耗时很短,但对于RUN bundle install或RUN apt update; apt install xxx这类耗时步骤,影响会很大。
请问我哪里操作有误?或者该如何实现复用远程镜像层缓存的目标?
附Docker版本信息:
docker version Client: Docker Engine - Community Cloud integration: v1.0.28 Version: 20.10.17 API version: 1.41 Go version: go1.17.11 Git commit: 100c701 Built: Mon Jun 6 23:02:57 2022 OS/Arch: linux/amd64 Context: desktop-linux Experimental: true Server: Docker Desktop 4.11.0 (83626) Engine: Version: 20.10.17 API version: 1.41 (minimum version 1.12) Go version: go1.17.11 Git commit: a89b842 Built: Mon Jun 6 23:01:23 2022 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.6 GitCommit: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1 runc: Version: 1.1.2 GitCommit: v1.1.2-0-ga916309 docker-init: Version: 0.19.0 GitCommit: de40ad0
解决方案
原因分析
Docker默认只会优先使用本地镜像的层缓存,拉取远程镜像后,虽然镜像存在,但Docker不会自动将其作为构建缓存的来源。构建缓存是基于本地镜像的层哈希匹配,远程拉取的镜像对应的构建上下文和层关联信息不会被Docker自动识别为可用缓存。
解决方法
要复用远程镜像的层缓存,需要在docker build命令中添加--cache-from参数,指定远程镜像作为缓存源:
docker build --cache-from my-registry/my-docker-cache -t my-registry/my-docker-cache .
这个参数会告诉Docker:先检查指定的远程(或本地)镜像是否包含可复用的层,只要Dockerfile指令和之前一致,就会直接复用该镜像中的对应层,无需重新构建。
补充说明
- 在CI/CD流程中,建议先拉取目标镜像(即使不存在也不会报错),再执行带
--cache-from的构建命令,确保缓存源存在。 - 对于多阶段构建,可以为每个阶段分别指定
--cache-from,比如--cache-from my-registry/my-image:stage1 --cache-from my-registry/my-image:latest,进一步提升缓存复用率。 - 如果使用Docker Buildx(推荐在CI/CD中使用),可以通过
--cache-to和--cache-from配合,将缓存推送到远程仓库,实现跨环境的缓存共享,命令示例:docker buildx build \ --cache-from type=registry,ref=my-registry/my-docker-cache:cache \ --cache-to type=registry,ref=my-registry/my-docker-cache:cache,mode=max \ -t my-registry/my-docker-cache . \ --push
内容的提问来源于stack exchange,提问作者Montells
相关产品推荐
相关产品推荐

