I did some searching but it seems that the docker
CLI currently just does not offer any straight forward way to do this. The closest thing is the idea I proposed in my comment: Build the main image and tag all intermediate images afterwards.
Take this Dockerfile
as an example:
FROM alpine AS frontend
RUN sleep 15 && touch /frontend
FROM alpine AS backend
RUN sleep 15 && touch /backend
FROM alpine AS runtime
COPY --from=frontend /frontend /frontend
COPY --from=backend /backend /backend
(the sleep
s are only there to make the speedup by caching obvious)
Building this with:
export DOCKER_BUILDKIT=1 # enable buildkit for parallel builds
docker build -t my-project .
docker build -t my-project-backend --target backend .
docker build -t my-project-frontend --target frontend .
will
- build the main image
runtime
by first building all required intermediate images, e.g. frontend
and backend
, and tag only the main image with my-project
- build the target
backend
tagged as my-project-backend
but using the cache from the previous build
- same but for
backend
Every image here will only be built once - but ultimately this is the very same you already did as stated in your question, just in a different order.
If you really want to be able to do this in a single command you could use docker-compose
to build the "multiple images":
version: "3.8"
services:
my-project:
image: my-project
build: .
backend:
image: my-project-backend
build:
context: .
target: backend
frontend:
image: my-project-frontend
build:
context: .
target: frontend
export DOCKER_BUILDKIT=1 # enable buildkit for parallel builds
export COMPOSE_DOCKER_CLI_BUILD=1 # use docker cli for building
docker-compose build
Here docker-compose
will basically run the same docker build
commands as above for you.
In both cases though you should be aware that although the cached layers massively speed up the build there is still a new build taking place which will each time:
- send the build context - i.e. content of the current directory - to the docker daemon
- download any remote files you
ADD
to the image
and only use the cache if the contents are the same again - which for large files/slow network will be a noticeable slow down.
Another workaround I found in this forum thread was to add a LABEL
to the image and use docker image ls --filter
to get the image IDs after the build.
But testing this it seems docker image ls
won't show intermediate images when using buildkit
. Also this approach would required more commands / a dedicated script - which would be again more work than your current approach.