65

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:

enter image description here

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 my docker 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:

  • One can use ARG to pass a build id from CI/CD to Dockerfile builder
  • Then one can use LABEL syntax to add build id metadata to the stage images being built
  • Then one can use the --filter option of docker image prune command to remove only the images with the current build id

This 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?

d4nyll
  • 11,811
  • 6
  • 54
  • 68
Andrew Savinykh
  • 25,351
  • 17
  • 103
  • 158
  • 1
    have you ever tried this for cleaning the dangled images:- `docker rmi $(docker images -f "dangling=true" -q)` – kakabali May 02 '18 at 04:59
  • @kakabali yes and it worked. Not helping with the problem at hand though. – Andrew Savinykh May 02 '18 at 05:00
  • oops sorry for that :-( . may be having a separate area(another docker image having docker installed inside itself) where you can push and image to the registry and then remove this container/ image after things have finished – kakabali May 02 '18 at 05:14
  • @kakabali docker in docker does not work well, this is a know fact many discovered from experience and docker developers do not recommend using it explicitly. There are many subtle issues. Google about it if you are interested. – Andrew Savinykh May 02 '18 at 05:18
  • 1
    @AndrewSavinykh what is interesting and no one mentions, after restarting the system these "dangling" images disappear from 'docker images' – Rodion May 03 '18 at 22:55

7 Answers7

71

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

For Automation Servers (e.g. Jenkins)

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

  1. Set a unique build ID as an environment variable inside your Jenkins build
  2. Add an ARG instruction for this build ID inside your Dockerfile
  3. Pass the build ID to docker build through the --build-arg flag
FROM 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
...
d4nyll
  • 11,811
  • 6
  • 54
  • 68
  • @AndrewSavinykh Perhaps you can set a unique build ID as an environment variable inside your Jenkins build, add it to the image using `ENV`, and use [environment replacement](https://docs.docker.com/engine/reference/builder/#environment-replacement) to use that build ID as the label value – d4nyll Mar 10 '19 at 01:31
  • Yes you'd need to modify the `Dockerfile` to include the `ENV` and `LABEL` instructions. I am not sure why this is a complex procedure, would you mind clarifying? – d4nyll Mar 10 '19 at 13:10
  • A `LABEL` instruction is not going to interfere with your build process. The label is purely metadata that the `docker` daemon uses. Nothing 'inside' the image itself gets changed. I'd advise you to read the documentation more closely, as this is precisely what the `LABEL` instructure is made for. If you find yourself implement your own `Dockerfile` parser, you are over-complicating things. – d4nyll Mar 10 '19 at 20:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189780/discussion-between-andrew-savinykh-and-d4nyll). – Andrew Savinykh Mar 10 '19 at 21:03
5

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.

Nick Chadwick
  • 51
  • 1
  • 1
2

You can run docker build inserting another param wich will remove automatically the intermediate images:

docker build --force-rm -t myimage .
  • 3
    This question is about [multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/) and removing images from this particular type of build. Your suggestion does not solve it. Did you try it yourself before proposing? – Andrew Savinykh Feb 11 '21 at 01:55
2

The easy way is to run the cmd docker rmi -f $(docker images -f "dangling=true" -q)

idirall22
  • 316
  • 2
  • 11
  • 1
    An even easier way is to run `docker image prune` since it cleans up only dangling images by default. https://docs.docker.com/config/pruning/ – Tim Nov 23 '21 at 17:16
  • 2
    The question explains in great details, why this is not an answer we are looking for. Have you read the entire question? – Andrew Savinykh Dec 24 '21 at 21:16
1

A little late, but the best option is

docker builder prune -a

enter image description here

dariogriffo
  • 4,148
  • 3
  • 17
  • 34
  • 2
    That does not remove images **from a single particular build only** as bolded in the question. – Andrew Savinykh Apr 29 '22 at 23:42
  • 1
    After upgrading to the latest docker version, builder cache no longer appears as images. I found this to be the only way to remove intermediate "images" and free up disk space. (docker image ls only shows about 5GB total usage, and docker builder prune cleaned up 17GB intermediate builder cache for me, which previously can be cleaned by docker image rm.) – msg7086 Feb 11 '23 at 21:36
-3

If you do not want to use the cache at all, you can use the --no-cache=true option on the docker build command

Leverage build cache

  • 4
    This question is about [multi-stage build](https://docs.docker.com/develop/develop-images/multistage-build/) and removing images from this particular type of build. Your suggestion does not solve it. Did you try it yourself before proposing? – Andrew Savinykh Mar 23 '20 at 21:10
  • You are right, but then subject is wrong and google leads to this answer in stackoverflow. So not useful – user13109090 Mar 25 '20 at 05:52
-5

Please use the below command for deleting all intermediate images:

docker rmi $(docker images -a|grep "<none>"|awk '$1=="<none>" {print $3}')
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 09 '22 at 09:21
  • Briefly describe what your command does and if there may be any side effects. – jMike Apr 15 '22 at 09:40