When you build your multi-stage Dockerfile with
docker build -t myimage .
it produces the final image tagged myimage
, and also intermediate images. To be completely clear we are talking here not about containers, but about images. It looks like this:
See these <none>
images? These are what I'm talking about.
Now this "issue" has been discussed to some extent here and here.
Here are some relevant parts:
If these intermediate images would be purged/pruned automatically, the build cache would be gone with each build, therefore forcing you to rebuild the entire image each time.
So okay, it does not make sense to prune then automatically.
Some people do this:
For now, I'm using
docker image prune -f
after mydocker build -t app .
command to cleanup those intermediate images.
But unfortunately this is not something I can do. As one discussion participant commented:
It removes "all dangling images", so in shared environments (like Jenkins slave) it's more akin to shooting oneself in the foot. :)
And this is a scenario I found myself in.
So nothing to be "fixed" on Docker side. But how can I remove those extra images, from a single particular build only?
Update
After reading very nice answer from d4nyll below, which is a big step forward, I'd like to add some more constraints to the question ;) First, let me sum up the answer:
Dockerfile
builder--filter
option of docker image prune command to remove only the images with the current build idThis is a big step forward, but I'm still struggling into how to fit it into my usage scenario without adding unnecessary complexity.
In my case a requirement is that application developers who author the Dockerfiles and check them into the source control system are responsible for making sure that their Dockerfiles build the image to their satisfaction. They are not required to craft all their Dockerfiles in a specific way, "so our CI/CD process does not break". They simply have to provide a Dockerfile
that produce correct docker image.
Thus, I'm not really in a position to request them to add stuff in the Dockerfile
for every single application, just for the sake of CI/CD pipeline. This is something that CI/CD pipeline is expected to handle all by itself.
The only way I can see making this work is to write a Dockerfile
parser, that will detect multi-staged build and inject a label per stage and then build that modified Dockerfile
. This is a complexity that I'm very hesitant to add to the CI/CD pipeline.
Do I have a better (read simpler) options?
When you build your images add “–rm” this should help with removing any intermediate and none images. [quote]When you build your images add “–rm” this should help with removing any intermediate and none images.
You can remove an image with docker rmi command, passing the name of the image you want to remove. This will remove the image. Sometimes when testing and developing, some images become dangling, which means untagged images. They can always be safely removed to free disk space.
To remove the image, you first need to list all the images to get the Image IDs, Image name and other details. By running simple command docker images -a or docker images . After that you make sure which image want to remove, to do that executing this simple command docker rmi <your-image-id> .
docker image prune removes all dangling images (those with tag none). docker image prune -a would also remove any images that have no container that uses them.
As ZachEddy
and thaJeztah
mentioned in one of the issues you linked to, you can label the intermediate images and docker image prune
those images based on this label.
Dockerfile (using multi-stage builds)
FROM node as builder
LABEL stage=builder
...
FROM node:dubnium-alpine
...
After you've built you image, run:
$ docker image prune --filter label=stage=builder
If you are running the builds in an automation server (e.g. Jenkins), and want to remove only the intermediate images from that build, you can
ARG
instruction for this build ID inside your Dockerfile
docker build
through the --build-arg
flagFROM node as builder
ARG BUILD_ID
LABEL stage=builder
LABEL build=$BUILD_ID
...
FROM node:dubnium-alpine
...
$ docker build --build-arg BUILD_ID .
$ docker image prune --filter label=stage=builder --filter label=build=$BUILD_ID
If you want to persists the build ID in the image (perhaps as a form of documentation accessible within the container), you can add another ENV
instruction that takes the value of the ARG
build argument. This also allows you to use the similar environment replacement to set the label value to the build ID.
FROM node as builder
ARG BUILD_ID
ENV BUILD_ID=$BUILD_ID
LABEL stage=builder
LABEL build=$BUILD_ID
...
FROM node:dubnium-alpine
...
We're doing exactly this, applying labels to the Dockerfile at build-time like this:
sed -i '/^FROM/a\
LABEL build_id=${env.BUILD_TAG}\
' Dockerfile
Probably too late to help the OP, but hopefully this will be useful to someone facing the same problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With