Docker

Sefism.

Chapter 02

Writing a Dockerfile

The instructions that turn source code into an image, and the details that decide how the container starts and stops.

FROM and base images

What
FROM picks the starting image and begins a build stage. Everything after it builds on that base, including its OS packages and default user.
Why
The base decides image size, available tools, libc and most of the vulnerabilities you inherit.

Watch out

Using a floating base such as node or python:latest, so a rebuild months later silently gets a new major version.

RUN

What
Executes a command at build time and saves the filesystem changes as a new layer.
Why
It installs packages and compiles code. Chaining related commands in one RUN keeps caches and temp files out of the final layer.
Dockerfile
RUN apt-get update \
  && apt-get install -y --no-install-recommends curl \
  && rm -rf /var/lib/apt/lists/*

Watch out

Running apt-get update in a separate RUN from the install: the cached update layer goes stale and installs fail or pull old versions.

COPY vs ADD

What
COPY copies files from the build context into the image. ADD also fetches URLs and unpacks local tar archives. Both accept --chown to set ownership.
Why
Prefer COPY for its predictable behaviour; use ADD only when you want the extraction or remote fetch.

Watch out

Copying files and then running chown -R in a later layer, which duplicates every byte; use COPY --chown instead.

WORKDIR, ENV and ARG

What
WORKDIR sets the working directory (creating it). ENV sets variables in the image and at runtime. ARG sets build-time variables passed with --build-arg; they are gone at runtime.
Why
They keep paths and versions in one place and let one Dockerfile build variants.

Watch out

Passing secrets as ARG or ENV: they are visible in docker history and the image config.

CMD vs ENTRYPOINT

What
ENTRYPOINT is the executable the container always runs; CMD gives default arguments, replaced by anything after the image name in docker run. With only CMD, it is the whole command.
Why
Use ENTRYPOINT for images that act like a single tool and CMD alone for apps where users may want to run a different command.
Dockerfile
ENTRYPOINT ["python", "-m", "reportgen"]
CMD ["--help"]

Exec form and PID 1

Also called shell form, tini, --init

What
Exec form ["node", "server.js"] runs the process directly as PID 1. Shell form node server.js wraps it in /bin/sh -c, which may not forward signals. docker run --init adds a tiny init that forwards signals and reaps zombies.
Why
If SIGTERM never reaches your app, every stop waits for the timeout and ends in SIGKILL, dropping in-flight requests.

Watch out

Starting through an entry script without exec "$@" at the end, so the script, not the app, is PID 1.

HEALTHCHECK

What
An instruction that runs a command inside the container on an interval. The container is reported as starting, healthy or unhealthy.
Why
Compose uses it to order startup, and docker ps shows at a glance whether the app actually serves, not only whether the process runs.
Dockerfile
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
  CMD curl -fsS http://localhost:3000/health || exit 1

Watch out

Relying on curl in a slim or distroless image that does not ship it; use a tiny built-in check command instead.

LABEL and OCI annotations

What
Key and value metadata stored in the image, such as org.opencontainers.image.source and org.opencontainers.image.revision.
Why
Registries and scanners use these labels to link an image back to its repository and commit.
02 · Writing a Dockerfile2 / 10