Dockerfile Reference
First of all, this is just the summary that I did from the original Dockerfile refernece found on Docker website. Then, let me admit that I am pretty new to Docker. I have been playing around with it for the last few days. One thing I must admit is that the learning curve for Docker was pretty steep for me. There were a lot of concepts to learn. However, the prospective benefits of using it were far greater. One of the key benefits of Docker I found was ability to deploy applications in different types of platforms without worring much about it. This also gave me the opportunity to share my code with my friends who would be able to run the application with minimum effort.
If you are not familiar to Docker and it's concepts, this might not be the article for you. This article summarizes the references required for writing the Dockerfile. The official documentation can be found the Docker website. This is however my "go-to" document for quick reference.
Purpose of Dockerfile
Docker uses Dockerfile to build images automatically. It is a text file without any extensions that contains all the commands that a user can call on the command line to build an image. The command docker build builds an image from two things:
-
Dockerfileand -
context: it is processed recursively. Thecontextis a set of files at specified location. While building the image, entirecontextis sent to theDocker daemon. Thecontextcan be either:-
PATH: a directory in the local filesystem. This can include subdirectories -
URL: a Git repository location. This can include repository and submodules To use a file in the build context,Dockerfilerefers to the file specified in an instruction (ie.COPY). We can use a.dockerignorefile to improve the build performance by excluding some of the files or directories.
-
Convention:
Dockerfileis usually calledDockerfileand located at the root of the context. However,-fflag can be used withdocker buildto specify anotherDockerfile. For example:
docker build -f /path/to/a/Dockerfile .
Each instruction in the Dockerfile is run separately to create a new image. However, Docker will reuse intermediate images (cache) to accelerate build process, which is indicated by the Using cache message in the output console.
Format of Instructions
Commands in Dockerfile is written in instruction-arguments method. So, there will be an instruction and along with it will be some arguments. Instructions are NOT case-sensitive but convention is to use uppercase.
- must begin with a
FROMinstruction - Comments start with
#sign and are removed from the file before executing the commands - leading whitespace are ignored but discouraged
# this is a comment-line
RUN echo hello
RUN echo world
- Parser directives must be at the top of the file; before the
FROMinstruction
Environment Replacement
Environment Variables can be used in certain instructions as variables to be interpreted by Dockerfile. Environment variable can be notated in Dockerfile with $variable_name or ${variable_name}. However, latter is applicable in case like: ${foo}_bar. Environment Variable is supported by: ADD, COPY, ENV, EXPOSE, FROM, LABEL,STOPSIGNAL, USER, VOLUME, WORKDIR, and ONBUILD. Example:
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
.dockerignore file
Before sending context to docker daemon, docker CLI looks for .dockerignore file in the root of context. If it exists, CLI excludes the files and directories. CLI interprets the file as newline-separated list of patterns. Rules of .dockerignore file:
| Rule | Behavior |
|---|---|
#text |
This is considered comment |
*/temp* |
Excludes file and directories starting with 'temp' in immediate subdirectory of root |
*/*/temp* |
Excludes file and directories starting with 'temp' in two levels below root |
temp? |
Excludes files and directores starting with 'temp' that are in root |
*.md |
Exclude all markdown files |
!README.md |
Exclude all file except README.md
|
Note: if
Dockerfileand.dockerignoreare added to the.dockerignorefile, they NOT copied to the image but are still sent to the daemon.
FROM Instruction
This instruciton initializes a new build stage and sets the Base Image for the subsequent instructions. A valid Dockerfile must start with a FROM instruction.
-
ARGis the only instruction that may precedeFROM -
FROMcan appear multiple times in oneDockerfileto create multiple images or use one build stage as dependency for another. EachFROMinstruction clears any state created by previous instructions -
namecan be used in subsequentFROMorCOPY --from=<name>instructions -
tagordigestvalues are optional. By default, builder assumeslatest. - Examples:
FROM [--platform=<platform>] <image> [AS <name>]
or
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
or
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
ARG and FROM working together
FROM supports variables that are declared by ARG instruction preceding the FROM. Example:
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
from extras:${CODE_VERSION}
CMD /code/run-extras
ARG declared before FROM is usually not available to instructions after the FROM. To make it available, we need to add the ARG instruction and variable name after the FROM without a value. Example:
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
RUN instruction
This instruction runs the commands in a new layer on the current image and commits the results. It has two forms:
-
RUN <command>(shell form):- Backslash
\can be used to continue writing commands in the following line - Default shell can be changed using the
SHELLcommand
- Backslash
-
RUN ["executable", "param1", "param2"](exec form):- Double quotes must be used for commands passed as string
- To change the default shell pass the target shell in first command:
RUN ["/bin/bash", "-c", "echo hello"] - Variable substitution doesn't happen by default. For variable substitution:
RUN [ "sh", "-c", "echo $HOME" ]
CMD instruction
The main purpose for this instruction is the provide defaults for an execurint container. These defaults can include or exclude the executable. If it excludes, then must specify an ENTRYPOINT instruction. There can be only one CMD instruction in a Dockerfile. If there are multiple CMD instructions, the last one will take effect. This instruction has three forms:
-
CMD command param1 param2(shell form): -
CMD ["executable","param1","param2"](exec form): Similar to exec form ofRUN. This is the preferred format forCMD -
CMD ["param1","param2"](default parameters to ENTRYPOINT): If you would like your container to run the same executable every time, then you should consider usingENTRYPOINTin combination withCMD.
Note:
RUNvsCMD.RUNactually runs a command and commits the result;CMDdoes not execute anything at build time, but specifies the intended command for the image.
LABEL instruction
- This instruction adds metadata to an image. The instruction adds a key-value pair to the image. Multiple labels can be added under one single instruction. Example:
LABEL multi.label1="value1" multi.label2="value2" other="value3"
-
LABELs in the parent images are inherited in the subsequent images. If a label exists with multiple values, the latest one override all previous values.
EXPOSE instruction
- This instruction informs that the container listens to a specific network port at runtime.
- TCP or UDP can be specified but TCP is default.
- Doesn't actually publish the port but works as a documentation between the person building image and person running container
- use
-pflag ondocker runto publish and map one or more ports:docker run -p 80:80/tcp -p 80:80/udp - use
-Pflag to publish all exposed ports and map them to high-order ports - Example:
EXPOSE 80/tcp
EXPOSE 80/udp
-
docker networkcommand supports creating networks for communication among containers without exposing ports
ENV instuction
- This instruction sets environment variable that will be available in all subsequent instuction in the build stage.
- Example:
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
- Allows multiple key-value variables to be set at one time:
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
- Environment variables set using this instruction will persist when a container is run from the resulting image. Check the values using
docker inspect; change values usingdocker run -env <key>=<value> - Environment variable persistence can lead to side effects
-
If environment variable is needed only during build, use either of the following methods:
- set value of a single command:
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ... - use
ARG:
ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y ... - set value of a single command:
Alternative syntax (doesn't allow setting multiple variables in one line):
ENV MY_VAR my-value
ADD instruction
- This instruction copies new files/directories from source to the desination
- It has two forms:
ADD [--chown=<user>:<group>] <src>... <dest>ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
Note:
--chownis supported only for Linux containers.
- This instruction takes local files, URLs, and
tarfiles as source - Multiple sources may be specified but there address will be interpreted as relative to the source of context of the build
- Sources may contain wildcards
- Destination is absolute path or path relative to
WORKDIR(where the sources will be copied)
ADD test.txt relativeDir/ # copies test.txt to <WORKDIR>/relativeDir/
ADD test.txt /absoluteDir/ # copies test.txt to /absoluteDir/
- All new files and directories are created with UID and GID of 0 (unless
--chownmentioned)
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
- source directory must be inside the context of the build; you cannot
ADD ../something /something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon. - if source is a directory, the entire contents of the directory are copied including filesystem metadata (the directory itself is not copied).
- if source is a local tar archive in identity/gzip/bzip2/xy format then it is unpacked as a directory with
tar -xbehavior. - if multiple sources are specified, destination must be a directory and must end with forward slash
/ - if destination does not end with a trailing slash, it will be considered a regular file and the contents of source will be written at destination.
- if desitnaton doesn't exist, it is created along with all missing directories
COPY instruction
- This is similar to
ADDinstuction but takes only local files as source and copies to docker image. ADDvsCOPY
ENTRYPOINT instruction
- This allows us to configure a container that will run as an executable.
- This has two forms:
1. `ENTRYPOINT ["executable", "param1", "param2"]` (exec form): `docker run <image>` will be appended after all elements and override all elements specified using `CMD`.
2. `ENTRYPOINT command param1 param2` (shell form): prevents `CMD` or `run` command line arguments to be passed. `ENTRYPOINT` will be started as a subcommand of `/bin/sh -c`, which doesn't pass signals. This means that the executable will be the container's `PID 1` and will not receive unix signals.
- Only the last
ENTRYPOINTwill have effect
How CMD and ENTRYPOINT interact
Both of these instructions define what command gets executed when running a container. The rules regarding interaction of these two are:
-
Dockerfileshould specify at least one ofCMDorENTRYPOINT -
ENTRYPOINTshould be defined when using container as an executable -
CMDshould be used to define default arguments for anENTRYPOINTor executing ad-hoc commands -
CMDwill be overriden when container is run with alternative arguments
The combinations of CMD and ENTRYPOINT are following:
| 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 |
Note: If
CMDis defined in base image, settingENTRYPOINTwill resetCMDto empty. So,CMDmust be redefined in current image to have a value
VOLUME instruction
This creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers.
- The value of this instruction can be:
- JSON array:
VOLUME ["/var/log/"] - Plain string:
VOLUME /var/log /var/db
- JSON array:
- Windows based containers must have volumes that are non-exiting or empty directory and a drive other than
C: - If any build steps change the data within the volume after it has been declared, those changes will be discarded
- The host directory is, by nature, host-dependent. This is to preserve image portability because a given host directory can't be guaranteed to be available on all hosts. That's why we can't mount host directory from within
Dockerfile. We must specify the mountpoint when we create or run the container. - Resource: Use Volumes
USER instruction
This instruction sets the username or UID and optionally the user group (or GID) to use when running the image and for RUN, CMD, and ENTRYPOINT instructions.
- Instruction format:
USER <user>[:<groupsUSER <UID>[:<GID>]
- If group/GID is specified, other group/GID will ignored
- Default group is
root - On Windows, the user must be created first with
net usercommand
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
WORKDIR instruction
This sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD instructions. If it doesn't exist, it will be created even if it's not used in any subsequent Dockerfile instruction.
- It can be declared multiple times. If relative path is provided, it will be relative to previous path provided
- This can resolve environment variables
ARG instruction
This instruction defines a variable that users can pass at build-time to the builder with the docker build command with --build-arg <var>=<value> flag. A Dockerfile may include one or more instructions.
FROM busybox
ARG user1=someuser # default value
ARG buildno # without any value
- The
ARGvariable is available fromt the line it is declared not from where it is used. AnARGgoes out of scope at the end of the build stage where it is defined. - Useful interaction between
ARGandENV:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER`
- Predefined
ARGs:HTTP_PROXY,http_proxy,HTTPS_PROXY,https_proxy,FTP_PROXY,ftp_proxy,NO_PROXY, andno_proxy - Automatic Platform
ARG(only available with BuildKit backend): These are not available inside build stage. To make these available addARG <arg_name>toDockerfile.-
TARGETPLATFORM: platform of the build result -
TARGETOS: OS component ofTARGETPLATFORM -
TARGETARCH: architecture component ofTARGETPLATFORM -
TARGETVARIANT: variant component ofTARGETPLATFORM -
BUILDPLATFORM: platform of the node performing build -
BUILDOS: OS component ofBUILDPLATFORM -
BUILDARCH: architecture component ofBUILDPLATFORM -
BUILDVARIANT: variant component ofBUILDPLATFORM
-
ONBUILD instruction
This adds a trigger instruction to the image, which would be executed at a later time, when the image is used as the base for another build. Any build instruction can be registered as a trigger. Format of the instruction: ONBUILD <instruction>. Example:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
- The way it works:
- When encourted
ONBUILDinstruction, the builder adds a trigger to the metadata of the image being built - After the build, a list of all triggers are stored in image manifest under the key
OnBuildand can be inspected withdocker inspectcommand. - The image can be used as base for another build using the
FROMinstruction. As part of processing theFROM, the downstream builder looks forONBUILDtriggers and executes them in the same order they are registered. - Triggers are cleared from final image after being executed (not inherited by "grand-children" builds)
Note: Chaining
ONBUILDwithONBUILDis not allowed:ONBUILD ONBUILDNote: May not trigger
FROMandMAINTAINERinstructions
STOPSIGNAL instruction
This sets the system call signal that will be sent to the container to exit. This can be valid unsigned number that matches a position in the kernel's syscall table (ex: 9) or signal name (ex: SIGKILL).
HEALTHCHECK instruction
This tells docker how to test a container to check that it is still working. This can be used in cases like web server in infinite loop. When HEALTHCHECK is specified, it has a health status in addition to normal status. There can be only one HEALTHCHECK instruction in a Dockerfile. If multiple are mentioned, only the last one is taken into consideration. The health statuses can be:
-
startinginitial stage -
healthywhen health check passes -
unhealthyafter a certain number of consecutive failures
The options that can appear before CMD are:
-
--interval=DURATION(default 30s) [frequency of running the checks] -
--timeout=DURATION(default 30s) [how much time to wait before a check is considered failed] -
--start-period=DURATION(default 0s) [initialization time for containers that need time to bootstrap] -
--retries=N(default 3) [consicutive failures to consider the containerunhealthy]
The command after the CMD keyword can be either a shell command (HEALTHCHECK CMD /bin/check-running) or an exec array (similar to ENTRYPOINT). Example
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
To debug failing probes, all output of the command are stored in health status and can be queried with docker inspect command. When the health status changes, a health_status event is triggered with new status.
SHELL instruction
This instruction allows the default shell to be overridden. The default shell on Linux is ["/bin/sh", "-c"] and on Windows is ["cmd", "/S", "/C"]. This command is particularly important for Windows because a user can choose between: cmd, powershell and sometimes sh. This can appear multiple times and each time it overrides the previous ones. Example:
SHELL ["/bin/sh", "-c"]
SHELL ["cmd", "/S", "/C"]
SHELL ["powershell", "-command"]
External Implementation and BuildKit
Starting from 18.09, Docker supports a new backend for building images, which is provided by moby/buildkit. There are some additional features that comes with this BuildKit. The documentation for this can be found here.
Reference
- Official Dockerfile reference - https://docs.docker.com/engine/reference/builder/
- BuildKit - https://github.com/moby/buildkit
Top comments (0)