Dockerfile
The Dockerfile contains special instructions, which tell the Docker Engine about the steps required to build an image. To invoke a build using Docker, you issue the Docker build
command.
A typical Dockerfile looks like this:
1 | FROM ubuntu:latest |
Build Context
A build context is a file or set of files available at a specific path or URL. To understand this better, we might have some supporting files that we need during a Docker image build—for instance, an application specific config file that was been generated earlier and needs to be part of the container.
The build context can be local or remote—we can even set the build context to the URL of a Git repository, which can come in handy if the source files are not located on the same host as the Docker daemon or if we’d like to test out feature branches.
- Build docker via a specific branch
docker build https://github.com/sathyabhat/sample-repo.git#mybranch
- Build docker via a pull request
docker build https://github.com/sathyabhat/sample-repo.git#pull/1337/head
The build command sets the context to the path or URL provided, uploading the files to the Docker daemon and allowing it to build the image.
Dockerignore
The ignore list is provided by a file known as .dockerignore and when the Docker CLI finds this file, it modifies the context to exclude the files/patterns provided in the file. Anything starting with a hash (#) is considered a comment and ignored.
Example .dockerignore
file1
2
3*/temp*
.DS_Store
.git
Build with docker build
- In a folder, create
dockerfile
. - Run
docker build .
Will build according to the instructions in the dockerfile. - Run docker image
docker run <image-id>
- Tag an docker image
docker tag <image_id> <tag_name>
- Run with tag
docker build -t <tag_name> .
- Search for image by tag
docker images <image-tag>
- Run with tag
Dockerfile Instructions
FROM
The FROM
instruction tells the Docker Engine which base image to use for subsequent instructions. Every valid Dockerfile must start with a FROM instruction.
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
WORKDIR
WORKDIR
instruction sets the current working directory for RUN
, CMD
, ENTRYPOINT
, COPY
, and ADD
instructions.
WORKDIR /path/to/directory
WORKDIR can be set multiple times in a Dockerfile and, if a relative directory succeeds a previous WORKDIR instruction, it will be relative to the previously set working directory.
1 | FROM ubuntu:latest |
ADD and COPY
ADD
and COPY
allow you to transfer files from the host to the container’s filesystem. Copy
supports basic copying of files to the container, while ADD
has support for features like tarball auto extraction and remote URL support.
ADD <source> <destination>
COPY <source> <destination>
i.e. Moving the requirements.txt
file from the current working directory to the /usr/share/app
directory.
ADD requirements.txt /usr/share/app
COPY requirements.txt /usr/share/app
RUN
The RUN
instruction will execute any commands in a new layer on top of the current image and create a new layer that is available for the next steps in the Dockerfile.
1 | RUN <command> (known as the shell form) |
Docker recommends chaining multiple RUN commands into a single command.
1 | RUN apt-get update && apt-get install -y \ |
This reduces the number of layers and makes for a leaner Docker image.
CMD and ENTRYPOINT
1 | CMD ["executable","param1","param2"] (exec form) |
Difference between CMD and RUN: CMD will only execute after a container starts running.
CMD
is usually the last instruction in the dockerfile.
i.e.1
2
3
4
5FROM ubuntu:latest
RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*
CMD curl
In this Docker image, we select Ubuntu as the base image, install curl on it, and choose curl as the CMD instruction. This means that when the container is created and run, it will run curl without any parameters.
docker run sathyabhat:curl curl -s wttr.in
We can set ENTRYPOINT to the executable while the parameter can be passed from the command line and will be overridden.
1 | FROM ubuntu:latest |
docker run sathyabhat:curl wttr.in
ENV
The ENV instruction sets the environment variables to the image. The ENV instruction has two forms:
1 | ENV <key> <value> # the entire string after the <key> will be considered the value, including whitespace characters. |
i.e.1
2
3FROM ubuntu:latest
ENV LOGS_DIR="/var/log"
ENV APPS_DIR /apps/
The environment variables defined for a container can be changed when running a container by the -e flag.
docker run -it -e LOGS_DIR="/logs" sathyabhat:env-example
VOLUME
The VOLUME
instruction tells Docker to create a directory on the host and mount it to a path specified in the instruction.
VOLUME /var/logs/nginx
EXPOSE
The EXPOSE
instruction tells Docker that the container listens for the specified network ports at runtime.
i.e. Expose port 80:EXPOSE 80
EXPOSE 53/tcp
EXPOSE 53/udp
An EXPOSE
instruction doesn’t publish the port. For the port to be published to the host, you need to use the -p flag when you do a docker run to publish and map the ports.
docker run -d -p 8080:80 sathyabhat:web
The -d
flag makes the nginx container run in the background; the -p
flag does the port mapping.
LABEL
The LABEL instruction adds metadata to an image as a key/value pair. LABEL <key>=<value> <key>=<value> <key>=<value> ...
.
For the Dockerfile, we should minimize the number of layers. As of Docker 1.10 and above, only RUN
, COPY
, and ADD
instructions create layers.
A Project Dockerfile Example
What we need:
- A Docker image based on Python3
- The project dependencies listed in
requirements.txt
- An environment variable named
NBT_ACCESS_TOKEN
Dockerfile should do:
- Start with a proper base image
- Make a list of files required for the application
- Make a list of environment variables required for the application
- Copy the application files to the image using a
COPY
instruction - Specify the environment variable with the
ENV
instruction
1 | FROM python:3-alpine |