Skip to content

Dockerfile

A Dockerfile is a text file that contains a set of instructions to automate the creation of Docker images. It defines how an image should be built, including its base image, dependencies, configurations, and runtime commands.

The default filename for a dockerfile is Dockerfile without a file extension. But you can specify custom Dockerfile filename using:

sh
docker build --file <something>.Dockerfile .

Example of a Dockerfile:

dockerfile
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
COPY app/ /app/
WORKDIR /app
ENV APP_ENV=prod
CMD ["python3", "app.py"]

Each command in a Dockerfile, that modifies the filesystem, will result in a new layer. However, not all Dockerfile commands alter the filesystem.

Commands that create layers

These commands alter the filesystem and therefore create new layers:

  • RUN – Executes a command inside the container and commits the changes.
  • COPY – Copies files from the host to the container image.
  • ADD – Similar to COPY, but also supports fetching files from URLs and automatically extracting compressed archives.

Commands that don't create layers

These commands modify metadata but do not change the filesystem, so they don't create new layers:

  • ENV – Sets environment variables.
  • WORKDIR – Sets the working directory for subsequent instructions.
  • CMD – Sets the default command, that runs when a container starts, for the container.
    • You can specify this in shell or exec form:
      • CMD ["executable","param1","param2"] (exec form)
      • CMD ["param1","param2"] (exec form, as default parameters to ENTRYPOINT)
      • CMD command param1 param2 (shell form)
    • There can only be one CMD instruction in a Dockerfile. If you list more than one, only the last one takes effect.
  • ENTRYPOINT – Defines the main command, that always runs when a container starts, for the container. Unlike CMD, which can be easily overridden, ENTRYPOINT is meant to be fixed, ensuring that the container behaves like a dedicated executable.
    • You can however override it, using --entrypoint flag of docker run.
  • EXPOSE – Declares which ports the container listens on (but doesn't actually open them). You must explicitly publish them when running the container using docker run command with option -p or -P.
  • LABEL – Adds metadata to the image. This metadata consists of key-value pairs that provide useful information about the image, such as its author, description, version, license, and more.
  • USER – SSets the default user for all subsequent instructions.
  • VOLUME – Declares a mount point for persistent external storage, allowing data to survive container restarts and be shared across multiple containers.

For a full list of Dockerfile commands, refer to the Official Documentation.

Shell and Exec form

The RUN, CMD, and ENTRYPOINT instructions all have two possible forms:

Exec Form (JSON array syntax)

dockerfile
INSTRUCTION ["executable","param1","param2"]

Exec form uses a JSON array syntax, which means each element must be wrapped within double-quotes (""). Each element in the array represents a command, flag, or argument.

Exec form doesn't automatically invoke a command shell. This means that normal shell processing, such as variable substitution, doesn't happen. For example, RUN [ "echo", "$HOME" ] won't handle variable substitution for $HOME.

Additionally, in exec form, you must escape backslashes. This is particularly relevant on Windows where the backslash is the path separator:

dockerfile
RUN ["c:\\windows\\system32\\tasklist.exe"]

Shell Form (regular command syntax)

dockerfile
INSTRUCTION command param1 param2

Unlike the exec form, instructions using the shell form always use a command shell. The shell form doesn't use the JSON array format, instead it's a regular string.

The shell form string lets you escape newlines using the backslash escape character.

dockerfile
RUN source $HOME/.bashrc && \
echo $HOME

Here Docs

You can also use heredocs with the shell form to break up supported commands.

dockerfile
RUN <<EOF
source $HOME/.bashrc && \
echo $HOME
EOF

TBD (Here Docs - https://docs.docker.com/reference/dockerfile/#here-documents)

.dockerignore file

A .dockerignore file is used to exclude files and directories during the image build process. It works similarly to .gitignore, improving build speed and reducing image size by excluding unnecessary files.

For example, if you don't want to copy node_modules and .env into the container, you can define .dockerignore file as follows:

shell
node_modules/
.env