Image Architecture
- A container image basically is a tar file with associated metadata
- To build container images in an efficient way, it typically consists of multiple layers
- While building an image, a base system image is used
- On top of the base system image, the application is installed as an additional layer
- Some of the standard images themselves already consist of multiple layers
- Using layers ensures that images are built efficiently
Exploring Image Layers
docker image ls
shows images stored, including version information using
tagsdocker image rm
removes imagesdocker history <imagelD>
ordocker history image:tag
shows the different layers in the image- Notice that each modification adds an image layer!
Tagging Images
- Tags allow you to assign names to images, which makes it
easier to manage versions- If no tag is added, “latest” is used as the default tag
- Manually tag images:
docker tag myapache myapache:1.0
- Next, using
docker image ls | grep myapache
will show the same image listed twice, as 1.0 and as latest
- Next, using
- Tags can also be used to identify the target registry
docker tag myapache localhost:5000/myapache:1.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
[root@controller ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 3db8720ecbf5 9 days ago 77.9MB mariadb latest 2f62d6fb2c8b 10 days ago 405MB busybox latest 3f57d9401f8d 5 weeks ago 4.26MB httpd latest 2776f4da9d55 5 weeks ago 167MB [root@controller ~]# docker tag mariadb localhost:5000/mariadb:latest [root@controller ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 3db8720ecbf5 9 days ago 77.9MB mariadb latest 2f62d6fb2c8b 10 days ago 405MB localhost:5000/mariadb latest 2f62d6fb2c8b 10 days ago 405MB busybox latest 3f57d9401f8d 5 weeks ago 4.26MB httpd latest 2776f4da9d55 5 weeks ago 167MB [root@controller ~]# docker image --help Usage: docker image COMMAND Manage images Commands: build Build an image from a Dockerfile history Show the history of an image import Import the contents from a tarball to create a filesystem image inspect Display detailed information on one or more images load Load an image from a tar archive or STDIN ls List images prune Remove unused images pull Download an image from a registry push Upload an image to a registry rm Remove one or more images save Save one or more images to a tar archive (streamed to STDOUT by default) tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE Run 'docker image COMMAND --help' for more information on a command. [root@controller ~]# docker image history mariadb:latest IMAGE CREATED CREATED BY SIZE COMMENT 2f62d6fb2c8b 10 days ago CMD ["mariadbd"] 0B buildkit.dockerfile.v0 <missing> 10 days ago EXPOSE map[3306/tcp:{}] 0B buildkit.dockerfile.v0 <missing> 10 days ago ENTRYPOINT ["docker-entrypoint.sh"] 0B buildkit.dockerfile.v0 <missing> 10 days ago COPY docker-entrypoint.sh /usr/local/bin/ # … 26.1kB buildkit.dockerfile.v0 <missing> 10 days ago COPY healthcheck.sh /usr/local/bin/healthche… 9.24kB buildkit.dockerfile.v0 <missing> 10 days ago VOLUME [/var/lib/mysql] 0B buildkit.dockerfile.v0 <missing> 10 days ago RUN |3 GPG_KEYS=177F4010FE56CA3336300305F165… 312MB buildkit.dockerfile.v0 <missing> 10 days ago RUN |3 GPG_KEYS=177F4010FE56CA3336300305F165… 133B buildkit.dockerfile.v0 <missing> 10 days ago ARG REPOSITORY=http://archive.mariadb.org/ma… 0B buildkit.dockerfile.v0 <missing> 10 days ago ENV MARIADB_VERSION=1:11.2.3+maria~ubu2204 0B buildkit.dockerfile.v0 <missing> 10 days ago ARG MARIADB_VERSION=1:11.2.3+maria~ubu2204 0B buildkit.dockerfile.v0 <missing> 10 days ago LABEL org.opencontainers.image.authors=Maria… 0B buildkit.dockerfile.v0 <missing> 10 days ago ENV LANG=C.UTF-8 0B buildkit.dockerfile.v0 <missing> 10 days ago RUN |1 GPG_KEYS=177F4010FE56CA3336300305F165… 0B buildkit.dockerfile.v0 <missing> 10 days ago RUN |1 GPG_KEYS=177F4010FE56CA3336300305F165… 14.5MB buildkit.dockerfile.v0 <missing> 10 days ago ARG GPG_KEYS=177F4010FE56CA3336300305F1656F2… 0B buildkit.dockerfile.v0 <missing> 10 days ago ENV GOSU_VERSION=1.17 0B buildkit.dockerfile.v0 <missing> 10 days ago RUN /bin/sh -c groupadd -r mysql && useradd … 329kB buildkit.dockerfile.v0 <missing> 10 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 10 days ago /bin/sh -c #(nop) ADD file:7f9a3c5a4231ed191… 77.9MB <missing> 10 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B <missing> 10 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B <missing> 10 days ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B <missing> 10 days ago /bin/sh -c #(nop) ARG RELEASE 0B |
Creating Images
There are two main approaches to creating an image
-
- Using a running container: a container is started, and
modifications are applied to the container. Thedocker
commit
command is used to write modifications - Using a Dockerfile: a Dockerfile contains instructions for
building an image. Each instruction adds a new layer to the
image, which offers more control over the files that are
added to an image at a later stage
- Using a running container: a container is started, and
Options tor Customizing Images
- Dockerfile, also known as Containerfile, is a very common way to build
custom images - It uses a descriptive file using a base image in which commands are executed to customize it
docker commit
commits changes that are made in a running container to the container image, after whichdocker save
can be used to save itbuildah
can be used to create, modify and manage container images
About Terminology
- Dockerfile is the original terminology, which was introduced by Docker
- OCI has standardized the name to Containerfile
- Dockerfile should be used while working with docker, Containerfile may be used while working with podman
Understanding the Process
- First, you’ll create a working directory: each project should have its own
project directory - Next, you’ll write the Dockerfile: the Dockerfile contains instructions to build the image
- The most important part in the Dockerfile is the default command it will start, which is done by using ENTRYPOINT or CMD
- Finally, build the image with
docker build
orpodman build
About Terminology
- Dockerfile was introduced by Docker to automate building container
images - In Red Hat environments, the word Containerfile is preferred
- Currently,
docker
only supports Dockerfile andpodman
works with Dockerfile as well as Containerfile - For this reason, in this lesson I’m using the word Dockerfile
Writing a Dockerfile
- Each Dockerfile starts with
FROM
, identifying the base image to use- Next, instructions are executed in that base image
- Instructions are executed in the order specified
- Each Dockerfile instruction runs in an independent container, using an intermediate image built from a previous command, which means that adding multiple instructions results in multiple layers
Understanding ENTRYPOINT
ENTRYPOINT
is the default command to be processed- If not specified,
/bin/sh -c
is executed as the default command - Arguments to the
ENTRYPOINT
command may be specified separately
usingCMD
ENTRYPOINT ["command"]; ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["arg1","arg2"]; CMD ["-D", "FOREGROUND"]
- If the default command is specified using
CMD
instead ofENTRYPOINT
, the command is executed as an argument to the default entrypointsh -c
which can give unexpected results - If the arguments to the command are specified within the
ENTRYPOINT
, then they are not supposed to be overwritten from the command line
Understanding Formats
- Options like
ADD, COPY, ENTRYPOINT, CMD
are used in shell form
and in exec form - Shell form is a list of items
ADD /my/file /mydir
ENTRYPOINT /usr/bin/nmap -sn 172.17.0.0/24
- Exec form is a JSON array of items
ADD ["/my/file", "/mydir"]
ENTRYPOINT ["/usr/bin/nmap", "-sn", "172.17.0.0/24"]
- Using Exec form is preferred, as shell form wraps command in a
/bin/sh -c
shell, which creates a sometimes unnecessary shellprocess
Avoiding Multi-layer Images
- Each command used in a Dockerfile creates a new layer and this should be
avoided - So don’t run multiple RUN commands, connect them using &&
RUN yum --disablerepo=* --enablerepo="myrepo" && yum update -y && yum install nmap
- To maintain readability, write the commands on different lines using && \ at the end of each line:
RUN yum --disablerepo=* --enablerepo="rhel7-server-rpms" && \ yum update -y && \
yum install -y nginx
Building Images with Dockerfile
- To build an image with Dockerfile, use
docker build / podman build
docker build
takes 2 arguments:-t name[:tag] directory
- If no tag is specified, the image is tagged as latest
docker build -t myimage
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
[root@controller ckad]# cd dockerfile [root@controller dockerfile]# ls Dockerfile sander.repo [root@controller dockerfile]# cat Dockerfile FROM centos:7 MAINTAINER Sander <mail@sandervanvugt.nl> # Add repo file ADD ./sander.repo /etc/yum.repos.d/ # Install cool software RUN yum --assumeyes update && \ yum --assumeyes install bash nmap iproute && \ yum clean all ENTRYPOINT ["/usr/bin/nmap"] CMD ["-sn", "172.17.0.0/24"] [root@controller dockerfile]# docker build -t nmap . [+] Building 1.1s (8/8) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 326B 0.0s => [internal] load metadata for docker.io/library/centos:7 1.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load build context 0.0s => => transferring context: 32B 0.0s => [1/3] FROM docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4 0.0s => CACHED [2/3] ADD ./sander.repo /etc/yum.repos.d/ 0.0s => CACHED [3/3] RUN yum --assumeyes update && yum --assumeyes install bash nmap iproute && yum clean all 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:6d3d4ddc5fcc659cb18a3b53f6602ff0630e6a64edba6d040c00a05e1dfbc221 0.0s => => naming to docker.io/library/nmap 0.0s [root@controller dockerfile]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nmap latest 6d3d4ddc5fcc 5 minutes ago 387MB ubuntu latest 3db8720ecbf5 11 days ago 77.9MB mariadb latest 2f62d6fb2c8b 12 days ago 405MB localhost:5000/mariadb latest 2f62d6fb2c8b 12 days ago 405MB busybox latest 3f57d9401f8d 5 weeks ago 4.26MB httpd latest 2776f4da9d55 5 weeks ago 167MB [root@controller dockerfile]# docker run nmap Starting Nmap 6.40 ( http://nmap.org ) at 2024-02-24 12:00 UTC Nmap scan report for 172.17.0.1 Host is up (0.000097s latency). MAC Address: 02:42:68:FE:8C:0D (Unknown) Nmap scan report for 172.17.0.2 Host is up (0.000025s latency). MAC Address: 02:42:AC:11:00:02 (Unknown) Nmap scan report for 172.17.0.3 Host is up (0.000031s latency). MAC Address: 02:42:AC:11:00:03 (Unknown) Nmap scan report for 172.17.0.4 Host is up (0.000022s latency). MAC Address: 02:42:AC:11:00:04 (Unknown) Nmap scan report for 172.17.0.5 Host is up (0.000037s latency). MAC Address: 02:42:AC:11:00:05 (Unknown) Nmap scan report for 28661016aea2 (172.17.0.6) Host is up. Nmap done: 256 IP addresses (6 hosts up) scanned in 4.50 seconds |
Using docker commit
- After making changes to a container, you can save it to an image
- Use
docker commit
to do sodocker commit -m "custom web server" -a "Miro" myapache myapache
- Use
docker images
to verify
- Next, use
docker save -o myapache.tar myapache
and transport it to anywhere you’d like - From another system, use
docker load -i myapache.tar
to import it as an image
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
[root@controller ckad]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cc94dcd26493 ubuntu:latest "/bin/bash" 4 days ago Up 4 days sweet_mclean a229ccfd0f81 mariadb "docker-entrypoint.s…" 4 days ago Up 4 days 3306/tcp mydb a96d522c5b20 busybox "sh" 4 days ago Up 4 days cool_pasteur 132a8601bc20 httpd "httpd-foreground" 4 days ago Up 4 days 0.0.0.0:8080->80/tcp, :::8080->80/tcp myapache [root@controller ckad]# docker exec -it myapache.sh "docker exec" requires at least 2 arguments. See 'docker exec --help'. Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Execute a command in a running container [root@controller ckad]# docker exec -it myapache sh # echo hello > /tmp/hellofile # ls -l /tmp/hellofile -rw-r--r-- 1 root root 6 Feb 24 13:12 /tmp/hellofile # exit [root@controller ckad]# docker diff myapache C /tmp A /tmp/hellofile C /var A /var/www A /var/www/html C /usr C /usr/local C /usr/local/apache2 C /usr/local/apache2/logs A /usr/local/apache2/logs/httpd.pid [root@controller ckad]# docker commit --help | more Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] Create a new image from a container's changes Aliases: docker container commit, docker commit Options: -a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>") -c, --change list Apply Dockerfile instruction to the created image -m, --message string Commit message -p, --pause Pause container during commit (default true) [root@controller ckad]# docker commit my Error response from daemon: No such container: my [root@controller ckad]# docker commit myapache myapache sha256:3b7004c30a95887e955966a9898f985e0e1785f183d09745ed83548da5f77f82 [root@controller ckad]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE myapache latest 3b7004c30a95 8 seconds ago 167MB namp latest 6d3d4ddc5fcc About an hour ago 387MB nmap latest 6d3d4ddc5fcc About an hour ago 387MB ubuntu latest 3db8720ecbf5 11 days ago 77.9MB mariadb latest 2f62d6fb2c8b 12 days ago 405MB localhost:5000/mariadb latest 2f62d6fb2c8b 12 days ago 405MB busybox latest 3f57d9401f8d 5 weeks ago 4.26MB httpd latest 2776f4da9d55 5 weeks ago 167MB [root@controller ckad]# docker save -o myapache.tar myapache |
Lab: Creating Custom Container Images
- Create a Dockerfile that creates an image that meets the
following requirements: - Based on fedora
- Contains the packages containing the
ps
command as well as network tools - Should run the sshd process
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
[root@controller ckad]# mkdir lesson1lab [root@controller ckad]# cp dockerfile/* lesson1lab/ [root@controller lesson1lab]# vi Dockerfile [root@controller lesson1lab]# vim Dockerfile [root@controller lesson1lab]# cat Dockerfile FROM fedora MAINTAINER Miro <mborodziuk@yahoo.com> # Install cool software RUN dnf -y update && \ dnf -y install procps-ng iproute openssh-server && \ dnf clean all CMD ["/usr/sbin/sshd"] [root@controller lesson1lab]# docker build -t mysshd ERROR: "docker buildx build" requires exactly 1 argument. See 'docker buildx build --help'. Usage: docker buildx build [OPTIONS] PATH | URL | - Start a build [root@controller lesson1lab]# docker build -t mysshd . [+] Building 119.4s (6/6) FINISHED docker:default => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 235B 0.0s => [internal] load metadata for docker.io/library/fedora:latest 2.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [1/2] FROM docker.io/library/fedora:latest@sha256:61864fd19bbd64d620f338eb11dae9e8759bf7fa97302ac6c43865c48dccd679 6.2s => => resolve docker.io/library/fedora:latest@sha256:61864fd19bbd64d620f338eb11dae9e8759bf7fa97302ac6c43865c48dccd679 0.0s => => sha256:5f878605acd6f24f3f11e4085544caf61b046378b31d6b3aa0677a7a3dbe0a17 2.00kB / 2.00kB 0.0s => => sha256:353b74d8db1cf655e87c780b9ac49f52ed72dfaa3ecc4bb0e9245e72c98a45b5 64.61MB / 64.61MB 0.9s => => sha256:61864fd19bbd64d620f338eb11dae9e8759bf7fa97302ac6c43865c48dccd679 975B / 975B 0.0s => => sha256:830a6bcb5c9b30bfa77479b747a904bed02151e9de7ceeb8a1d117b574571fa4 529B / 529B 0.0s => => extracting sha256:353b74d8db1cf655e87c780b9ac49f52ed72dfaa3ecc4bb0e9245e72c98a45b5 4.7s => [2/2] RUN dnf -y update && dnf -y install procps-ng iproute openssh-server && dnf clean all 109.3s => exporting to image 1.2s => => exporting layers 1.2s => => writing image sha256:88ace079c8650240999a2d9169cc4600d6c25a84ef3dd817e6255095dbfd7bc9 0.0s => => naming to docker.io/library/mysshd 0.0s [root@controller lesson1lab]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysshd latest 88ace079c865 About a minute ago 231MB myapache latest 3b7004c30a95 37 minutes ago 167MB namp latest 6d3d4ddc5fcc 2 hours ago 387MB nmap latest 6d3d4ddc5fcc 2 hours ago 387MB ubuntu latest 3db8720ecbf5 11 days ago 77.9MB mariadb latest 2f62d6fb2c8b 12 days ago 405MB localhost:5000/mariadb latest 2f62d6fb2c8b 12 days ago 405MB busybox latest 3f57d9401f8d 5 weeks ago 4.26MB httpd latest 2776f4da9d55 5 weeks ago 167MB [root@controller lesson1lab]# docker run mysshd sshd: no hostkeys available -- exiting. |