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`?
answer
- Entrypoint + Cmd = argv
- run args replace CMD, append to ENTRYPOINT
- --entrypoint is the only ENTRYPOINT override
- ENTRYPOINT resets inherited CMD
- last one wins; JSON form always
basics
~20 sENTRYPOINT 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 sBoth 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 linesFROM alpine:3.20
RUN apk add --no-cache curl
ENTRYPOINT ["curl"]
CMD ["--help"]go deeper
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.
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.
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.
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.