Cheatsheet - Dockerfile
A Dockerfile is a text file that contains all the commands a user could call on the command line to assemble an image. It acts as a blueprint for building Docker images.
1. FROM
- Purpose: Defines the base image for your new image. Every Dockerfile must start with
FROM
. - Syntax:
FROM <image>[:<tag>]
- Example:
- Ubuntu:
FROM ubuntu:22.04
- Node LTS version:
FROM node:lts-slim
- Ubuntu:
- Tip: Use a specific tag (e.g.,
22.04
) instead oflatest
for consistent builds.
2. LABEL
- Purpose: Adds metadata to an image. This can include information like maintainer, version, or description.
- Syntax:
LABEL <key>=<value> [<key>=<value>...]
- Example:
LABEL maintainer="John Doe <[email protected]>" version="1.0" description="My Awesome App"
- Tip: Useful for documentation and organizing images.
3. RUN
- Purpose: Executes commands in a new layer on top of the current image and commits the results. Used for installing packages, creating directories, etc.
- Syntax:
RUN <command>
(shell form, default:/bin/sh -c
on Linux)RUN ["executable", "param1", "param2"]
(exec form, preferred for clarity and avoiding shell string processing)
- Example (shell form):
RUN apt-get update && apt-get install -y git build-essential
- Example (exec form):
RUN ["/bin/bash", "-c", "echo Hello && echo World"]
- Tip: Chain multiple
RUN
commands with&&
and use\
for readability to reduce image layers.
4. WORKDIR
- Purpose: Sets the working directory for any
RUN
,CMD
,ENTRYPOINT
,COPY
, andADD
instructions that follow it. - Syntax:
WORKDIR /path/to/workdir
- Example:
WORKDIR /app COPY . . # Copies content to /app in the image
- Tip: Use
WORKDIR
to keep your Dockerfile clean and avoid absolute paths in subsequent commands.
5. COPY
- Purpose: Copies new files or directories from the host machine (
<src>
) to the filesystem of the container at path<dest>
. - Syntax:
COPY <src>... <dest>
- Example:
COPY ./src /app/src COPY requirements.txt /app/
- Tip: Preferred over
ADD
for copying local files as it's more transparent.
6. ADD
- Purpose: Similar to
COPY
but has additional features:- Can extract tar files from
<src>
(local or remote URL). - Can accept a URL for
<src>
.
- Can extract tar files from
- Syntax:
ADD <src>... <dest>
- Example (local tar):
ADD app.tar.gz /app/
- Example (remote URL):
ADD http://example.com/latest.zip /app/
- Tip: Use
COPY
unless you specifically need the tar extraction or URL download features ofADD
.
7. EXPOSE
- Purpose: Informs Docker that the container listens on the specified network ports at runtime. This is purely for documentation and doesn't actually publish the port.
- Syntax:
EXPOSE <port> [<port>...]
- Example:
EXPOSE 80 443
- Tip: To actually publish ports, use the
-p
or--publish
flag withdocker run
.
8. ENV
- Purpose: Sets environment variables. These variables persist when a container is run and can be accessed by applications inside the container.
- Syntax:
ENV <key>=<value> [<key>=<value>...]
- Example:
ENV NODE_ENV=production PORT=3000
- Tip: Can be overridden with
docker run -e <key>=<value>
.
9. ARG
- Purpose: Defines a variable that users can pass at build-time to the builder using
docker build --build-arg <varname>=<value>
. - Syntax:
ARG <name>[=<default value>]
- Example:
ARG BUILD_VERSION=1.0 RUN echo "Building version: $BUILD_VERSION"
- Tip:
ARG
variables are not available after the image is built, unlikeENV
.
10. VOLUME
- Purpose: Creates a mount point with the specified name and marks it as holding externally mounted volumes from the native host or other containers.
- Syntax:
VOLUME ["/data"]
orVOLUME /data
- Example:
VOLUME /var/log/app
- Tip: Use volumes to persist data generated by and used by Docker containers, especially for database files or logs.
11. USER
- Purpose: Sets the user name or UID to use when running the image and for any
RUN
,CMD
, andENTRYPOINT
instructions that follow it. - Syntax:
USER <user>[:<group>]
- Example:
USER appuser
- Tip: Running containers as a non-root user is a security best practice.
12. HEALTHCHECK
- Purpose: Tells Docker how to test a container to check if it is still working.
- Syntax:
HEALTHCHECK [OPTIONS] CMD command
- Example:
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl -f http://localhost/ || exit 1
- Tip: Essential for robust container orchestration (e.g., Kubernetes) to determine container readiness.
13. ENTRYPOINT
- Purpose: Configures a container that will run as an executable. It defines the command that will always be executed when the container starts.
- Syntax:
ENTRYPOINT ["executable", "param1", "param2"]
(exec form, preferred)ENTRYPOINT command param1 param2
(shell form)
- Example (exec form):
ENTRYPOINT ["/usr/bin/supervisord", "-n"]
- Tip: Often used in conjunction with
CMD
to provide default arguments to theENTRYPOINT
.
14. CMD
-
Purpose: Provides defaults for an executing container. There can only be one
CMD
instruction in a Dockerfile. -
Syntax:
CMD ["executable","param1","param2"]
(exec form, as the main command)CMD ["param1","param2"]
(as default arguments toENTRYPOINT
)CMD command param1 param2
(shell form)
-
Example (with ENTRYPOINT):
ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"] # Default arguments for nginx
-
Example (without ENTRYPOINT):
CMD ["python", "app.py"]
-
Tip: When
ENTRYPOINT
is defined,CMD
provides the default arguments for it. IfENTRYPOINT
is not defined,CMD
provides the default command to execute. Thedocker run
command line arguments will overrideCMD
.
CMD vs ENTRYPOINT
Both CMD
and ENTRYPOINT
instructions define what command gets executed when running a container. There are few rules that describe their co-operation.
- Dockerfile should specify at least one of
CMD
orENTRYPOINT
commands. ENTRYPOINT
should be defined when using the container as an executable.CMD
should be used as a way of defining default arguments for anENTRYPOINT
command or for executing an ad-hoc command in a container.CMD
will be overridden when running the container with alternative arguments.
Dockerfile Best Practices:
- Order matters: Place instructions that change less frequently at the top to leverage Docker's build cache.
- Minimize layers: Combine
RUN
commands where possible using&&
and\
for efficiency. - Remove unnecessary files: Clean up temporary files, caches (
apt-get clean
,rm -rf /var/lib/apt/lists/*
) to keep image size small. - Use
.dockerignore
: Exclude files and directories not needed in the image (like.git
,node_modules
,*.log
). - Run as non-root: Create a dedicated user and group for your application for security.
- Specific tags: Always use specific version tags for base images instead of
latest
.
Example: Containerize a Node app
Use this Dockerfile
template:
# node
FROM node:12-slim
# the path inside the container
WORKDIR /usr/src/app
# copy the package.json and package-lock.json, and install dependencies
COPY package*.json ./
RUN npm install
# copy all the source code
COPY . .
# port
EXPOSE 8080
# run the command inside the container
CMD [ "node", "app.js" ]
And add a .dockerignore
file:
Dockerfile
.dockerignore
node_modules
npm-debug.log
What is || : &&
|| : &&
creates a conditional execution flow:
- The command before
||
is executed. - If it succeeds, the
|| :
part is skipped, and the command after&&
is executed. - If it fails, the
|| :
part is executed (doing nothing), and then the command after && is executed regardless.
This pattern is often used to ensure that subsequent commands in a RUN instruction are always executed, even if a previous command fails. This is useful for tasks like cleaning up or setting up configurations that should happen regardless of earlier failures.
RUN apt-get update || : && apt-get install -y --no-install-recommends some-package