A Docker image is an immutable read-only file system that is a snapshot of the entire package of an application, including the dependencies, configuration, and settings.
In this chapter, you’ll learn about Dockerfile and its basics. We’ll build images using Dockerfiles and then view the running images. We’ll then run these images inside a Docker container, and you’ll discover how to attach the container to our local terminal input/output.
Docker Images
As mentioned previously, Docker images are read-only and immutable and created with the docker image build command . They are stored inside a Docker registry and run inside a container. Images can become quite large very quickly. Therefore, they are designed to be composed of layers of other images, allowing a minimal amount of data to be sent when transferring images over a network. So, you can build your own customized image on top of an existing image. When you modify that image, new layers are added that contain your changes.
As for Docker containers, you’ll learn about them in more detail later in this chapter, but to summarize with a programming metaphor, if an image is a class, then a container is an instance of a class, that is, a runtime object. While images are lightweight and portable encapsulations of an environment, containers are the running instances of images.
Furthermore, a Docker image is created using a Dockerfile. Let’s see what a Dockerfile is. Later on, you’ll learn how to build a Docker image from a Dockerfile.
Dockerfile
Everything Docker begins with a Dockerfile. The Dockerfile is the instruction set on how to build an image. It the basis on which your entire Docker container is built. It specifies all the configuration settings environment variables, volumes to be mounted, the base image to build on top of, the list of dependencies, etc. All this is then bundled into an image that then runs inside the container.
A Dockerfile must be built to create the Docker image of an application. The image is just the “compiled version” of the source code that lives inside the Dockerfile. The Dockerfile is a text file that contains a set of instructions or commands that are then assembled into an image.
Creating a Sample Dockerfile
- 1.
The first line, #This is a sample image, is a comment. You can add other comments to the Dockerfile for readability using the # command.
- 2.
The FROM keyword is used to tell Docker which base image you want to build your customized image on top of. This instruction is mandatory.
- 3.
LABEL is a non-executable instruction used to indicate the author of the Dockerfile.
- 4.The RUN instruction is used to execute a command on top of an existing image. That in turn creates another layer with the results of the execution of the command on top of the image. For example, if there is a precondition to install PHP before running an application, you can run appropriate commands to install PHP on top of the base image (say, Ubuntu), as shown following.FROM ubuntuRUN apt-get update && update apt-get install –y php
- 5.
The CMD command doesn’t execute anything during the build time. It just specifies the intended command for the image. The difference between the CMD and the RUN command is that RUN actually executes the command during build time. If you have multiple CMD instructions in the Dockerfile, only the last one will take effect.
ENV: This instruction can be used to set the environment variables in the container as shown following.
#Default environment variables requires to run service, can be overridden by docker runENV CONFIG_FILE=config/config.service.test.propertiesHEAP_SIZE=6GLOG4J_CONFIG_FILE=config/log4j_local.xmlNEW_SIZE=4GCOPY: This instruction is used to copy the files and directories from a specified source to a specified destination (in the file system of the container), as follows.
COPY conditions.txt /usr/tmpADD: The ADD instruction is like the COPY instruction. It has some additional features, such as support for remote URLs. The COPY instruction is more readable, so if you don’t need the extra supported features that ADD provides, it’s recommended that you use the COPY instruction instead. See the following usage. Tar or zip files will be auto-expanded when you add one to a source destination.
ADD http://www.xyz.com/sample.tar.xz /usr/srcWORKDIR: This is used to set the currently active directory for other instructions, such as RUN, CMD, ENTRYPOINT, COPY, and ADD. See the following paragraph for a usage example.
If you provide a relative path as the WORKDIR, it will be taken as relative to the path of the previous WORKDIR instruction.WORKDIR /userWORKDIR homeUSER: This is used to set the UID (or username) to use when running the image or any subsequent commands. See the following usage.
USER daemonVOLUME: This instruction specifies a path in which data should be persisted longer than the life of the container. See the following usage.
VOLUME /dataENTRYPOINT: This command is the primary command of your Docker image.
This command is set in such a way that whenever you run the image, the ENTRYPOINT command will be executed every time.
You can also pass arguments here, but they are optional. You can pass them when you run the image with something such as docker run <image-name>.
Save this file, and in the next section, you’ll see how to build an image from this Dockerfile.
Building Images with Dockerfile
As you’ve learned so far, Docker images are immutable, read-only file systems. Images can be based on other existing images that can be pulled from Dockerfile. This makes modifying them a lot easier, because the only thing that changes is the layer that gets modified. This also prevents images from becoming extremely large in size.
In the previous section, we created a Dockerfile called Dockerfile with some basic instructions and saved it in a directory called docker.
Let’s continue to build an image from the Dockerfile created in the previous section. From the docker directory, run the command docker image build. The . builds the Dockerfile within the directory.
When you run this command for the first time, you’ll see a long list of packages being pulled, because we’re building our image on top of the Ubuntu image.
I am going to divide the output in multiple sections, to make it easier to read. You should be able to see this entire output, if your image is built successfully.
In the next section, let’s run this image inside a container.
Docker Containers
Now that we have built a Docker image successfully, let’s look into what a Docker container is and run this image inside a container.
As we’ve seen before, Docker containers provide a different form of isolation than virtual machines (VMs). They are lightweight platforms to package your entire microservices application and have it running inside the container.
Let’s run inside a container the image we built successfully. There are multiple ways to run a Docker image inside a container.
You could use either or both to run the image inside a container.
Now let’s look inside the container. Your container has the ID 1c3e3baace92.
When inside the container, you can view logs, volumes that have been mounted, etc. Getting inside the Docker container very much comes in handy when debugging errors.
Attaching and Detaching from a Docker Container
Attaching to the Docker container means attaching the local standard input/output to the Docker container. Detaching means detaching your local input/output from the Docker container. Now you’ll learn how to attach to and detach from a Docker container.
kinnaryjangla@dev-abv:~/code/demo/docker$
You should see that your terminal is now attached to the container’s input/output.
In this example, we run the image inside a container and call it test. We then attach the container to the local standard input/output. From inside the container, we set an exit code of 13, which exits the container. On your local terminal, when you echo, you see 13 as the output. In your list of containers, you see that the container exited, owing due to the exit code 13.
You can also create a new container over a certain image. This is useful when you want to set up a container configuration beforehand.
This lands you inside the newly created container.
You can do various things when you create a container, such as initializing volumes and even removing them using the -v option.
Now that we’ve looked at how to create Dockerfiles, how to build images with Dockerfiles, and how to run these images inside a container, in the next chapter, let’s look at how to link multiple containers,in order to get an entire microservices application up and running on Docker.
Summary
In this chapter, we looked at what a Dockerfile is and created a basic Dockerfile step by step. You learned that a Dockerfile is the first step to anything Docker.
Later, we built an image using this Dockerfile. We looked at how to list all the images on your host machine.
Later, we ran this image inside a container and looked at how to attach the container to our local terminal input/output. We executed a few examples and attached and detached the container to our local terminal. You also learned how to list all the containers that are up and running on your machine.
In the next chapter, we’ll look at how to link multiple containers, hence multiple services to each other, and create a real-world microservices application, using Docker.