You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多阶段Dockerfile如何实现全阶段构建缓存的充分复用

Docker多阶段构建Buildkit中间阶段缓存复用问题

现有配置

Dockerfile

FROM debian:10 as builder
RUN sleep 10
COPY input input
# worlds most trivial build pipeline
RUN cat input > artifact

FROM debian:10
COPY --from=builder artifact artifact
RUN cat artifact
COPY input2 input2

docker-compose配置文件

%YAML 1.1
---
version: '3.7'
services:
  sdn-controller:
    build:
      context: .
      cache_from:
      - hansbogert/test1:latest
      args:
      - BUILDKIT_INLINE_CACHE=1
    image: hansbogert/test1:latest

初始化操作

创建两个空文件:

$ touch input input2

初始构建并推送镜像:

export DOCKER_BUILDKIT=1 
docker-compose build 
docker-compose push

测试场景

场景1:清空本地缓存后重新构建

操作:

docker rmi hansbogert/test1 ; docker image prune -f; docker builder prune -af
docker-compose build 

结果:所有步骤均命中缓存,符合预期。

场景2:修改input2后清空缓存重新构建

操作:

$ echo 1 > input2
$ docker rmi hansbogert/test1 ; docker image prune -f; docker builder prune -af
$ docker-compose build 

结果:仅COPY input2之后的步骤重新执行,符合预期,截断输出如下:

=> CACHED [stage-1 3/4] RUN cat artifact                                                                                            0.7s
 => => pulling sha256:f33c84f9d3c6505acdda2a6d1c7238c853e07f3723e4a5d4c9eb65a163710ffd                                               0.3s
 => => pulling sha256:0b00a0a96175fa32a06c3741ac1fb655aafc2ed1584eebfd2e213561998f7bea                                               0.4s
=> [stage-1 4/4] COPY input2 input2                                                                                                 0.0s
=> exporting to image                                                                                                           
...

场景3:修改input后清空缓存重新构建

操作:

$ echo 1 > input
$ docker rmi hansbogert/test1 ; docker image prune -f; docker builder prune -af
$ docker-compose build 

结果:builder阶段的RUN sleep 10步骤未命中缓存,整个builder阶段全部重新执行,不符合预期,截断输出如下:

=> [internal] load build definition from Dockerfile                                                                                 0.0s
=> => transferring dockerfile: 254B                                                                                                 0.0s
=> [internal] load .dockerignore                                                                                                    0.1s
=> => transferring context: 2B                                                                                                      0.0s
=> [internal] load metadata for docker.io/library/debian:10                                                                         0.0s
=> importing cache manifest from hansbogert/test1:latest                                                                            1.3s
=> [builder 1/4] FROM docker.io/library/debian:10                                                                                   0.1s
=> [internal] load build context                                                                                                    0.0s
=> => transferring context: 71B                                                                                                     0.0s
=> [builder 2/4] RUN sleep 10                                                                                                      10.5s
=> [builder 3/4] COPY input input                                                                                                   0.1s
=> [builder 4/4] RUN echo input > artifact                                                                                          0.6s
=> CACHED [stage-1 2/4] COPY --from=builder artifact artifact                                                                       0.0s

核心问题

是否有方案可以让最终镜像之外的构建阶段也能正常复用缓存?


解决方案

问题原因

默认的BUILDKIT_INLINE_CACHE仅会将最终镜像的层缓存内嵌到推送的镜像中,多阶段构建的中间阶段(如本案例中的builder阶段)的层不会被包含在内,因此修改input文件后,builder阶段的所有前置步骤无法命中远端缓存,只能重新执行。

方案1:单独推送中间阶段镜像

新增对应builder阶段的构建配置,将中间阶段的镜像单独推送到镜像仓库,主服务的缓存源同时添加最终镜像和中间阶段镜像即可:
修改后的docker-compose配置:

version: '3.7'
services:
  # builder阶段专属镜像服务
  sdn-controller-builder:
    build:
      context: .
      target: builder # 指定仅构建到builder阶段
      cache_from:
        - hansbogert/test1-builder:latest
      args:
        - BUILDKIT_INLINE_CACHE=1
    image: hansbogert/test1-builder:latest

  sdn-controller:
    build:
      context: .
      cache_from:
        - hansbogert/test1:latest
        - hansbogert/test1-builder:latest # 新增中间阶段镜像作为缓存源
      args:
        - BUILDKIT_INLINE_CACHE=1
    image: hansbogert/test1:latest
    depends_on:
      - sdn-controller-builder

构建执行顺序:

export DOCKER_BUILDKIT=1
# 先构建推送中间阶段镜像
docker-compose build sdn-controller-builder
docker-compose push sdn-controller-builder
# 再构建推送最终镜像
docker-compose build sdn-controller
docker-compose push sdn-controller

该方案无需额外依赖,适合阶段较少的多阶段构建场景。

方案2:使用Buildkit全阶段缓存导出

使用Buildkit原生支持的缓存导出模式,指定mode=max即可导出所有构建阶段的缓存,无需单独维护中间镜像,适合复杂多阶段构建场景:

直接使用docker buildx命令示例

docker buildx build \
  --push \
  -t hansbogert/test1:latest \
  --cache-to=type=registry,ref=hansbogert/test1-cache:latest,mode=max \
  --cache-from=type=registry,ref=hansbogert/test1-cache:latest \
  .

docker-compose配置示例(需compose v2及以上版本支持)

services:
  sdn-controller:
    build:
      context: .
      cache_from:
        - type=registry,ref=hansbogert/test1-cache:latest
      cache_to:
        - type=registry,ref=hansbogert/test1-cache:latest,mode=max
    image: hansbogert/test1:latest

验证效果

修改input文件后重新构建,可观察到[builder 2/4] RUN sleep 10步骤标记为CACHED,仅COPY input之后的步骤重新执行,符合预期。


内容的提问来源于stack exchange,提问作者hbogert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 14:45:04