Dockerfile Key Instructions and Best Practices

A guide to essential Dockerfile instructions including FROM, COPY, RUN, CMD, and ENTRYPOINT with syntax examples and usage differences explained.

A Dockerfile is a text file for automatically building Docker images. The instructions written in a Dockerfile are executed sequentially from top to bottom, ultimately creating a Docker image. Here, we explain the major instructions commonly used in Dockerfiles.

FROM

Specifies the base image. This must be the first instruction in the Dockerfile.

FROM <image_name>[:<tag>]
# Example: FROM ubuntu:22.04
# Example: FROM python:3.9-slim-buster

LABEL

Specifies image metadata. Written as key-value pairs, it can attach information about the image (author, version, description, etc.).

LABEL <key>="<value>" [<key>="<value>" ...]
# Example: LABEL maintainer="Your Name <your.email@example.com>"
# Example: LABEL version="1.0" description="My custom web app image"

USER

Specifies the user under which subsequent RUN, CMD, and ENTRYPOINT instructions are executed. The default is root. For security, it is recommended to specify a non-root user for operations that do not require privileges.

USER <username>[:<groupname>]
# Example: USER appuser

WORKDIR

Specifies the working directory for subsequent RUN, CMD, ENTRYPOINT, COPY, and ADD instructions. If specified as a relative path, it is relative to the previous WORKDIR instruction.

WORKDIR /path/to/workdir
# Example: WORKDIR /app

EXPOSE

Specifies the ports the container listens on. This serves as documentation; the docker run -p option is required to actually publish ports.

EXPOSE <port_number> [<port_number>/<protocol> ...]
# Example: EXPOSE 80
# Example: EXPOSE 8080/tcp 8080/udp

COPY

Copies files or directories from the host machine (the machine running the Docker daemon) into the container image.

COPY <host_path> <container_path>
# Example: COPY ./app /app
# Example: COPY requirements.txt /tmp/

ADD

Similar to COPY, but with the following additional features:

  • If host_path is a URL, it downloads the file and places it in the container.
  • If host_path is a compressed file (tar, gzip, bzip2, etc.), it is automatically extracted in the container.
ADD <host_path_or_URL> <container_path>
# Example: ADD https://example.com/app.tar.gz /app/

Generally, COPY is preferred. Use ADD only when its additional features are needed.

RUN

Executes commands inside the container during image build time. This allows installing software and setting up files in the image.

RUN <command>
# Example: RUN apt-get update && apt-get install -y nginx
# Example: RUN pip install -r requirements.txt

Chaining multiple commands with && in a single RUN instruction reduces the number of image layers and makes efficient use of the build cache.

CMD

Specifies the default command to execute when the container starts. Only one can be specified per Dockerfile. If multiple are present, the last one takes effect.

CMD ["executable", "arg1", "arg2"] # exec form (recommended)
# Example: CMD ["nginx", "-g", "daemon off;"]
# Example: CMD ["python", "app.py"]

CMD command param1 param2 # shell form
# Example: CMD python app.py

In shell form, the command is executed with /bin/sh -c.

ENTRYPOINT

Specifies the command to execute when the container starts. Unlike CMD, ENTRYPOINT is always executed, and CMD is treated as arguments to ENTRYPOINT.

ENTRYPOINT ["executable", "arg1"] # exec form (recommended)
# Example: ENTRYPOINT ["/usr/sbin/nginx"]

ENTRYPOINT command param1 param2 # shell form
# Example: ENTRYPOINT nginx -g "daemon off;"

Combining ENTRYPOINT and CMD allows defining flexible container startup commands. For example, with ENTRYPOINT ["nginx"] and CMD ["-g", "daemon off;"], the container runs nginx -g "daemon off;" at startup. Specifying arguments with docker run overrides the CMD content.

References