4. Docker Dockerfile

4.1. Write a Dockerfile

Dockfile instructs how to construct a docker image.

Typically, the docker file can be split into three parts

  • Base node specifications

  • Configuration of the image

  • Post progresses after the configuration

4.1.1. Base Node Specifications

Each image is based on a parent image, something like the inheritance in OOP. For instance, if your system is based on ubuntu, than pick a ubuntu node as a parent image. If you want a nginx server, than pick a pre-configured nginx node.

The syntax is pretty simple, use keyword FROM and follow with the node name. If you don’t specify a tag, by default it will be the latest node, e.g.

# based on nginx's latest node
FROM nginx

# based ubuntu
FROM ubuntu:15.10

# debian
FROM debian:bullseye

# centos
FROM centos

4.1.2. Configuration of the image

You need to execute some commands to configure the image based on your specified parent image. Typically, this step contains lots of bash commands. The syntax is

# you can write
RUN ["cmd", "parameter1", "parameter2", ...]

# you can also write

RUN cmd parameter1 parameter2

For the cp command, it can copy the file or directory from your host machine to the container. For instance,

# copy a local file test.py to the container's root directory
RUN cp test.py ~/

4.1.3. Post progresses after the configuration

This step following syntaxes no difference from the configuration step. I think it to be useful to separate out because you would like to run some service at this step, such running the nginx server in the container. In this step, we will use CMD rather than RUN.

# an example of running django server after build
CMD python3 manage.py runserver
  • RUN execute when building the image

  • CMD execute when running the container. It can be override if you specify another command when calling docker run.

Suppose the last line of your dockerfile is CMD echo "hello", but you use the following code to run the docker image

docker run -t myimage echo "hello world"

CMD echo "hello" won’t be called, instead, echo "hello world" will be called. You can use docker container ls -a to view the last command the container ran.

  • ENTRYPOINT is another command that you can specify the command to be ran when running the container, but it’s commonly recognized that if you specify the ENTRYPOINT, it means the user should better not to override the starting program.

  • Trick

CMD can pass parameters/flags to ENTRYPOINT. For instance, the following four styles are equivalent.

# style one
CMD ["--flag1", "param1", "--flag2"]
ENTRYPOINT ["command"]

# style two
ENTRYPOINT ["command", "--flag1", "param1", "--flag2"]

# style three
CMD ["command", "--flag1", "param1", "--flag2"]

# style four
CMD command --flag1 param1 --flag2

4.1.4. Other Useful commands

  • ENV Create an environment variable

# ENV <key> <value>
ENV VERSION_ID 1.0.0
  • ARG Create a local variable. Similar to ENV but is effective only in the dockerfile

# ARG <key> <value>
ARG TEMP_PATH ~/Workspace

#ARG <key>
ARG IN_MEMORY
  • VOLUME Specify the docker data volume to mount. This command requires the creation of a data volume. We will introduce it later.

VOLUME ['volume name1', 'volume name 2']

When we run the container, we can use -v to change the mount point.

  • EXPOSE Purely a declaration of ports to use. When using -P to randomly map the port during docker run, random port(s) will be mapped automatically to the declared port(s)

EXPOSE <port1> [<port2> <port3>...]
  • USER Specify the existing user and usergroup to run the following commands.

USER <username>[:<usergroup>]
  • ONBUILD Won’t be called in this build operation, but will be called when it was created by a child node.

ONBUILD <some commands>
  • LABEL Create some key-value pairs, e.g. author

LABEL <key>=<value>

4.1.5. Example of a Dockerfile

We present an example docker file that

# Build based on ubuntu:18.04
FROM ubuntu:18.04

# create a environment variable named "VERSION_ID" with key "1.0.0"
ENV VERSION_ID 1.0.0

# Just to let you know how to run a command in the container
RUN sudo apt-get update
RUN sudo apt-get install python3 -y

# Switch the working directory. Something like "cd"
WORKDIR ~/Workspace

# Copy a local file to the specified working directory
# Practially, you may copy some source codes to the container
COPY django-project/ .

# Create an output
RUN echo "hello world" > output.txt

# specify the command to run if a container is running
CMD python3 manage.py runserver

4.2. Create a Container from Dockerfile

The operation of creating a container from a dockerfile is called build. Since the command is simple, we will show several commonly used command to build a container

# use a file named either "Dockerfile" or "docker"
# the image name and tag will be "<none>"
docker build .

# specify the image to be "myimage" and tag to be "v1.0"
docker build -t myimage:v1.0 .

# specify the dockerfile to be "customDockerFile"
docker build -t myimage:v1.0 --file customDockerFile .

# build without using the cache (useful if you have built multiple times)
docker build --no-cache -t myimage:v1.0 .

4.3. Copy Files to Host After Build

For some applications, you may want to copy the output from the container to the host machine after running some programs. You can follow the step in Docker Interactions Here, we introduce how to write a Copy command in dockerfile.

The general idea is to split the building process into two stages.

  1. Build the docker file that will generate the output.

  2. Instantialize the docker container and execute the copy command

# Codes in the dockerfile

# Build based on ubuntu:18.04
# Give it a nickname of our image as testimg1 because we will use it later
FROM ubuntu:18.04 AS testimg1

WORKDIR ~/TEST
RUN echo "hello world" > output.txt

# Copy the output to local directory
FROM scratch AS stage2
COPY --from=stage1 ~/TEST/output.txt .

After generating the dockerfile, we execute the following command in the host machine to create and then acquire the output

docker build --file dockerfile --output out .

--output out specifies the output path to be out