Dockerfile cheat sheet

Maciej
6 min readMar 1, 2020

--

Overview

DockerfileInstructions are summarized.

  • Docker version: v19.03

Simplified chart

FROM

Acquire by specifying the base image. The first line is this command. Specify an image from Docker Hub or a private Docker repository.

  • No tag specified: latestpull

Dockerfile

FROM centos:7.7.1908
ENTRYPOINT [ "/bin/bash" ]
$ docker image build --file Dockerfile -t testrepo:test .
$ docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
REPOSITORY TAG SIZE
testrepo test 204MB # < -The image created this time
centos 7.7.1908 204MB # < -Base image
  • Tag specified: Pull with specified tag, basically should be specified

Dockerfile

FROM centos
ENTRYPOINT ["/bin/bash"]
$ docker image build --file Dockerfile -t testrepo:test .
$ docker image ls --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
REPOSITORY TAG SIZE
Testrepo Test 220MB # <- created this time the image
Centos Latest 220MB # <- based image

RUN

Execute the specified command. It is described later in Tips, but should be described together as much as possible.

Dockerfile

FROM centos:8
RUN yum install -y httpd iproute && \
echo "Test" > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/httpd"]

ENTRYPOINT / CMD

Specifies the command to be executed when the container is started. An image that is written once at the end of the Dockerfile.

Dockerfile

FROM centos:8ENTRYPOINT ["df"]
CMD ["-H", "."]

Specify the command to be specified by separating each space with a comma. For example go run main.go, if you want to specify:

Dockerfile

ENTRYPOINT ["go", "run", "main.go"]

Difference between ENTRYPOINT and CMD

ENTRYPOINTIs always executed as is,CMDcan be overwritten by specifying an argument when starting the container. Taking advantage of this property, you can write the ENTRYPOINTcommand part CMDand the command option part. Assuming that the image is built with the above Dockerfile, the difference between the concrete execution results when starting the container with arguments and when starting the container without arguments is shown below.

  • No argument: df -H .is executed.
$ docker run override_test
Filesystem Size Used Avail Use% Mounted on
overlay 63G 2.1G 58G 4% /
  • With argument ( --help): df --helpis executed. You can see that the CMD part is overwritten by the options specified on the command line.
$ docker run docker_test --help
Usage: df [OPTION]... [FILE]...
Show information about the file system on which each FILE resides,
or all file systems by default.
Mandatory arguments to long options are mandatory for short options too.
-a, --all include pseudo, duplicate, inaccessible file systems

COPY

Copy a file or directory from the host machine into the container. Directory structure of host machine

.
├── Dockerfile
├── copied
│ ├── subfile.txt
│ └── subfile2.txt
└── copyfile.txt

Dockerfile

FROM centos:latestRUN mkdir  -p / app
# file unit
COPY ./copyfile.txt / app
# directory * It is necessary to specify the directory name of the copy destination.
COPY ./copydir / app / subdir
$ docker image build --file Dockerfile -t centos:copytest .
$ docker container run centos:copytest ls -ltR /app
/app:
total 8
drwxr-xr-x 2 root root 4096 Jan 12 13:27 subdir
-rw-r--r-- 1 root root 6 Jan 12 13:18 copyfile.txt
/app/subdir:
total 4
-rw-r--r-- 1 root root 0 Jan 12 13:25 subfile2.txt
-rw-r--r-- 1 root root 8 Jan 12 13:19 subfile.txt

ADD

COPYSimilarly, copy the file from the host machine into the container. (Above Dockerfile of COPYthe ADDwill be the same result as) However, ADDwhen you use the, if the copy file is a compressed file, will be performed automatically decompress.

Dockerfile

FROM centos:8RUN mkdir  -p /app
# addtest.tar is a compressed file of
copydir ADD ./addtest.tar/app

Terminal

$ docker image build --file add/Dockerfile -t centos:addtest .
$ docker container run centos:addtest ls -lR /app
/app:
total 4
drwxr-xr-x 2 501 games 4096 Jan 12 13:25 copydir
/app/copydir:
total 4
-rw-r--r-- 1 501 games 8 Jan 12 13:19 subfile.txt
-rw-r--r-- 1 501 games 0 Jan 12 13:25 subfile2.txt
# There is no tar file itself and decompression Existed

ef COPY the case of

Terminal

$ docker container run testrepo:copy ls -lR /app
/app:
total 4
-rw-r--r-- 1 root root 177 Jan 12 13:31 addtest.tar # leave the compressed file

Separation from COPY

  • When copying is simply performed => COPY
  • To copy and decompress => ADD

ENV

Add environment variables to the execution container.

Dockerfile

FROM centos:8
ENV NEW_ENV='env-value'
ENTRYPOINT ["/bin/bash"]

Terminal

$ docker image build --file Dockerfile -t centos:envtest .
$ docker container run -it centos:envtest
[root@de6dc0f2577e /]# env
LANG=en_US.UTF-8
HOSTNAME=de6dc0f2577e
NEW_ENV=env-value # fileで追加した環境変数

EXPOSE

Put the specified port in the LISTEN state.

Dockerfile

FROM python:3.8-slim-busterCOPY . /
RUN pip install -r /app/requirements.txt
EXPOSE 9876
ENTRYPOINT [ "gunicorn", "flask_app:app" ]
CMD [ "-c", "/app/config/gunicorn_settings.py" ]

Terminal

$ docker image build --file Dockerfile -t python:flask .
$ docker container run --name exposetest python:flask
$ docker container ps --format "table {{.Image}}\t{{.Ports}}"
IMAGE PORTS NAMES
flask 9876/tcp exposetest
a2556b3a812 worktest
# LISTENED port number is displayed in PORTS

WORKDIR

Change working directory. In Dockerfilecd

Dockerfile

FROM centos:8
RUN mkdir -p /test
RUN echo "before workdir" > before.txt
WORKDIR /test
RUN echo "after workdir" > after.txt
ENTRYPOINT ["/bin/bash"]

Terminal

$ docker image build --file Dockerfile -t centos: workdir . 
$ docker container run -it --name workdirtest centos: workdir
[ root @ 4cd5accab742 test ] # pwd
/ test # The last WORKDIR path is the base path for starting the container to become
[ root Atto 4Cd5accab742 Test ] # Ls .. | Grep before
Before.Txt # before the presence in the root directory that you have created before WORKDIR
[ root Atto 4Cd5accab742 Test ] . # Ls
After.Txt # for after is created after WORKDIR Exists in the / test directory

Tips

Light weight with multi-stage build

A multi-stage build is like a technique to reduce the weight of the final finished image. As an example, Golet's compare the image size between when the application is applied with multi-stage build and when it is not.

  • No multi-stage build

Dockerfile

FROM golang:1.13-alpine
COPY ./main.go ./
RUN go build -o /app ./main.go
ENTRYPOINT ["/app"]
  • Multi-stage build available

Dockerfile

# 1st step (build) 
FROM golang: 1.13-alpine as builder
COPY ./main.go ./
RUN go build -o / app ./main.go
# Second stage (this is the completed image)
# Select a lightweight image that meets the minimum requirements for the base
FROM alpine: 3.11
# Copy the required items from the first stage container
COPY --from = builder / app.
ENTRYPOINT [" ./app "]
  • Check size

Terminal

REPOSITORY     TAG                 SIZE
golang nonmultistage 361MB
golang multistage 7.6MB # overwhelmingly light

Combine instructions as much as possible

An image cache is built for each Dockerfile instruction. Minimizing this number of image cache layers is considered a best practice, which can result in lighter weight and faster builds. Specifically, perform the following actions.

  • RUN instructions are connected by “backslash + &&”
  • Keep COPY / ADD instructions as small as possible

In particular, RUNthere is a problem with the cache at the time of build, yum updateand if you do not connect them with yum installthe &&word , you may get stuck. (The cache is not described in this article.)

URL can be specified in ADD instruction, but it is not written

Use curlor when retrieving resources from a URL in order to reduce the number of layers and reduce the image weight wget.

Example ( excerpt from Best practices )

Dockerfile

# Good
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
# Bad
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all

Reference

--

--

Maciej
Maciej

Written by Maciej

DevOps Consultant. I’m strongly focused on automation, security, and reliability.