skip to content

questions

5

In a Dockerfile, what is the difference between the CMD and ENTRYPOINT instructions, and what happens to each of them when you pass extra arguments after the image name in `docker run`?

level: juniorimportance: must knowfreq 78%

answer

  1. Entrypoint + Cmd = argv
  2. run args replace CMD, append to ENTRYPOINT
  3. --entrypoint is the only ENTRYPOINT override
  4. ENTRYPOINT resets inherited CMD
  5. last one wins; JSON form always

basics

~20 s

ENTRYPOINT is the executable that always runs; CMD gives default arguments, or the whole command when there is no ENTRYPOINT. Arguments after the image name in docker run replace CMD but are appended to ENTRYPOINT.

solid answer

~50 s

Both declare what a container runs, but they play different roles. - **ENTRYPOINT** is the fixed part — the program the image exists to run. - **CMD** is the variable part — default arguments, or the entire command when no ENTRYPOINT is set. At runtime Docker concatenates them: `Entrypoint + Cmd` becomes the container's first process. `docker run img foo bar` **replaces CMD** and leaves ENTRYPOINT untouched. So with `ENTRYPOINT ["curl"]` and `CMD ["--help"]`, plain `docker run img` runs `curl --help`, while `docker run img https://example.com` runs `curl https://example.com`. With only `CMD ["curl","--help"]` those same run arguments would throw the whole command away. Overriding ENTRYPOINT needs the explicit `--entrypoint` flag. Rule of thumb: ENTRYPOINT when the image *is* one tool and users only vary arguments; CMD alone when the image is a general environment where users may run anything. Use the JSON (exec) form for both.

code

dockerfile · 4 lines
dockerfile
FROM alpine:3.20
RUN apk add --no-cache curl
ENTRYPOINT ["curl"]
CMD ["--help"]

go deeper

for a junior

Know that ENTRYPOINT is the fixed program, CMD is the default arguments, and run arguments replace CMD. Be able to read a two-line Dockerfile and say what the container executes.

for a middle

Reproduce the full interaction matrix including the shell-form ENTRYPOINT case, and know that ENTRYPOINT clears an inherited CMD and that only the last instruction of each kind counts.

for a senior

Frame it as an image contract: what you allow callers to override, how it reads on the CLI, how it maps into orchestrator manifests, and what it costs when someone needs to debug the image.

for a principal

Discuss it as a fleet-wide convention — consistency of override semantics across base images, how the contract survives orchestrator wrapping, and the debuggability tax of mandatory entrypoints.

## The underlying model An image stores two pieces of default-command metadata, `Entrypoint` and `Cmd`, each a list of strings. When a container starts, Docker concatenates them — **Entrypoint first, then Cmd** — and executes the resulting argument vector as PID 1 inside the container. That single sentence explains nearly every behaviour people find surprising. `ENTRYPOINT ["nginx", "-g", "daemon off;"]` with no CMD gives the vector `nginx -g "daemon off;"`. `CMD ["nginx","-g","daemon off;"]` with no ENTRYPOINT gives exactly the same vector. Statically the container behaves identically — the difference only appears when someone overrides something. ## What `docker run` overrides Anything you type after the image name replaces **Cmd** and nothing else: - `docker run img` → Entrypoint + Cmd - `docker run img a b` → Entrypoint + `a b` (Cmd discarded) - `docker run --entrypoint X img a b` → `X` + `a b` So ENTRYPOINT is the part you are asserting is non-negotiable, and CMD is the part you are inviting the caller to change. This is the whole design intent: an image that *is* a tool (`ENTRYPOINT ["curl"]`) behaves like that tool on the command line — `docker run curlimg -sS https://x` reads naturally. An image that is an *environment* (`ubuntu`, whose Cmd is `bash`) lets `docker run ubuntu ls /` work, because the default command is fully replaceable. ## The interaction matrix Assume exec (JSON) form unless stated: | ENTRYPOINT | CMD | Container runs | |---|---|---| | none | `["a","b"]` | `a b`; run args replace it entirely | | `["e"]` | none | `e`; run args appended | | `["e"]` | `["d"]` | `e d`; run args replace `d` → `e <args>` | | shell form `e` | anything | `/bin/sh -c "e"` — **CMD and run args are ignored** | | `["e"]` | shell form `d` | `e /bin/sh -c d` — almost never what you want | The fourth row is the classic trap: a shell-form ENTRYPOINT silently swallows every argument, because the whole command is baked into the `sh -c` string and nothing is appended. ## Inheritance and repetition Only the **last** ENTRYPOINT and the **last** CMD in a Dockerfile take effect; earlier ones are dead metadata. Both are also inherited from the base image, with one asymmetry that bites people: **setting ENTRYPOINT resets the inherited CMD to empty.** If you build on an image whose CMD is `["node","server.js"]` and add `ENTRYPOINT ["/entrypoint.sh"]` without a CMD, the container runs the script with no arguments. Whenever you introduce an ENTRYPOINT, re-declare CMD. ## Choosing between them - **CMD only** — general-purpose images, base images, anything where a human will want `docker run img bash`. Debugging stays easy: no flag needed. - **ENTRYPOINT + CMD** — single-purpose service or CLI images. The default is useful (`CMD ["--help"]`, or the normal server arguments) and callers append flags naturally. - **ENTRYPOINT as a wrapper script + CMD as the real command** — the pattern the official Postgres, MySQL and Redis images use: the script does setup, then hands off to whatever CMD holds. A cost worth knowing: an ENTRYPOINT makes ad-hoc inspection slightly harder, because `docker run img sh` now passes `sh` as an argument to the entrypoint instead of running a shell. You need `docker run --entrypoint sh img`. ## Cross-referencing other runtimes Other container runtimes reuse the same two image fields, so the contract you set in the Dockerfile carries. In a Kubernetes pod spec, `command` overrides the image's ENTRYPOINT and `args` overrides CMD — a frequent source of confusion because the names are swapped relative to Docker's vocabulary. Docker Compose exposes them as `entrypoint` and `command`. ## Form matters too Always prefer the JSON array (exec) form for both instructions. Shell form wraps the command in `/bin/sh -c`, which changes argument handling as shown above and also changes which process is PID 1 — with consequences for signal delivery and shutdown. Note that JSON form requires **double** quotes; `CMD ['a','b']` with single quotes is not valid JSON and is silently treated as shell form.

  • Your base image defines `CMD ["node","server.js"]`. You add only `ENTRYPOINT ["/entrypoint.sh"]`. What runs?
    Just `/entrypoint.sh` with no arguments. Declaring ENTRYPOINT resets any CMD inherited from the base image to empty, so the previous default command is lost. You must re-declare `CMD ["node","server.js"]` in your own Dockerfile if the script is meant to receive it.
  • How do Kubernetes `command` and `args` map onto ENTRYPOINT and CMD?
    `command` in a container spec overrides the image's ENTRYPOINT, and `args` overrides its CMD. The naming is the confusing part: setting only `command` overrides the entrypoint and, like the Dockerfile, drops the image's CMD unless you also set `args`.
  • If both instructions can express the same container, when does the choice actually matter?
    Only at override time. It matters when someone runs the image with arguments, debugs it with a shell, or wraps it in an orchestrator manifest. An ENTRYPOINT declares 'this part is not negotiable', which is exactly right for a single-purpose image and wrong for a general-purpose base image.

ENTRYPOINT is the appliance; CMD is the dial setting it ships with. Handing a container arguments turns the dial — it does not swap the appliance.

saying these in an interview costs you the question

  • Saying CMD runs at build time and ENTRYPOINT at runtime — both are runtime metadata only.
  • Claiming a Dockerfile can only have one of the two, or that having both is an error.
  • Believing `docker run img bash` gives a shell in an image that has an ENTRYPOINT — it passes `bash` as an argument instead.
  • Thinking multiple CMD lines are executed in sequence; only the last one survives.
  • Forgetting that adding ENTRYPOINT wipes the CMD inherited from the base image.

context

open as a page

A Dockerfile ends with `CMD python app.py` instead of `CMD ["python", "app.py"]`. What is the practical difference between those two forms, and why does it matter when someone runs `docker stop` on the container?

level: middleimportance: must knowfreq 64%

basics

~20 s

Shell form runs the command via /bin/sh -c, so the shell is PID 1 and usually does not forward the SIGTERM that docker stop sends — the container is SIGKILLed after the timeout. Exec (JSON) form runs the process directly as PID 1, so it receives the signal.

open as a page

An image's configured start-up command crashes immediately, so the container never stays up long enough to inspect. How do you get a shell inside that image using `docker run`, and what exactly does the `--entrypoint` flag change?

level: middleimportance: should knowfreq 46%

basics

~10 s

Run docker run --rm -it --entrypoint sh myimage. The flag replaces the image's ENTRYPOINT for that container only; anything you type after the image name still becomes the arguments, replacing CMD.

open as a page

Describe the entrypoint wrapper-script pattern used by images such as the official Postgres image: what work belongs in that script, how it is wired up in the Dockerfile, and why the script must end with `exec "$@"`?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Set ENTRYPOINT to a small script and CMD to the real command. The script does start-up work — render config, fix permissions, first-run initialisation — then runs exec "$@", replacing itself with the CMD so the real process becomes PID 1 and receives signals.

open as a page

You own the shared base images for dozens of services. How would you standardise the ENTRYPOINT/CMD contract, PID 1 behaviour, and shutdown-signal handling across all of them, and what trade-offs would you weigh?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Mandate exec-form instructions, decide one convention for whether ENTRYPOINT is the app or a thin wrapper, guarantee the real process ends up as PID 1 with a SIGTERM handler, standardise grace periods against measured drain time, and enforce it with lint plus an automated termination test.

open as a page