Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why docker build image from docker file will create container when build exit incorrectly?

I'm using docker to build images from a docker file. In the process there's some error happened, so the build exit with error code.

When I run docker images I can see a untagged image. so I tried to remove it docker rmi xxxxx. But it always fails, it says the images can't be removed because it's used by a stopped container.

So I dig a little deeper. I run docker ps -a, now I can see a long list of stopped container which are created when the build process fails.

Why there will be container created?? I thought image is like the concept of "class" in programming, and container is instance of the class. Before the image is successfully built, why there'll be instance created? How can I build image without all those stopped containers ?

like image 682
Aaron Shen Avatar asked Apr 23 '16 08:04

Aaron Shen


2 Answers

Each line of your Dockerfile creates an intermediate container to execute the Dockerfile directive for that line.

If the directive succeeds, that will create an intermediate image, which will be the base for the next container to be launch (to execute the next line of your Dockerfile)

If said directive fails, that can leave a container in an Exited state, which in turn will block the intermediate image it was created from.
Simply cleanup all the containers then all the images, and try again.

If you have tried to build repeatedly your Dockerfile, you end up with a collection of intermediate images and containers.

That is why, when my build (finally) succeeds, I always cleanup extra containers, images and (with docker 1.10+) volumes in my build script:

cmdb="docker build${proxy}${f} -t $1 $2"
# echo "cmdb='${cmdb}"
if eval ${cmdb}; then
    docker rm $(docker ps -qa --no-trunc --filter "status=exited" 2>/dev/null) 2>/dev/null
    docker rmi $(docker images --filter "dangling=true" -q --no-trunc 2>/dev/null) 2>/dev/null
    docker volume rm $(docker volume ls -qf dangling=true 2>/dev/null) 2>/dev/null
    exit 0
fi
like image 145
VonC Avatar answered Sep 22 '22 16:09

VonC


The build process is creating an intermediate for each step in the dockerfile. Like you can see in this example:

...
Removing intermediate container e07079f73a9f
Step 3 : RUN cd /opt/
 ---> Running in 78d480a57cca
 ---> 324e9006d642
Removing intermediate container 78d480a57cca
Step 4 : RUN unzip /opt/mule-ee-distribution-standalone-3.7.3.zip -d /opt/
 ---> Running in 81aa445c770c
...
 ---> e702e1cff4ee
 ---> removing intermediate container 81aa445c770c

To speed up the build process the intermediate container will be used as cache. Those containers will be deleted after a succesful build but when you try to build for multiple times the 'old' intermediate containers and image will still be on your system.

If you wish to keep the intermediate containers after the build is complete, you must use --rm=false. By default it's true so after a successful build the intermediate containers will be deleted. When a build fails during the use of an intermediate container, than this container will exit. The intermediate 'image for this container' has tags <none>:<none> and can't be deleted normally because there is an (excited) container which is from this image. You can delete the image by using the -f (force) flag: docker rmi -f image-id

like image 40
lvthillo Avatar answered Sep 19 '22 16:09

lvthillo