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
- Dockerfile reference | Docker Documentation
- To read more about Docker: https://blog.knoldus.com/understanding-containerization-and-its-implementation-by-docker/