9

I'm getting some weird behavior from Docker and I can't find it mentioned anywhere. It is skipping stages seemingly at random, even with multi-stage Dockerfiles that I've simply copy-pasted from forums around the net.

My dockerfile is:

FROM alpine as base
RUN echo "1"

# SKIPPED
FROM base as mid
RUN echo "2"

FROM base as final
RUN echo "3"

OUTPUT:

docker build -t test .\ --no-cache
[+] Building 2.0s (7/7) FINISHED
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 34B                                                                                   0.0s
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 143B                                                                               0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                   1.3s
 => CACHED [base 1/2] FROM docker.io/library/alpine@sha256:...  0.0s
 => [base 2/2] RUN echo "1"                                                                                        0.3s
 => [final 1/1] RUN echo "3"                                                                                       0.4s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:...                      0.0s
 => => naming to docker.io/library/...                                                                 0.0s

What causes this?

Eduard G
  • 443
  • 5
  • 21

1 Answers1

17

Buildkit uses a dependency graph. It looks at the target stage, which by default is the last one:

FROM base as final
RUN echo "3"

From there it sees that base is needed to build this stage so it pulls in the base stage:

FROM alpine as base
RUN echo "1"

And from there it's done, it's not needed to build the mid stage to create your target image. There's no dependencies in the FROM or a COPY --from that would require it. This behavior differs from the classic docker build which performed steps in order until the target stage was reached, and is one of the reasons buildkit is much faster.

BMitch
  • 231,797
  • 42
  • 475
  • 450
  • Ah, I see. Out of curiosity, is there a way to force it to go through every stage? – Eduard G Dec 10 '20 at 14:41
  • 1
    You can add an explicit dependency, copy something from the stage you want to run to the stage you build. – BMitch Dec 10 '20 at 14:45
  • For me, setting DOCKER_BUILDKIT environment variable to 0 allowed it to run all steps. Of course, you lose the benefits of buildkit so it's something you have to weigh up. – Lewis Marhin Feb 23 '21 at 22:39