Two instructions decide what a container runs when it starts.
| Instruction | Role | Replaced by |
|---|---|---|
CMD | Default command, or default arguments for ENTRYPOINT | Arguments after the image name in docker run |
ENTRYPOINT | The executable that always runs | docker run --entrypoint |
The container's command is ENTRYPOINT followed by CMD. If a Dockerfile has several, the last of each wins. Setting ENTRYPOINT also clears any CMD inherited from the base image.
Exec form and shell form
CMD ["node", "server.js"] # exec form: a JSON array, run directly
CMD node server.js # shell form: run as /bin/sh -c "node server.js"| Exec form | Shell form | |
|---|---|---|
| PID 1 | node | /bin/sh |
docker stop | SIGTERM reaches Node.js | The shell may not forward it; after 10s Docker kills the container (exit 137) |
$VAR, &&, pipes | Not expanded | Expanded by the shell |
| Quotes | Double quotes only (JSON) | Any |
BuildKit warns about shell form:
1 warning found (use docker --debug to expand):
- JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 7)The image records the wrapper:
learner@pier:~/status-page$ docker image inspect status-page:0.5 --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}'
["docker-entrypoint.sh"] ["/bin/sh","-c","node server.js"]docker-entrypoint.sh is inherited from node:20-alpine.
What docker run arguments replace
| Dockerfile | docker run IMG | docker run IMG print-config.js |
|---|---|---|
CMD ["node", "server.js"] | node server.js | print-config.js: the whole command is replaced |
ENTRYPOINT ["node"] + CMD ["server.js"] | node server.js | node print-config.js |
ENTRYPOINT ["node", "server.js"] | node server.js | node server.js print-config.js |
Use CMD alone for an app image. Use ENTRYPOINT plus CMD when the image should always run one program and callers pick its arguments.
Overriding at run time
learner@pier:~/status-page$ docker run --name config-check -e SERVICE_NAME=Platform status-page:0.5 print-config.js
SERVICE_NAME=Platform
APP_VERSION=undefined
PORT=undefined
learner@pier:~/status-page$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
99fddfcd7640 status-page:0.5 "node print-config.js" 2 seconds ago Exited (0) 2 seconds ago config-check
e1dd94dc29ef status-page:0.5 "node server.js" 6 seconds ago Up 6 seconds 0.0.0.0:8080->3000/tcp statusWith ENTRYPOINT ["node"], any other command becomes a script name:
learner@pier:~/status-page$ docker run --rm status-page:0.5 ls
...
Error: Cannot find module '/app/ls'Replace the entrypoint to run something else:
docker run --rm --entrypoint ls status-page:0.5 /app