A Dockerfile with build instructions.
Create an empty directory:
$ mkdir sample_image
$ cd sample_image
Create a file named Dockerfile with the following content:
$ cat Dockerfile
# Pick up the base image
FROM fedora
# Add author name
MAINTAINER Neependra Khare
# Add the command to run at the start of container
CMD date
$ docker build .
$ docker build -t fedora/test .
The preceding output is different from what we did earlier. However, here we are using a cache after each instruction. Docker tries to save the intermediate images as we saw earlier and tries to use them in subsequent builds to accelerate the build process. If you don't want to cache the intermediate images, then add the --no-cache option with the build. Let's take a look at the available images now:
A context defines the files used to build the Docker image. In the preceding command, we define the context to the build. The build is done by the Docker daemon and the entire context is transferred to the daemon. This is why we see the Sending build context to Docker daemon 2.048 kB message. If there is a file named .dockerignore in the current working directory with the list of files and directories (new line separated), then those files and directories will be ignored by the build context. More details about .dockerignore can be found at https://docs.docker.com/reference/builder/#the-dockerignore-file.
After executing each instruction, Docker commits the intermediate image and runs a container with it for the next instruction. After the next instruction has run, Docker will again commit the container to create the intermediate image and remove the intermediate container created in the previous step.
For example, in the preceding screenshot, eb9f10384509 is an intermediate image and c5d4dd2b3db9 and ffb9303ab124 are the intermediate containers. After the last instruction is executed, the final image will be created. In this case, the final image is 4778dd1f1a7a:
The -a option can be specified with the docker images command to look for intermediate layers:
$ docker images -a
The format of the Dockerfile is:
INSTRUCTION arguments
Generally, instructions are given in uppercase, but they are not case sensitive. They are evaluated in order. A # at the beginning is treated like a comment.
Let's take a look at the different types of instructions:
FROM <image>
Alternatively, consider the following tag:
FROM <images>:<tag>
There can be more than one FROM instruction in one Dockerfile to create multiple images. If only image names, such as Fedora and Ubuntu are given, then the images will be downloaded from the default Docker registry (Docker Hub). If you want to use private or third-party images, then you have to mention this as follows:
[registry_hostname[:port]/][user_name/](repository_name:version_tag)
Here is an example using the preceding syntax:
FROM registry-host:5000/nkhare/f20:httpd
MAINTAINER: This sets the author for the generated image, MAINTAINER <name>.
RUN: We can execute the RUN instruction in two ways—first, run in the shell (sh -c):
RUN <command> <param1> ... <pamamN>
Second, directly run an executable:
RUN ["executable", "param1",...,"paramN" ]
As we know with Docker, we create an overlay—a layer on top of another layer—to make the resulting image. Through each RUN instruction, we create and commit a layer on top of the earlier committed layer. A container can be started from any of the committed layers.
By default, Docker tries to cache the layers committed by different RUN instructions, so that it can be used in subsequent builds. However, this behavior can be turned off using --no-cache flag while building the image.
LABEL: Docker 1.6 added a new feature to the attached arbitrary key-value pair to Docker images and containers. We covered part of this in the Labeling and filtering containers recipe in Chapter 2, Working with Docker Containers. To give a label to an image, we use the LABEL instruction in the Dockerfile as LABEL distro=fedora21.
CMD: The CMD instruction provides a default executable while starting a container. If the CMD instruction does not have an executable (parameter 2), then it will provide arguments to ENTRYPOINT.
CMD ["executable", "param1",...,"paramN" ]
CMD ["param1", ... , "paramN"]
CMD <command> <param1> ... <pamamN>
Only one CMD instruction is allowed in a Dockerfile. If more than one is specified, then only the last one will be honored.
ENTRYPOINT: This helps us configure the container as an executable. Similar to CMD, there can be at max one instruction for ENTRYPOINT; if more than one is specified, then only the last one will be honored:
ENTRYPOINT ["executable", "param1",...,"paramN" ]
ENTRYPOINT <command> <param1> ... <pamamN>
Once the parameters are defined with the ENTRYPOINT instruction, they cannot be overwritten at runtime. However, ENTRYPOINT can be used as CMD, if we want to use different parameters to ENTRYPOINT.
EXPOSE: This exposes the network ports on the container on which it will listen at runtime:
EXPOSE <port> [<port> ... ]
We can also expose a port while starting the container. We covered this in the Exposing a port while starting a container recipe in Chapter 2, Working with Docker Containers.
ENV: This will set the environment variable <key> to <value>. It will be passed all the future instructions and will persist when a container is run from the resulting image:
ENV <key> <value>
ADD: This copies files from the source to the destination:
ADD <src> <dest>
The following one is for the path containing white spaces:
ADD ["<src>"... "<dest>"]
COPY: This is similar to ADD.COPY <src> <dest>:
COPY ["<src>"... "<dest>"]
VOLUME: This instruction will create a mount point with the given name and flag it as mounting the external volume using the following syntax:
VOLUME ["/data"]
Alternatively, you can use the following code:
VOLUME /data
USER: This sets the username for any of the following run instructions using the following syntax:
USER <username>/<UID>
WORKDIR: This sets the working directory for the RUN, CMD, and ENTRYPOINT instructions that follow it. It can have multiple entries in the same Dockerfile. A relative path can be given which will be relative to the earlier WORKDIR instruction using the following syntax:
WORKDIR <PATH>
ONBUILD: This adds trigger instructions to the image that will be executed later, when this image will be used as the base image of another image. This trigger will run as part of the FROM instruction in downstream Dockerfile using the following syntax:
ONBUILD [INSTRUCTION]
Look at the help option of docker build:
$ docker build -help
The documentation on the Docker website https://docs.docker.com/reference/builder/
You just enjoyed an excerpt from the book, DevOps: Puppet, Docker, and Kubernetes by Thomas Uphill, John Arundel, Neependra Khare, Hideto Saito, Hui-Chuan Chloe Lee, and Ke-Jou Carol Hsu. To master working with Docker containers, images and much more, check out this book today!
How to publish Docker and integrate with Maven
Building Scalable Microservices