Dockerfile Instructions and Semantics
Know exactly what each Dockerfile instruction does at build time and at run time: how CMD and ENTRYPOINT combine, which variables the builder expands, and which choices leak secrets or break signal handling.
Key points
- 1
Exec form (
["node", "app.js"]) runs the program directly as PID 1; shell form wraps it in/bin/sh -c, which does not forward SIGTERM. Exec form needs double quotes, because it is parsed as JSON. - 2
With an ENTRYPOINT, CMD becomes its default arguments and
docker runarguments replace CMD. A shell-form ENTRYPOINT ignores both, and setting ENTRYPOINT resets a CMD inherited from the base image. - 3
An ARG before the first FROM is only usable in FROM lines; re-declare
ARG NAMEinside a stage to read it. ENV always overrides an ARG of the same name, and an ARG only applies from the line it is declared on. - 4
The builder expands
$VARin ADD, COPY, ENV, EXPOSE, FROM, LABEL, STOPSIGNAL, USER, VOLUME, WORKDIR and ONBUILD. RUN, CMD and ENTRYPOINT rely on a shell, so their exec forms get no expansion. - 5
COPY and ADD create files owned by root unless
--chownis given, even after USER. ADD also extracts local tar archives and downloads URLs, but does not extract remote archives without--unpack. - 6
EXPOSE is documentation; publish ports with
-por-P. HEALTHCHECK defaults are interval 30s, timeout 30s, start-period 0s, start-interval 5s and retries 3, and exit code 2 is reserved. - 7
.dockerignorelives at the context root (or as<Dockerfile>.dockerignore), uses Go filepath.Match plus**, and the last matching line wins.
Common traps
Never pass secrets through ARG or ENV: build args show up in
docker history. UseRUN --mount=type=secret.Parser directives such as
# syntax=only work on the very first lines, before any comment or blank line.Entrypoint scripts must end with
exec "$@", or the shell stays PID 1 and the app never sees SIGTERM.
Test yourself on Dockerfile Instructions and Semantics
Ten questions, with the answer and explanation after each one.