Dockerfile
TL;DR
What is Dockerfile?
A Dockerfile is a text file that defines a Docker image. You’ll use a Dockerfile to create your own custom Docker image, in other words to define your custom environment to be used in a Docker container.
A Dockerfile is a step by step definition of building up a Docker image. The Dockerfile contains a list of instructions that Docker will execute when you issue the docker build
command. Your workflow is like this:
- Create the Dockerfile and define the steps that build up your images
- Issue the
docker build
command which will build a Docker image from your Dockerfile - Use this image to start containers with the
docker run
command
Dockerfile commands
FROM
The
FROM
instruction initializes a new build stage and sets the Base Image for subsequent instructions.As such, a valid
Dockerfile
must start with aFROM
instruction.- Note:
ARG
is the only instruction that may precedeFROM
in theDockerfile
.
- Note:
The image can be any valid image – it is especially easy to start by pulling an image from the Public Repositories.
Syntax:
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
Example:
FROM ubuntu:18.04
RUN
Execute a command in a shell or exec form.
The RUN instruction adds a new layer on top of the newly created image.
The committed results are then used for the next instruction in the DockerFile.
Syntax
Shell form (the command is run in a shell, which by default is
/bin/sh -c
on Linux)RUN <command>
In the shell form you can use a
\
(backslash) to continue a single RUN instruction onto the next line.E.g.
RUN /bin/bash -c 'source $HOME/.bashrc; \ echo $HOME'
Together they are equivalent to this single line:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
Exec form
RUN ["executable", "param1", "param2"]
E.g.
RUN ["/bin/bash", "-c", "echo hello"]
CMD
Give the default commands when the image is instantiated, it doesn’t execute while build stage.
The
CMD
instruction has three forms:CMD ["executable","param1","param2"]
(exec form, this is the preferred form)- It will NOT involke a command shell. This means that normal shell processing does NOT happen.
E.g
CMD ["echo","hello", "world"]
CMD ["param1","param2"]
(as default parameters to ENTRYPOINT)- If you would like your container to run the same executable every time, then you should consider using
ENTRYPOINT
in combination withCMD
. See ENTRYPOINT.
- If you would like your container to run the same executable every time, then you should consider using
CMD command param1 param2
(shell form)The
<command>
will execute in/bin/sh -c
.E.g.
CMD echo $HW
It will execute the command
/bin/sh -c echo $HW
There can only be ONE
CMD
instruction in aDockerfile
. If you list more than oneCMD
then only the lastCMD
will take effect.The main purpose of a
CMD
is to provide defaults for an executing container. These defaults can include- an executable, or
- they can omit the executable, in which case you must specify an
ENTRYPOINT
instruction as well.
docker run
then they will override the default specified in CMD
.ENTRYPOINT
Configures a container that will run as an executable. I.e., a specific application can be set as default and run every time a container is created using the image.
ENTRYPOINT
has two forms:exec form (the preferred form)
ENTRYPOINT ["executable", "param1", "param2"]
shell form:
ENTRYPOINT command param1 param2
Unlike
CMD
, command line arguments todocker run <image>
will NOT override the default specified inCMD
. Instead, they will be appended after all elements in an exec formENTRYPOINT
, and will override all elements specified usingCMD
.Only the last
ENTRYPOINT
instruction in theDockerfile
will have an effect.You can override the
ENTRYPOINT
instruction using thedocker run --entrypoint
flag.
Understand how CMD and ENTRYPOINT interact
Both CMD
and ENTRYPOINT
instructions define what command gets executed when running a container. There are few rules that describe their co-operation.
- Dockerfile should specify at least one of
CMD
orENTRYPOINT
commands. ENTRYPOINT
should be defined when using the container as an executable.CMD
should be used as a way of defining default arguments for anENTRYPOINT
command or for executing an ad-hoc command in a container.CMD
will be overridden when running the container with alternative arguments.
The table below shows what command is executed for different ENTRYPOINT
/ CMD
combinations:
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] | |
---|---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD [“p1_cmd”, “p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
A common use case is: the executable is defined with ENTRYPOINT, while CMD specifies the default parameter.
Example:
Dockerfile
FROM node:8.11-slim
CMD ["world"]
ENTRYPOINT ["echo", "Hello"]
Build image:
docker built -t my-docker-image .
Run container:
without argument
docker run -it my-docker-image
output:
Hello world
If we run
docker run
without argument, the default argumentworld
defined inCMD
will be used. I.e, the commandecho Hello World
will be executed.with argument
docker run -it my-docker-image James Bond
output:
Hello James Bond
If we specify arguments when running
docker run
,CMD
will be overriden by our given arguments. In our case,CMD ["World"]
is overriden toCMD ["James", "Bond"]
and then applied toecho
. Thus, the commandecho Hello James Bond
will be executed.
Summary of
CMD
andENTRYPOINT
see: Docker CMD Vs Entrypoint Commands: What’s The Difference?
EXPOSE
Specify the port on which the container will be listening at runtime by running the EXPOSE instruction.
Syntax
EXPOSE <port>
ENV
Set environment variables using the ENV instruction.
This value will be in the environment for all subsequent instructions in the build stage and can be replaced inline in many as well.
They come as key value pairs and increases the flexibility of running programs.
Syntax
ENV <key>=<value> ...
e.g.
ENV PATH=usr/node
or
ENV <key> <value>
e.g.
ENV PATH usr/node
ADD
ADD
has two forms:ADD [--chown=<user>:<group>] <src>... <dest>
or
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
Copies new files, directories or remote file URLs from
<src>
and adds them to the filesystem of the image at the path<dest>
.Invalidates caches. Avoid
ADD
and useCOPY
instead.
COPY
Syntax
COPY [--chown=<user>:<group>] <src>... <dest>
or
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
Copy new files or directories from
<src>
and adds them to the filesystem of the container at the path<dest>
.- Each
<src>
may contain wildcards and matching will be done using Go’s filepath.Match rules.COPY
obeys the following rules:
- Each
Example: copy
test.txt
to<WORKDIR>/relativeDir/
:COPY test.txt relativeDir/
COPY
obeys the following rules:The
<src>
path must be inside the context of the buildIf
<src>
is a directory, the entire contents of the directory are copied, including filesystem metadata.(The directory itself is not copied, just its contents.)
If
<src>
is any other kind of file, it is copied individually along with its metadata. In this case, if<dest>
ends with a trailing slash/
, it will be considered a directory and the contents of<src>
will be written at<dest>/base(<src>)
.If multiple
<src>
resources are specified, either directly or due to the use of a wildcard, then<dest>
must be a directory, and it must end with a slash/
.If
<dest>
does not end with a trailing slash, it will be considered a regular file and the contents of<src>
will be written at<dest>
.If
<dest>
doesn’t exist, it is created along with all missing directories in its path.
VOLUMN
- Creates a mount point for externally mounted volumes or other containers
WORKDIR
Sets the working directory for any
RUN
,CMD
,ENTRYPOINT
,COPY
andADD
instructions that follow it in theDockerfile
.The
WORKDIR
instruction can be used multiple times in aDockerfile
. If a relative path is provided, it will be relative to the path of the previousWORKDIR
instruction. E.g.WORKDIR /usr/node WORKDIR app
The resulted work directory will be
/usr/mode/app
The
WORKDIR
instruction can resolve environment variables previously set usingENV
. E.g.ENV WORK_DIR=/usr/node/app WORKDIR ${WORK_DIR}
ARG
Defines a build-time variable
Syntax
ARG <name>[=<default value>]
ARG
is the only instruction that can occur before theFROM
.E.g. we can use
ARG
to specify the version of base imageARG NODE_VERSION=8.11-slim FROM node:${NODE_VERSION}
ONBUILD
- Adds a trigger instruction when the image is used as the base for another build
STOPSIGNAL
- Sets the system call signal that will be sent to the container to exit.
LABEL
Add key/value metadata to your images, containers, or daemons.
Syntax
LABEL <key>=<value> <key>=<value> <key>=<value> ...
Example
LABEL version="1.0" LABEL description="Just a demo"
If a label already exists but with a different value, the most-recently-applied value overrides any previously-set value.
To view an image’s labels, use the
docker image inspect
command. You can use the--format
option to show just the labelsdocker image inspect --format='' <image>
SHELL
- Override default shell is used by docker to run commands.
HEALTHCHECK
- Tells docker how to test a container to check that it is still working.
Example with common commands
# ARG is used to pass some arguments to consecutive instructions
# this is only command other than a comment can be used before FROM.
ARG NODE_VERSION=8.11-slim
# from base image node
FROM node:${NODE_VERSION}
# LABEL add metadata to your images, containers, or daemons
LABEL "about"="This file is just an example to demostrate the basic usage of dockerfile commands"
# ENV sets the environment variables for the subsequent instructions in the build stage
ENV WORK_DIR /usr/node
# WORKDIR sets the working directory for all the consecutive commands.
# We can have multiple WORKDIR commands and will be appended with a relative path.
# E.g. we have two WORKDIR commands leads to /usr/node/app
WORKDIR ${WORK_DIR}
WORKDIR app
# VOLUME is used to create a mount point with the specified name
RUN mkdir /dockerexample
VOLUME /dockerexample
# COPY is used to copy files or directories
# from source host filesystem to a destination in the container file system.
# Here we're gonna copy package.json from our system to container file system
COPY package.json .
# RUN executes the instructions in a new layer on top of the existing image and commit those layers
# The resulted layer will be used for the next instructions in the Dockerfile
RUN ls -ll && \
npm install
# USER instruction sets the user name and optionally the user group to use
# when running the image and for any instructions that follow it in the Dockerfile
RUN useradd ecko
USER ecko
# ADD is used to add files or directories and remote files
# from URL from source host filesystem to a destination in the container file system.
# Avoid ADD and use COPY instead!
ADD index.js .
# CMD command is used to give the default commands when the image is instantiated,
# it doesn’t execute while build stage.
# There should be only ONE CMD per Dockerfile,
# you can list multiple but the last one will be executed.
CMD ["echo", "Hello World"]
# EXPOSE informs Docker that
# the container listens on the specified network ports at runtime.
EXPOSE 3070
# ENTRYPOINT is used as an executable for the container.
# We can use ENTRYPOINT for executable command
# and use CMD command to pass some default commands to the executable.
ENTRYPOINT ["echo", "Hello"]
Reference
- Tutorials
- Reference: Dockerfile reference
- Cheatsheet