Dockerfile

Dockerfile is a text file that contains instructions on how to build a custom image.

A very simple Dockerfile for Springboot app

1
2
3
4
FROM openjdk:8-jre-alpine
EXPOSE 8080
COPY /target/myApp.jar myApp.jar
ENTRYPOINT ["java","-jar","myApp.jar"]

A Dockerfile for Python app. see Get Started, Part 2: Containers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Building Image using Dockerfile

docker build command builds an image from a Dockerfile and context. Docker Image is consist of read-only layers. Each instruction in a Dockerfile creates one layer on top of the previous layer.

Syntax

1
docker build -t image_name directory_path

The build’s context is the set of files at a specified location PATH or URL. The PATH is a directory on your local filesystem. The URL is a Git repository location.

The build is run by the Docker daemon, not by CLI. the context(except for the files and directory exclude by .dockerignore file) is send to the daemon.

Example to build testimage:v1 using ./testapp as the context

1
docker build -t testimage:v1 ./testapp

Use -f option to specify Dockerfile location if Dockerfile is not at the top of the context

1
docker build -f testapp/dockerfiles/Dockerfile.debug -t testimage:v1 ./testapp

Dockerfile Format

Comments starts with ‘#’

use backslash() as the escape character.

A Dockerfile usually start with a form instruction.

Environment Variable

You can get the value of an Environment variable with $variable_name or ${variable_name}

You can escape string starts with $ by adding a \ before the $.

Environment variables are supported by the following list of instructions:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • FROM
  • LABEL
  • STOPSIGNAL
  • USER
  • VOLUME
  • WORKDIR

FROM

Syntax

1
FROM <image>[:<tag>]

The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions.

example:

1
2
3
FROM httpd:2.4
FROM centos:latest
FROM openjdk:8-jre-alpine

COPY & ADD

The COPY and ADD instruction copies files and folders from host to the image we’re building. ADD is more powerful, it can unpack tar archive and download from URL and copy to the building image.

example

1
2
COPY index.html /var/www/html/
COPY *.html /var/www/html/

Best practice is to use COPY when copying local files to Docker image because it is more explicit. Use ADD only for tar files and download from URLs.

WORKDIR

sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.
The WORKDIR instruction can be used multiple times in a Dockerfile.

1
2
3
4
RUN mkdir -p /path/to/workdir
WORKDIR /path/to/workdir
RUN pwd # will print /path/to/workdir

Do not use RUN cd /path/to/workdir. It has no effect on the image filesystem

RUN

Commonly used instruction. The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. RUN instruction is often used to install software packages.

You can have many RUN instructions in a Dockerfile.

Syntax

1
2
RUN <command>
RUN ["executable", "param1", "param2"]

example

1
2
RUN apt-get update \ 
&& apt-get install -y wget

CMD & ENTRYPOINT

Both CMD and ENTRYPOINT can be used to start a process. They are very similar. Both CMD and ENTRYPOINT has two forms, shell form and exec form.

Two forms of ENTRYPOINT

  • ENTRYPOINT command param1 param2 (shell form)
  • ENTRYPOINT [“executable”, “param1”, “param2”] (exec form, preferred)

Shell format example

1
2
FROM alpine
ENTRYPOINT echo "Hello Docker"

exec form example

1
2
FROM alpine
ENTRYPOINT ["/bin/echo", "Hello Docker"]

CMD provide defaults for an executing container. command line arguments will override CMD instruction.

Three forms of CMD

  • CMD command param1 param2 (shell form)
  • CMD [“executable”,”param1”,”param2”] (exec form, this is the preferred form)
  • CMD [“param1”,”param2”] (as default parameters to ENTRYPOINT, ENTRYPOINT must use exec form in this case)

Shell form example

1
2
FROM alpine
CMD echo "Hello Docker"

exec form example

1
2
FROM alpine
CMD ["/bin/echo", "Hello Docker"]

CMD and ENTRYPOINT can interact. When both instruction are presented,
CMD defines default arguments for an ENTRYPOINT instruction.

Example

1
2
3
4
FROM alpine

ENTRYPOINT ["ls" ]
CMD [ "-l", "/usr"]

CMD vs ENTRYPOINT

  • CMD sets default command. This command can be easily overriden from commandline
  • ENTRYPOINT is often used for a long running process. parameters passed to docker run will not override ENTRYPOINT instruction parameters
  • CMD is used to define a default command to execute. parameters passed to docker run will override CMD.

VOLUME

VOLUME defines a path in the container to the host. Host path can map to the container path using -v argument when runnning a cotnainer.

1
VOLUME ["/data/db"]

Volume allows us to add source and data to the image without commiting them to the image.

EXPOSE

The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. You can have multiple EXPOSE instruction in a Dockerfile

1
2
EXPOSE 80
EXPOSE 8080

By default, EXPOSE assumes TCP. You can also specify UDP

1
EXPOSE 80/udp

ARG

The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command. use --build-arg var=val option to pass these variables.

ARG instruction can have a default value.

An ARG instruction goes out of scope at the end of the build stage where it was defined.

1
2
3
FROM busybox
ARG buildno=0
RUN echo buildno is $buildno

to pass 123456 as argument

1
docker build --build-arg buildno=123456 .

Sample output

1
2
3
4
5
6
7
8
9
10
11
12
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox
---> 3a093384ac30
Step 2/3 : ARG buildno=0
---> Using cache
---> 92ad6cab8c44
Step 3/3 : RUN echo buildno is $buildno
---> Running in b290e1c97eec
buildno is 123456
Removing intermediate container b290e1c97eec
---> 815f540e2db8
Successfully built 815f540e2db8

ENV

The ENV instruction sets the environment variable. see Reference

syntax

1
2
ENV <key> <value>
ENV <key>=<value> ...

example

1
2
ENV foo /bar/baz
ENV foo=/bar/baz

You can also pass environment variable to container using -e flag

1
docker run -dit -e ENV_VAR_1='foo' -e ENV_VAR_2='bar' -p 80:80 --name test nginx:alpine

ENV vs ARG

Environment variable are available during the image build stage and when a container is launched from the image. ARG variables is ONLY available during the image build stage.

LABEL

label is a key-value pair.
syntax

1
LABEL <key>=<value> <key>=<value> <key>=<value> ...

example

1
2
3
LABEL version="1.0"
LABEL description="Some app description..."
LABEL maintainer="alicebob@example.com"

When you use docker inspect command to get the low level info for a container, you will get the labels for the containers

STOPSIGNAL

sets the signal to send to stop the container using docker stop command. The default signal is SIGTERM. If the main process doesn’t exit after a period of time, SIGKILL will be sent.

1
STOPSIGNAL SIGKILL

ONBUILD

syntax

1
ONBUILD [INSTRUCTION]

ONBUILD adds a trigger instruction to be executed when the image is used as the base for another build.

This is useful if you are building an image which will be used as a base to build other images

HEALTHCHECK

Tells Docker how to test a container to see if it is working.

syntax

1
HEALTHCHECK [OPTIONS] CMD command

example

1
2
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

SHELL

the SHELL instruction overrides the default shell. The default shell on Linux is ["/bin/sh", "-c"]. For windows, it is ["cmd", "/S", "/C"]

Example

1
2
3
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

Best practices

use this document for Dockerfile best practice

  • use .dockerignore file to filter out the files and directories not being used
  • Don’t install unnecessary package
  • Minimize layers used. Multi-stage build can be used to achieve that.
  • Leverage build cache. Cache can significantly reduce build time. If you don’t want to use cache, set parameter --no-cache-true

see this blog post for some useful Best practices

Tools

Docker Extension for VS Code provides syntax highlighting, commands, and linting for Dockerfile.

To Install, just search for Docker in VS Code extension tab. Then install the Docker extension from Microsoft.

Reference