Introduction to Dockerfile and its various Instructions

Reading Time: 4 minutes

What is a Dockerfile

Dockerfile is a special text document that contains all the commands necessary for building an image. Docker reads the Dockerfile and builds an image based on the commands and instructions provided in the Dockerfile.

A Docker image follows a layered architechture. Every line in the Dockerfile forms a new layer in the architecture of the image. Docker chaches individual layers of the image and thus reuses these unchanged cached layers of the image everytime during image building jobs rather than rebuilding the entire image everytime.

How to write a Dockerfile:

The basic syntax of writing a Dockerfile is

INSTRUCTION ARGUMENTS

The instructions should always be in uppercase. The best practice while writing a Dockerfile is to put those lines at the end which varies with every image build. Some basic instructions we need to write a Dockerfile are as follows:

FROM

Every Docker image needs a base image on which the image is built. So we will need to mention the name of the base image with the FROM instruction.

If the base image is not present in the Docker Host, it pulls the image from the central repository viz. DockerHub.

Syntax:
FROM openjdk:jdk AS builder

Here the builder is the alias pointing to the image built in this stage. We can use this image in another build stage as the base image. In the above example, jdk is a tag that specifies the version of the base image. If the tag is not specified, it will pull the latest version.

RUN

We use RUN instruction to run any commands on the current image. This execution of commands as a result creates a new layer in the image build. We can have multiple RUN instructions in the Dockerfile. It has two forms:

Syntax:
  • Executable Form:
RUN ["apt","install","python"]
  • Shell Form:
RUN apt install python

ARG

ARG instruction is used to pass a value during the build stage of the image. We can use the passed value to set any commands in the Dockerfile. It is the only command that can precede FROM command. A Dockerfile can have multiple ARG commands.

Syntax:
ARG version=jdk
FROM openjdk:$version

Using –build-arg flag we can pass the argument value during image build.

docker build --build-arg version="18-jdk" -t custom-image:latest .

WORKDIR

We can set a working directory in the image by using WORKDIR instruction. As a result, all the following instructions are executed inside this directory. Docker creates the directory if it does not exist.

Syntax:
WORKDIR ~/workingDirectory

ENV

We use the ENV instruction to set Environment variables for the image. The environment variables are set in the form of key-value pair. The value remains same for all the following commands but we can change the value during the execution of the container.

Syntax:
ENV username root
#Here we set a default value to the environment variable, username=root 

EXPOSE

We use EXPOSE instruction to specify the ports on which the containerized application will listen during runtime. Multiple ports can be specified using EXPOSE.

By default, exposed port listens TCP Protocol. The Protocol can also be specified with the ports.

Syntax:
#EXPOSE <port>/<protocol>

EXPOSE 80 443
# Specifying the protocols
EXPOSE 80/tcp 443/udp 

ADD

We use the ADD instruction to copy files, directories and remote URL files into a Docker Image.

When copying a tarball file from the Docker Host to any location inside the image, the ADD instruction not only copies the file but also extracts the tarball file automatically.

Syntax:
#ADD source1 source2 sourceN destination
ADD ~/localFolder/File.java ~/folderInsideImage

COPY

We use COPY instruction to copy files, directories into a Docker Image. The difference between ADD and COPY is, when copying a tarball from the Docker Host to any location inside the image, the COPY instruction copies the tarball file as it is.

Syntax:
#COPY source1 source2 sourceN destination
COPY ~/localFolder/Application.java ~/folderInsideImage

CMD

We use CMD instruction to set a command that will be executed when running a container. There must always be one CMD in a Dockerfile. In case of more than one CMD in the file, the last CMD takes effect. We can override the CMD instructionThe CMD command can be overridden if the user appends the run command with the command to be executed.

Syntax:
  • Executable Form:
CMD ["java","Application"]
  • Shell Form:
CMD java Application
Overriding CMD Instruction
# docker run image_name:tag <instruction> <argument>
docker run -d custom-image:latest javac Application.java 

ENTRYPOINT

We use ENTRYPOINT instruction to set commands that act as an entry point to the container. In other words, they will always run when a container is executed. Unlike CMD, we can only override ENTRYPOINT command if we add the
--entrypoint flag. Otherwise, we can only append to the ENTRYPOINT command.

Syntax:
  • Executable Form:
ENTRYPOINT ["java","Application"]
  • Shell Form:
ENTRYPOINT java Application

We can combine ENTRYPOINT and CMD if we need a container with a specified executable and a default parameter .

USER

A Docker container runs as a Root user by default. We use the USER instruction to change the user inside the container. We can create a new user using RUN instruction then we can use USER command to switch the default user.

Syntax:
RUN useradd newUser
USER newUser

CONCLUSION

After reading this blog, you will be familiarised with writing a Dockerfile to build a custom image. The blog covers instructions required to write a Dockerfile. I have provided the link to the official page of the Dockerfile. You can head over to the site if you need more detailed overview about Dockerfile.

REFERENCES

Written by 

Dipayan Pramanik is a DevOps Software Consultant at Knoldus Inc. He is passionate about coding, DevOps tools, automating tasks and is always ready to take up challenges. His hobbies include music and gaming.