ImageLayers, a new project from the team at CenturyLink Labs, gives you the ability to inspect all the layers of an image, including ancestors. And of course, all images must begin with some primordial layer at the base. Generally this image is the Docker scratch image but it can also be a custom image. Using the ImageLayers tool we can demonstrate the various types of root images found in the Docker ecosystem. You can load the example images in your browser using this example link.

imagelayers-comparison_04-21-29-pm

The most common root image is the Docker scratch image, which is pulled into a Dockerfile using the FROM scratch instruction. In the photo above, all of the images except one (mysql) are derived from this scratch image. But that fact may be hard to observe because Docker has recently changed the way it reports the FROM instruction. Prior to Docker 1.5 an image's history would look like the following:

[email protected] ~ $ docker history golang:1.4.0

IMAGE CREATED CREATED BY SIZE
1ea210e0e1f6 4 months ago /bin/sh -c #(nop) COPY file:56695ddefe9b0bd83 2.481 kB
986643313a7b 4 months ago /bin/sh -c #(nop) WORKDIR /go 0 B
258b590ccdee 4 months ago /bin/sh -c #(nop) ENV PATH=/go/bin:/usr/src/g 0 B
4f23222e2f74 4 months ago /bin/sh -c #(nop) ENV GOPATH=/go 0 B
e2d60f7b3d07 4 months ago /bin/sh -c mkdir -p /go/src 0 B
7a94d87545e8 4 months ago /bin/sh -c #(nop) ENV PATH=/usr/src/go/bin:/u 0 B
1dafbd563f5a 4 months ago /bin/sh -c cd /usr/src/go/src && ./make.bash 97.29 MB
7982826b1e59 4 months ago /bin/sh -c curl -sSL https://golang.org/dl/go 39.68 MB
3f1e6432f26e 4 months ago /bin/sh -c #(nop) ENV GOLANG_VERSION=1.4 0 B
22c23ce0a90c 4 months ago /bin/sh -c apt-get update && apt-get install 208.6 MB
835c4d274060 4 months ago /bin/sh -c #(nop) CMD [/bin/bash] 0 B
16386e29a1f4 4 months ago /bin/sh -c #(nop) ADD file:c7787717f522443dee 122.6 MB
511136ea3c5a 23 months ago 0 B

The final line shows an image with size 0 and no command. This is the Docker scratch image which is also reflected in ImageLayers as a 0 size layer with the instruction FROM scratch.

A change was made in Docker 1.5.0 which changes the reporting of the scratch image, but it's still there. The golang:latest was created with Docker 1.5.0 or later because the FROM scratch image has been omitted. This is shown in the docker history golang:latest report:

[email protected] ~ $ docker history golang:latest

IMAGE CREATED CREATED BY SIZE
ca0f230b927e 12 days ago /bin/sh -c #(nop) COPY file:56695ddefe9b0bd83 2.481 kB
f1bec3d7a3c2 12 days ago /bin/sh -c #(nop) WORKDIR /go 0 B
4a386c8c854d 12 days ago /bin/sh -c #(nop) ENV PATH=/go/bin:/usr/src/g 0 B
2c006467b059 12 days ago /bin/sh -c #(nop) ENV GOPATH=/go 0 B
cf87a463dca8 12 days ago /bin/sh -c mkdir -p /go/src /go/bin && chmod 0 B
33e1becc4d89 12 days ago /bin/sh -c #(nop) ENV PATH=/usr/src/go/bin:/u 0 B
86c1ba2f46fd 12 days ago /bin/sh -c cd /usr/src/go/src && ./make.bash 97.4 MB
f3d5a2ae5530 12 days ago /bin/sh -c curl -sSL https://golang.org/dl/go 39.69 MB
e3dfcb7c6e5a 12 days ago /bin/sh -c #(nop) ENV GOLANG_VERSION=1.4.2 0 B
c032a945ed19 12 days ago /bin/sh -c apt-get update && apt-get install 88.32 MB
05bacbdfa6eb 13 days ago /bin/sh -c apt-get update && apt-get install 122.3 MB
e66a33f451f4 13 days ago /bin/sh -c apt-get update && apt-get install 44.33 MB
41b730702607 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
3cb35ae859e7 2 weeks ago /bin/sh -c #(nop) ADD file:96977352301efe982e 125.1 MB

The root image remains the 0 byte scratch image but Docker 1.5.0 made the following change:

"Dockerfile FROM scratch instruction is now interpreted as a no-base specifier."

Therefore images will not show the 0 byte no command scratch layer if they have been created using Docker 1.5.0 or greater. In the history and in ImageLayers.io the last reported instruction will be the one after FROM scratch. In the golang case above the last reported command is the ADD file:96977352301efe982e

Custom Base

[email protected] ~ $ docker history appcontainers/mysql:latest

IMAGE CREATED CREATED BY SIZE
41761f3abd2d 6 days ago /bin/sh -c #(nop) EXPOSE 3306/tcp 0 B
4abf5bd70eac 6 days ago /bin/sh -c #(nop) CMD [/bin/sh -c /bin/bash] 0 B
b6ba40403c71 6 days ago /bin/sh -c chmod +x /tmp/.runconfig.sh && ech 3.298 kB
d78d035692d5 6 days ago /bin/sh -c yum clean all && yum -y update && 106.1 MB
24f3acb1a3eb 6 days ago /bin/sh -c #(nop) ADD file:3d527599b9b026dc36 279 B
9ac9a11cf920 6 days ago /bin/sh -c #(nop) ADD file:54c2df97b40234bcf3 328 B
590d8ca3ab76 6 days ago /bin/sh -c #(nop) ADD file:46cc9ef2efab335e68 3.04 kB
bd7ddd0cbc5f 6 days ago /bin/sh -c #(nop) ENV APP_PASS=testpass 0 B
98223298da0d 6 days ago /bin/sh -c #(nop) ENV APP_USER=testuser 0 B
a126bf054304 6 days ago /bin/sh -c #(nop) ENV MYSQL_DB=testapp 0 B
c86cfaf3af69 6 days ago /bin/sh -c #(nop) ENV CREATEDB=false 0 B
9b08e78d224c 6 days ago /bin/sh -c #(nop) ENV MYSQL_CLIENT=172.17.%.% 0 B
f87ea8845b1e 6 days ago /bin/sh -c #(nop) ENV MYSQL_PASS=PAssw0rd 0 B
c78917b2cdad 6 days ago /bin/sh -c #(nop) ENV MYSQL_USER=root 0 B
b17c76062d08 6 days ago /bin/sh -c #(nop) ENV TERMTAG=mysql 0 B
14f0208b808f 6 days ago /bin/sh -c #(nop) ENV ENV=dev 0 B
7401b06a45d9 6 days ago /bin/sh -c #(nop) MAINTAINER Rich Nason rnaso 0 B
a939136a931f 6 days ago 270.6 MB

It is possible to create a custom base image. The appcontainers/mysql:latest image shows a 271mb unknown instruction in ImageLayers. This instruction is the result of Creating a Base Image. Having a custom base image may allow a single layer as a base to improve application deployment by using the shared base. However creating a custom base is akin to squashing an image. It could reduce the size and number of layers but it prevents incremental changes. The merging of the layers possibly creates a single optimized image, but the entire merged image must be updated on changes rather than a single layer.

Summary

The most common base for Docker images will be the FROM scratch image even if it is reported as a no-base specifier. The history of images which constitute a single image can be found using the docker history command or shown visually using the ImageLayers.io tool. Knowing the ancestry of images may not be an everyday need but when optimizing your images it can be useful to see what additional baggage is brought along.