Dockerfile

Dockerfile is a syntax for describing a container image. Several container toolchains are capable of compiling Dockerfile files, including Docker and Podman.


Example

# Setup
FROM alpine:latest
RUN apk update
RUN apk add postgres14

# Data persistence
VOLUME /var/lib/postgresql/data

# Configuration
COPY local/path/to/postgresql.conf /etc/postgresql/postgresql.conf

# The containerized process
USER postgres
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]


From


Label

The LABEL command is used for image metadata.

LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."


Arg and Env


Run and Shell

Shell

The SHELL command overrides how RUN commands are handled. The default shell is ["/bin/sh", "-c"] on Linux and ["cmd", "/S", "/C"] on Windows.


Add


Copy

To copy a single file, try:

COPY index.html /usr/share/nginx/html/index.html
# or
COPY index.html /usr/share/nginx/html/

If and only if the destination ends in /, it is interpreted as a directory.

To copy multiple files, try:

COPY README.md package.json __BUILD_NUMBER /destination/path/
# or
COPY ["__init__.py", "__main__.py", "app.py", "/destination/path/"]
# or
COPY *.conf /destination/path/

The destination must be a directory when copying multiple files.

Note that COPY handles source directories differently. COPY dir1 dir2 /destination/path/ is actually COPY dir1/* dir2/* /destination/path/

Ownership

Files and directories are copied with uid and gid of 0. To set ownership, try:

COPY --chown=nginx:nginx index.html /usr/share/nginx/html/index.html

If a user name or group name is used, the container will depend on having /etc/passwd and /etc/group files. If this isn't feasible, consider using numeric uids and gids.

Copy from

COPY has a --from=CONTAINER option.

In a multi-stage build, files and binaries are copied from a build container into the production container. This keeps the statically-compiled dependencies outside of the production image.

FROM golang:latest AS builder
WORKDIR /app
COPY * ./
RUN go mod download
RUN go build -o /my-binary-name

FROM alpine:latest
WORKDIR /
COPY --from=builder /my-binary-name /my-binary-name
EXPOSE 8080
ENTRYPOINT ["/my-binary-name"]

Build Context

COPY depends on the build context (i.e. the working directory and all contained files). Files from outside this context cannot be accessed by COPY.

When building a piped Dockerfile (i.e. docker build - <Dockerfile.example), there is no build context and COPY cannot be used.


Volume


User


Workdir


Cmd

The CMD command is used to define the default process for an image. There can only be one CMD command in a Dockerfile.

Some best practices follow.

Run without a shell

If the command is a string, it is processed by a shell just like a RUN command.

If the command is a JSON array, it is executed directly. This is always preferable.

Run in foreground

Container images are designed to run singular services, and accordingly expect services to behave like userspace utilities. These expectations include...

  1. observe and respond to signals
  2. exit upon completion with a meaningful exit code
  3. log to stdout
  4. print errors to stderr

Most services can be run in the foreground, as init systems prefer to handle forking internally. Some can even be configured to use stdout and sterr correctly.

For services that cannot be made to fit this model, consider using a supervisor.

Use a supervisor

Supervisord is a minimal init system for use in containers. Consider the below Dockerfile:

FROM alpine:latest
RUN apk add supervisord
USER root
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

The container's main process will be supervisord(1), and the services will instead be managed by that process.


Entrypoint

The ENTRYPOINT command is very similar to CMD, and in many cases they can be used interchangeably.

Entrypoint and Cmd

If ENTRYPOINT and CMD are used in the same Dockerfile, then ENTRYPOINT acts as the default program while CMD acts as the default argument.

FROM alpine:latest
ENTRYPOINT ["/bin/ping","-c","3"]
CMD ["localhost"]


Expose


Healthcheck


CategoryRicottone