У меня какое-то странное поведение от Docker, и я нигде не могу найти упоминания об этом. Кажется, что этапы пропускаются случайным образом, даже с многоэтапными файлами Dockerfile, которые я просто скопировал и вставил с форумов в сети.
Мой докерфайл:
FROM alpine as base
RUN echo "1"
# SKIPPED
FROM base as mid
RUN echo "2"
FROM base as final
RUN echo "3"
ВЫХОД:
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
Что вызывает это?
Buildkit использует граф зависимостей. Он смотрит на целевой этап, который по умолчанию является последним:
FROM base as final
RUN echo "3"
Отсюда он видит, что base
необходим для построения этого этапа, поэтому он извлекает базовый этап:
FROM alpine as base
RUN echo "1"
И после этого все готово, нет необходимости создавать промежуточную стадию для создания целевого образа. В FROM
или COPY --from
нет зависимостей, которые потребовали бы этого. Это поведение отличается от классической сборки Docker, которая выполняла шаги по порядку, пока не была достигнута целевая стадия, и является одной из причин, по которой buildkit работает намного быстрее.
Вы можете добавить явную зависимость, скопировать что-то из этапа, который вы хотите запустить, в этап, который вы создаете.
Для меня установка переменной среды DOCKER_BUILDKIT на 0 позволила выполнить все шаги. Конечно, вы теряете преимущества buildkit, так что вам придется это взвесить.
Ах я вижу. Из любопытства, есть ли способ заставить его пройти все этапы?