-
Book Overview & Buying
-
Table Of Contents
The Docker Workshop
By :
In the last section, we learned how to create a Dockerfile. The next step of the process is to build a Docker image using the Dockerfile.
A Docker image is the template used to build Docker containers. This is analogous to how a house plan can be used to create multiple houses from the same design. If you are familiar with object-oriented programming concepts, a Docker image and a Docker container have the same relationship as a class and an object. A class in object-oriented programming can be used to create multiple objects.
A Docker image is a binary file consisting of multiple layers based on the instructions provided in the Dockerfile. These layers are stacked on top of one another, and each layer is dependent on the previous layer. Each of the layers is a result of the changes from the layer below it. All the layers of the Docker image are read-only. Once we create a Docker container from a Docker image, a new writable layer will be created on top of other read-only layers, which will contain all the modifications made to the container filesystem:
Figure 2.2: Docker image layers
As illustrated in the preceding image, the docker image build command will create a Docker image from the Dockerfile. The layers of the Docker image will be mapped to the directives provided in the Dockerfile.
This image build process is initiated by the Docker CLI and executed by the Docker daemon. To generate a Docker image, the Docker daemon needs access to the Dockerfile, source code (for example, index.html), and other files (for example, properties files) that are referenced in the Dockerfile. These files are typically stored in a directory that is known as the build context. This context will be specified while executing the docker image build command. The entire context will be sent to the Docker daemon during the image build process.
The docker image build command takes the following format:
$ docker image build <context>
We can execute the docker image build command from the folder that contains the Dockerfile and the other files, as shown in the following example. Note that the dot (.) at the end of the command is used to denote the current directory:
$ docker image build.
Let's see the Docker image build process for the following sample Dockerfile:
FROM ubuntu:latest LABEL [email protected] CMD ["echo","Hello World"]
This Dockerfile uses the latest ubuntu images as the parent image. Then, the LABEL directive is used to specify [email protected] as the maintainer. Finally, the CMD directive is used to echo "Hello World" as the output of the image.
Once we execute the docker image build command for the preceding Dockerfile, we can see an output similar to the following on the console during the build process:
Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:latest latest: Pulling from library/ubuntu 2746a4a261c9: Pull complete 4c1d20cdee96: Pull complete 0d3160e1d0de: Pull complete c8e37668deea: Pull complete Digest: sha256:250cc6f3f3ffc5cdaa9d8f4946ac79821aafb4d3afc93928 f0de9336eba21aa4 Status: Downloaded newer image for ubuntu:latest ---> 549b9b86cb8d Step 2/3 : LABEL [email protected] ---> Running in a4a11e5e7c27 Removing intermediate container a4a11e5e7c27 ---> e3add5272e35 Step 3/3 : CMD ["echo","Hello World"] ---> Running in aad8a56fcdc5 Removing intermediate container aad8a56fcdc5 ---> dc3d4fd77861 Successfully built dc3d4fd77861
The first line of the output is Sending build context to Docker daemon, which indicates that the building starts by sending the build context to the Docker daemon. All the files available in the context will be sent recursively to the Docker daemon (unless specifically asked to ignore certain files).
Next, there are steps mentioned as Step 1/3 and Step 2/3, which correspond to the instructions in the Dockerfile. As the first step, the Docker daemon will download the parent image. In the preceding output shown, Pulling from library/ubuntu indicates this. For each line of the Dockerfile, a new intermediate container will be created to execute the directive, and once this step is completed, this intermediate container will be removed. The lines Running in a4a11e5e7c27 and Removing intermediate container a4a11e5e7c27 are used to indicate this. Finally, the Successfully built dc3d4fd77861 line is printed when the build is completed without any errors. This line prints the ID of the newly built Docker image.
Now, we can list the available Docker images using the docker image list command:
$ docker image list
This list contains the locally built Docker images and Docker images pulled from remote Docker repositories:
REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> dc3d4fd77861 3 minutes ago 64.2MB ubuntu latest 549b9b86cb8d 5 days ago 64.2MB
As shown in the preceding output, we can see two Docker images. The first Docker image with the IMAGE ID of dc3d4fd77861 is the locally built Docker image during the build process. We can see that this IMAGE ID is identical to the ID in the last line of the docker image build command. The next image is the ubuntu image that we used as the parent image of our custom image.
Now, let's build the Docker image again using the docker image build command:
$ docker image build Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:latest ---> 549b9b86cb8d Step 2/3 : LABEL [email protected] ---> Using cache ---> e3add5272e35 Step 3/3 : CMD ["echo","Hello World"] ---> Using cache ---> dc3d4fd77861 Successfully built dc3d4fd77861
This time, the image build process was instantaneous. The reason for this is the cache. Since we did not change any content of the Dockerfile, the Docker daemon took advantage of the cache and reused the existing layers from the local image cache to accelerate the build process. We can see that the cache was used this time with the Using cache lines available in the preceding output.
The Docker daemon will perform a validation step before starting the build process to make sure that the Dockerfile provided is syntactically correct. In the case of an invalid syntax, the build process will fail with an error message from the Docker daemon:
$ docker image build Sending build context to Docker daemon 2.048kB Error response from daemon: Dockerfile parse error line 5: unknown instruction: INVALID
Now, let's revisit the locally available Docker images with the docker image list command:
$ docker image list
The command should return the following output:
REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> dc3d4fd77861 3 minutes ago 64.2MB ubuntu latest 549b9b86cb8d 5 days ago 64.2MB
Note that there was no name for our custom Docker image. This was because we did not specify any repository or tag during the build process. We can tag an existing image with the docker image tag command.
Let's tag our image with IMAGE ID dc3d4fd77861 as my-tagged-image:v1.0:
$ docker image tag dc3d4fd77861 my-tagged-image:v1.0
Now, if we list our images again, we can see the Docker image name and the tag under the REPOSITORY and TAG columns:
REPOSITORY TAG IMAGE ID CREATED SIZE my-tagged-image v1.0 dc3d4fd77861 20 minutes ago 64.2MB ubuntu latest 549b9b86cb8d 5 days ago 64.2MB
We can also tag an image during the build process by specifying the -t flag:
$ docker image build -t my-tagged-image:v2.0 .
The preceding command will print the following output:
Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:latest ---> 549b9b86cb8d Step 2/3 : LABEL [email protected] ---> Using cache ---> e3add5272e35 Step 3/3 : CMD ["echo","Hello World"] ---> Using cache ---> dc3d4fd77861 Successfully built dc3d4fd77861 Successfully tagged my-tagged-image:v2.0
This time, in addition to the Successfully built dc3d4fd77861 line, we can see a Successfully tagged my-tagged-image:v2.0 line, which indicates the tagging on our Docker image.
In this section, we learned how to build a Docker image from a Dockerfile. We discussed the difference between a Dockerfile and a Docker image. Then, we discussed how a Docker image is made up of multiple layers. We also experienced how caching can accelerate the build process. Finally, we tagged the Docker images.
In the next exercise, we are going to build a Docker image from the Dockerfile that we created in Exercise 2.01: Creating Our First Dockerfile.
In this exercise, you will build the Docker image from the Dockerfile that you created in Exercise 2.01: Creating Our First Dockerfile and run a Docker container from the newly built image. First, you will run the Docker image without passing any arguments, expecting You are reading The Docker Workshop as the output. Next, you will run the Docker image with Docker Beginner's Guide as the argument and expect You are reading Docker Beginner's Guide as the output:
custom-docker-image directory created in Exercise 2.01: Creating Our First Dockerfile. Confirm that the directory contains the following Dockerfile created in Exercise 2.01: Creating Our First Dockerfile:# This is my first Docker image FROM ubuntu LABEL [email protected] RUN apt-get update CMD ["The Docker Workshop"] ENTRYPOINT ["echo", "You are reading"]
docker image build command. This command has the optional -t flag to specify the tag of the image. Tag your image as welcome:1.0:$ docker image build -t welcome:1.0 .
Note
Do not forget the dot (.) at the end of the preceding command, which is used to denote the current directory as the build context.
It can be seen from the following output that all five steps mentioned in the Dockerfile are executed during the build process. The last two lines of the output suggest that the image is successfully built and tagged:

Figure 2.3: Building the welcome:1.0 Docker image
Dockerfile content:$ docker image build -t welcome:2.0 .
Note that this build process completed much quicker than the previous process due to the cache being used:

Figure 2.4: Building the welcome:1.0 Docker image using the cache
docker image list command to list all the Docker images available on your computer:$ docker image list
These images are available on your computer, either when you pull them from a Docker registry, or when you build on your computer:
REPOSITORY TAG IMAGE ID CREATED SIZE welcome 1.0 98f571a42e5c 23 minutes ago 91.9MB welcome 2.0 98f571a42e5c 23 minutes ago 91.9MB ubuntu latest 549b9b86cb8d 2 weeks ago 64.2MB
As you can see from the preceding output, there are three Docker images available. The ubuntu image is pulled from the Docker Hub, and version (tag) 1.0 and 2.0 of the welcome images are built on your computer.
docker container run command to start a new container from the Docker image that you built in step 1 (welcome:1.0):$ docker container run welcome:1.0
The output should be as follows:
You are reading The Docker Workshop
You receive the expected output of You are reading The Docker Workshop. You are reading is due to the parameter provided with the ENTRYPOINT directive, and The Docker Workshop comes from the parameter provided with the CMD directive.
docker container run command again, this time with command-line arguments:$ docker container run welcome:1.0 "Docker Beginner's Guide"
You will get the output You are reading Docker Beginner's Guide because of the command-line argument, Docker Beginner's Guide, and the You are reading argument provided in the ENTRYPOINT directive:
You are reading Docker Beginner's Guide
In this exercise, we learned how to build a custom Docker image using the Dockerfile and run a Docker container from the image. In the next section, we are going to learn other Docker directives that we can use in the Dockerfile.
Change the font size
Change margin width
Change background colour