Interactive image creation
The first way we can create a custom image is by interactively building a container. That is, we start with a base image that we want to use as a template and run a container of it interactively. Let's say that this is the alpine image. The command to run the container would then be as follows:
$ docker container run -it --name sample alpine /bin/sh
By default, the alpine container does not have the ping tool installed. Let's assume we want to create a new custom image that has ping installed. Inside the container, we can then run the following command:
/ # apk update && apk add iputils
This uses the Alpine package manager apk to install the iputils library, of which ping is a part. The output of the preceding command should look as follows:
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
v3.7.0-50-gc8da5122a4 [http://dl-cdn.alpinelinux.org/alpine/v3.7/main]
v3.7.0-49-g06d6ae04c3 [http://dl-cdn.alpinelinux.org/alpine/v3.7/community]
OK: 9046 distinct packages available
(1/2) Installing libcap (2.25-r1)
(2/2) Installing iputils (20121221-r8)
Executing busybox-1.27.2-r6.trigger
OK: 4 MiB in 13 packages
Now, we can indeed use ping, as the following snippet shows:
/ # ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.049 ms
^C
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2108ms
rtt min/avg/max/mdev = 0.028/0.040/0.049/0.010 ms
Once we have finished our customization, we can quit the container by typing exit at the prompt. If we now list all containers with docker container ls -a, we can see that our sample container has a status of Exited, but still exists on the system:
$ docker container ls -a | grep sample
eff7c92a1b98 alpine "/bin/sh" 2 minutes ago Exited (0) ...
If we want to see what has changed in our container in relation to the base image, we can use the docker container diff command as follows:
$ docker container diff sample
The output should present a list of all modifications done on the filesystem of the container:
C /bin
C /bin/ping
C /bin/ping6
A /bin/traceroute6
C /etc/apk
C /etc/apk/world
C /lib/apk/db
C /lib/apk/db/installed
C /lib/apk/db/lock
C /lib/apk/db/scripts.tar
C /lib/apk/db/triggers
C /root
A /root/.ash_history
C /usr/lib
A /usr/lib/libcap.so.2
A /usr/lib/libcap.so.2.25
C /usr/sbin
C /usr/sbin/arping
A /usr/sbin/capsh
A /usr/sbin/clockdiff
A /usr/sbin/getcap
A /usr/sbin/getpcaps
A /usr/sbin/ipg
A /usr/sbin/rarpd
A /usr/sbin/rdisc
A /usr/sbin/setcap
A /usr/sbin/tftpd
A /usr/sbin/tracepath
A /usr/sbin/tracepath6
C /var/cache/apk
A /var/cache/apk/APKINDEX.5022a8a2.tar.gz
A /var/cache/apk/APKINDEX.70c88391.tar.gz
C /var/cache/misc
In the preceding list, A stands for added, and C for changed. If we had any deleted files, then those would be prefixed with D.
We can now use the docker container commit command to persist our modifications and create a new image from them:
$ docker container commit sample my-alpine
sha256:44bca4141130ee8702e8e8efd1beb3cf4fe5aadb62a0c69a6995afd49c2e7419
With the preceding command, we have specified that the new image shall be called my-alpine. The output generated by the preceding command corresponds to the ID of the newly generated image. We can verify this by listing all images on our system, as follows:
$ docker image ls
We can see this image ID (shortened) as follows:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-alpine latest 44bca4141130 About a minute ago 5.64MB
...
We can see that the image named my-alpine, has the expected ID of 44bca4141130 and automatically got a tag latest assigned. This happens since we did not explicitly define a tag ourselves. In this case, Docker always defaults to the tag latest.
If we want to see how our custom image has been built, we can use the history command as follows:
$ docker image history my-alpine
This will print the list of layers our image consists of:
IMAGE CREATED CREATED BY SIZE COMMENT
44bca4141130 3 minutes ago /bin/sh 1.5MB
e21c333399e0 6 weeks ago /bin/sh -c #... 0B
<missing> 6 weeks ago /bin/sh -c #... 4.14MB
The first layer in the preceding list is the one that we just created by adding the iputils package.