Instructor Demo: Creating Images
In this demo, we'll illustrate:
- How to read each step of the image build output
- How intermediate image layers behave in the cache and as independent images
- What the meanings of 'dangling' and
<missing>image layers are
Understanding Image Build Output
Make a folder
demofor our image demo:[centos@node-0 ~]$ mkdir demo ; cd demoAnd create a Dockerfile therein with the following content:
FROM centos:7 RUN yum update -y RUN yum install -y which RUN yum install -y wget RUN yum install -y vimBuild your image from your Dockerfile, just like we did in the last exercise:
[centos@node-0 demo]$ docker image build -t demo .Examine the output from the build process. The very first line looks like:
Sending build context to Docker daemon 2.048kBHere the Docker daemon is archiving everything at the path specified in the
docker image buildcommand (.or the current directory in this example). This is why we made a fresh directorydemoto build in, so that nothing extra is included in this process.The next lines look like:
Step 1/5 : FROM centos:7 ---> 49f7960eb7e4Do an
image ls:[centos@node-0 demo]$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE demo latest 59e595750dd5 10 seconds ago 645MB centos 7 49f7960eb7e4 2 months ago 200MBNotice the Image ID for
centos:7matches that second line in the build output. The build starts from the base image defined in theFROMcommand.The next few lines look like:
Step 2/5 : RUN yum update -y ---> Running in 8734b14cf011 Loaded plugins: fastestmirror, ovl ...This is the output of the
RUNcommand,yum update -y. The lineRunning in 8734b14cf011specifies a container that this command is running in, which is spun up based on all previous image layers (just thecentos:7base at the moment). Scroll down a bit and you should see something like:---> 433e56d735f6 Removing intermediate container 8734b14cf011At the end of this first
RUNcommand, the temporary container8734b14cf011is saved as an image layer433e56d735f6, and the container is removed. This is the exact same process as when you useddocker container committo save a container as a new image layer, but now running automatically as part of a Dockerfile build.Look at the history of your image:
[centos@node-0 demo]$ docker image history demo IMAGE CREATED CREATED BY SIZE COMMENT 59e595750dd5 2 minutes ago /bin/sh -c yum install -y vim 142MB bba17f8df167 2 minutes ago /bin/sh -c yum install -y wget 87MB b9f2efa616de 2 minutes ago /bin/sh -c yum install -y which 86.6MB 433e56d735f6 2 minutes ago /bin/sh -c yum update -y 129MB 49f7960eb7e4 2 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 2 months ago /bin/sh -c #(nop) LABEL org.label-schema.... 0B <missing> 2 months ago /bin/sh -c #(nop) ADD file:8f4b3be0c1427b1... 200MBAs you can see, the different layers of
democorrespond to a separate line in the Dockerfile and the layers have their own ID. You can see the image layer433e56d735f6committed in the second build step in the list of layers for this image.Look through your build output for where steps 3/5 (installing
which), 4/5 (installingwget), and 5/5 (installingvim) occur - the same behavior of starting a temporary container based on the previous image layers, running theRUNcommand, saving the container as a new image layer visible in yourdocker iamge historyoutput, and deleting the temporary container is visible.Every layer can be used as you would use any image, which means we can inspect a single layer. Let's inspect the
wgetlayer, which in my case isbba17f8df167(yours will be different, look at yourdocker image historyoutput):[centos@node-0 demo]$ docker image inspect bba17f8df167Let's look for the command associated with this image layer by using
--format:[centos@node-0 demo]$ docker image inspect \ --format='{{.ContainerConfig.Cmd}}' bba17f8df167 [/bin/sh -c yum install -y wget]We can even start containers based on intermediate image layers; start an interactive container based on the
wgetlayer, and look for whetherwgetandvimare installed:[centos@node-0 demo]$ docker container run -it bba17f8df167 bash [root@a766a3d616b7 /]# which wget /usr/bin/wget [root@a766a3d616b7 /]# which vim /usr/bin/which: no vim in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)wgetis installed in this layer, but sincevimdidn't arrive until the next layer, it's not available here.
Managing Image Layers
Change the last line in the Dockerfile from the last section to install
nanoinstead ofvim:FROM centos:7 RUN yum update -y RUN yum install -y which RUN yum install -y wget RUN yum install -y nanoRebuild your image, and list your images again:
[centos@node-0 demo]$ docker image build -t demo . [centos@node-0 demo]$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE demo latest 5a6aedc1feab 8 seconds ago 590MB <none> <none> 59e595750dd5 23 minutes ago 645MB centos 7 49f7960eb7e4 2 months ago 200MBWhat is that image named
<none>? Notice the image ID is the same as the old image ID fordemo:latest(see your history output above). The name and tag of an image is just a pointer to the stack of layers that make it up; reuse a name and tag, and you are effectively moving that pointer to a new stack of layers, leaving the old one (the one containing theviminstall in this case) as an untagged or 'dangling' image.Rewrite your Dockerfile one more time, to combine some of those install steps:
FROM centos:7 RUN yum update -y RUN yum install -y which wget nanoRebuild using a
newtag this time, and list your images one more time:[centos@node-0 demo]$ docker image build -t demo:new . ... [centos@node-0 demo]$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE demo new 568b29a0dce9 20 seconds ago 416MB demo latest 5a6aedc1feab 5 minutes ago 590MB <none> <none> 59e595750dd5 28 minutes ago 645MB centos 7 49f7960eb7e4 2 months ago 200MBImage
demo:newis much smaller in size thandemo:latest, even though it contains the exact same software - why?
Conclusion
In this demo, we explored the layered structure of images; each layer is built as a distinct image and can be treated as such, on the host where it was built. This information is preserved on the build host for use in the build cache; build another image based on the same lower layers, and they will be reused to speed up the build process. Notice that the same is not true of downloaded images like centos:7; intermediate image caches are not downloaded, but rather only the final complete image.