Dockerfile Cheat Sheet
Dockerfile Examples
Installing packages
FROM debian:jessie
ENV DEBIAN_FRONTEND=noninteractive # Always have this on Debian-based distros!
# Always
# - combine update + install to avoid apt caching issues!
# - disable recommends to get no extra packages!
# - clean lists afterwards
RUN apt-get update \
&& apt-get install -y --no-install-recommends python git
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Copy files
COPY sourcefile.txt /app
COPY sourcefile.txt config.ini /app/ # Note the trailing slash on target with multiple files
COPY dir1 /app
Adding users
RUN useradd jsmith -u 1001 -s /bin/bash
Defining work directories and environment
WORKDIR /home/jsmith/
ENV HOME /home/jsmith
Mounts
VOLUME ["/home"]
Opening ports
EXPOSE 22
EXPOSE 80
Start command
USER jsmith
WORKDIR /home/jsmith/
ENTRYPOINT bin/my-start-script.sh
Start command with parameters
ENTRYPOINT [ "script.sh", "param1", "param2"] # using ENTRYPOINT command cannot be overridden, only parameters can be appended
CMD [ "script.sh", "param1", "param2"] # using CMD "docker run" can override command and parameters
ENV TZ=America/Los_Angeles
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
Using variables
RUN curl $JAR_DOWNLOAD
...
CMD java ${JAVA_OPTS} ...
Pass those variables using --build-arg JAR_DOWNLOAD=... --build-arg JAVA_OPTS="-D..."
For longer commands use CMD array syntax
CMD [ "java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", <...>]
Ensure pipe errors to break the build
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
Clear apt cache
RUN apt-get update \
&& apt-get install --no-install-recommends -y <packages> \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Working with private registries
In Dockerfile use syntax with /
FROM <server>/<image>:<tag>
Define a variable registry in FROM clause and pass the hostname with --build-arg MY_REGISTRY=docker.example.com
ARG MY_REGISTRY=
FROM ${MY_REGISTRY}/myimage
Multi-stage Dockerfiles
Starting with Docker 17.05 you can do multi-stage builds by having multiple FROM commands in one Dockerfile
FROM image1
...
FROM image2
...
Above syntax example will automatically trigger two builds. Stages also can be named:
FROM image1 as stage1
and explicitely called on the CLI
docker build --target stage1 ...
Hardening Dockerfiles
Things you should do
- Ensure there is a .dockerignore file in your base directory
- Ensure there is a USER statement
- Ensure there is a HEALTHCHECK statement (for non-k8s use cases)
- Check FROM clause for trusted base images
- Check curl/wget fetching from trusted domains only
- Check your base image limits typical package managers (Python, Node, Maven…) to trusted repositories
In the end: firewall your build environment to avoid all unintended internet access