What is the difference between CMD and ENTRYPOINT?
Both instructions define what will run when the container starts, but they have different roles:
Junior Level
Simple Explanation
Both instructions define what will run when the container starts, but they have different roles:
- ENTRYPOINT — the main program of the container (e.g.,
java) - CMD — default arguments for that program (e.g.,
-jar app.jar)
RUN — executes during image BUILD. CMD/ENTRYPOINT — at container LAUNCH.
Analogy
Think of a function call in programming:
ENTRYPOINT— the function nameCMD— the default parameters
java -jar app.jar
^^^^^ ^^^^^^^^^^^^
| |
ENTRYPOINT CMD
How They Work Together
ENTRYPOINT ["java", "-jar", "/app.jar"]
CMD ["--server.port=8080"]
Running docker run myapp executes: java -jar /app.jar --server.port=8080
Running docker run myapp --server.port=9090 executes: java -jar /app.jar --server.port=9090
Two Forms of Writing
Exec form (recommended) — as a JSON array:
ENTRYPOINT ["java", "-jar", "/app.jar"]
Shell form — as a plain string:
ENTRYPOINT java -jar /app.jar
Always use Exec form — it correctly handles shutdown signals.
What to Remember
ENTRYPOINT— fixed command,CMD— default parameters- They can be used together
CMDis easy to override at launch,ENTRYPOINT— not- Always use Exec form
["cmd", "arg1", "arg2"] - Only one
CMDand oneENTRYPOINTcan exist in a Dockerfile
Middle Level
Detailed Behavior
ENTRYPOINT
Defines the main executable of the container:
- Stability: hard to accidentally override (requires
--entrypointflag) - Purpose: turns the container into an “executable binary”
- Arguments: all arguments passed to
docker runare appended to the end of theENTRYPOINTcommand
CMD
Defines the default command or parameters for ENTRYPOINT:
- Flexibility: very easy to override. Any arguments at the end of
docker runcompletely replaceCMD - Purpose: provide standard behavior that the user can easily change
Three Usage Scenarios
Scenario 1: CMD only
CMD ["java", "-jar", "/app.jar"]
docker run myapp → java -jar /app.jar
docker run myapp echo hello → echo hello (CMD completely replaced)
Scenario 2: ENTRYPOINT only
ENTRYPOINT ["java", "-jar", "/app.jar"]
docker run myapp → java -jar /app.jar
docker run myapp --debug → java -jar /app.jar --debug
Scenario 3: ENTRYPOINT + CMD (recommended)
ENTRYPOINT ["java", "-jar", "/app.jar"]
CMD ["--server.port=8080"]
docker run myapp → java -jar /app.jar --server.port=8080
docker run myapp --server.port=9090 → java -jar /app.jar --server.port=9090
Scenario 3 (ENTRYPOINT + CMD) — recommended. Scenario 1 — for simple scripts. Scenario 2 — when the container should act like an “executable file”.
Typical Mistakes
| Mistake | Consequence | How to avoid |
|---|---|---|
Shell form ENTRYPOINT java -jar |
Signals don’t reach the application | Exec form ["java", "-jar"] |
| Multiple CMDs in Dockerfile | Only the last one counts | One CMD per file |
| CMD without ENTRYPOINT | CMD is easy to accidentally replace | Use ENTRYPOINT + CMD pair |
| ENTRYPOINT without CMD | Developer can’t override for debugging | Add CMD with default parameters |
| Confusion with override | Container runs the wrong thing | Understand that docker run myapp arg replaces CMD |
Override at Launch
# Override CMD — just pass arguments
docker run myapp --custom-arg
# Override ENTRYPOINT — use flag
docker run --entrypoint /bin/bash myapp
Shell form vs Exec form: Critical Nuance
Exec form — command runs directly as a process with PID 1. Correctly handles shutdown signals. Important for Kubernetes and Docker Stop.
Shell form — command runs as a subprocess of /bin/sh -c. OS signals arrive at the sh shell, not the application. The application may be “killed” hard without completing transactions.
What to Remember
- Use Exec form for both instructions
ENTRYPOINTfor the immutable part of the commandCMDfor parameters that may change- Only one
CMDand oneENTRYPOINTare considered (the last ones in the file) - Without proper signal handling, the application can’t shut down correctly
When NOT to Use ENTRYPOINT
Don’t use ENTRYPOINT if the image is intended for different commands (e.g., a curl/wget image for various requests). In this case CMD is more flexible.
Senior Level
Architectural Design of ENTRYPOINT and CMD
The difference between ENTRYPOINT and CMD is not just syntax — it’s a design pattern for creating reusable container images.
“Executable Container” Pattern
ENTRYPOINT turns a container into an executable:
ENTRYPOINT ["java"]
CMD ["-jar", "/app.jar"]
The container behaves like a binary:
docker run myapp -version # java -version
docker run myapp -jar other.jar # java -jar other.jar
PID 1 Problem and Signal Handling
In Linux, a process with PID 1 has special behavior:
- Doesn’t receive signals by default (ignores SIGTERM)
- Responsible for “adopting” orphaned processes
- Doesn’t automatically terminate on unhandled signals
PID 1 — the main process in the container. If it can’t terminate correctly (handle SIGTERM), the application will be “killed” hard via SIGKILL.
Shell form problem:
ENTRYPOINT java -jar /app.jar
Processes in the container:
PID 1: /bin/sh -c "java -jar /app.jar"
PID 7: java -jar /app.jar
SIGTERM arrives at /bin/sh, which doesn’t know what to do with java. Result: docker stop waits 10 seconds and sends SIGKILL. The application doesn’t perform graceful shutdown — transactions are interrupted, connections aren’t closed.
Solutions:
- Exec form (recommended):
ENTRYPOINT ["java", "-jar", "/app.jar"]Application is PID 1, receives signals directly.
- Tini (init system):
ENTRYPOINT ["tini", "--", "java", "-jar", "/app.jar"]Tini — minimal init, correctly forwards signals and reaps zombie processes.
- Docker –init flag:
docker run --init myapp
Interaction with Kubernetes
In Kubernetes, ENTRYPOINT and CMD map to container fields:
| Docker | Kubernetes |
|---|---|
ENTRYPOINT |
command |
CMD |
args |
containers:
- name: app
image: myapp
command: ["java", "-jar"] # overrides ENTRYPOINT
args: ["--server.port=9090"] # overrides CMD
Important: if command and args are specified in the Kubernetes manifest, they completely replace Docker’s ENTRYPOINT and CMD.
Trade-offs
| Approach | Plus | Minus |
|---|---|---|
| CMD only | Flexibility for developer | Easy to accidentally replace |
| ENTRYPOINT only | Stability | Hard to override for debugging |
| ENTRYPOINT + CMD | Best of both | Need to understand interaction |
| Entrypoint script | Flexible initialization | Another layer, needs maintenance |
| Tini | Correct signals + zombie reap | Additional dependency |
Edge Cases
- Override in Kubernetes:
commandin K8s manifest completely replaces ENTRYPOINT. If the developer expects an entrypoint script to run migrations, but K8s overrodecommand— migrations won’t start. - ENTRYPOINT inheritance: if the base image has an ENTRYPOINT and the child Dockerfile doesn’t, the parent’s ENTRYPOINT is inherited. This can lead to unexpected behavior.
- JSON array parsing:
ENTRYPOINT ["java", "-jar", "/app.jar"]— this is JSON. An error in quotes or commas will cause the build to fail. - CMD as shell form + ENTRYPOINT as exec form:
ENTRYPOINT ["java"]+CMD -jar app.jar— CMD runs as/bin/sh -c "java -jar app.jar", ENTRYPOINT is ignored.
“Entry Point Script” Pattern
For complex applications, an entrypoint script is used:
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["java", "-jar", "/app.jar"]
#!/bin/sh
# docker-entrypoint.sh
# Run migrations
if [ "$RUN_MIGRATIONS" = "true" ]; then
java -jar /app.jar --migrate
exit 0
fi
# Launch the application (exec replaces the script process)
exec "$@"
exec "$@" replaces the shell script process with the target command, preserving PID 1 and signals. Without exec the script remains PID 1 and signals don’t reach the application.
Antipatterns
- Shell form without signal handling:
ENTRYPOINT java -jar /app.jar— graceful shutdown doesn’t work. - Multiple CMD/ENTRYPOINT: only the last one counts.
- ENTRYPOINT without CMD in developer images: impossible to override for debugging.
- Entrypoint script without
exec: script remains PID 1, signals are lost. - Secrets in CMD/ENTRYPOINT:
CMD ["java", "-jar", "app.jar", "--db-password=secret"]— visible indocker inspectandps.
Performance
| Approach | Shutdown time | Graceful shutdown | Zombie reap |
|---|---|---|---|
| Shell form | 10s (SIGKILL timeout) | No | No |
| Exec form | < 1s (SIGTERM) | Yes | No |
| Exec form + tini | < 1s | Yes | Yes |
| Docker –init | < 1s | Yes | Yes |
Summary
- Use Exec form for both instructions — critical for signal handling.
ENTRYPOINT+CMDtogether create a flexible and reusable image.- Understand the mapping to Kubernetes
command/args. - The PID 1 problem is real: use exec form or tini.
- Entrypoint scripts with
exec "$@"— standard for complex initialization scenarios. - Only one
CMDand oneENTRYPOINTinstruction can exist in a Dockerfile (the last one counts).
Interview Cheat Sheet
Must know:
- ENTRYPOINT — fixed command (PID 1), CMD — default parameters
- ENTRYPOINT + CMD together — recommended pattern (“executable container”)
- Exec form
["cmd", "arg"]is required for correct signal handling - Docker CMD is easy to override (
docker run image args), ENTRYPOINT — via--entrypoint - In K8s: Docker ENTRYPOINT →
command, CMD →args(complete replacement) - PID 1 problem: process without signal handler can’t do graceful shutdown
- PID 1 solution: exec form, tini, or
docker run --init
Frequent follow-up questions:
- “What happens with
docker run myapp arg?” —argreplaces CMD, appended to ENTRYPOINT - “Why is shell form dangerous in K8s?” — Signals arrive at
/bin/sh, not the application; graceful shutdown doesn’t work - “What does
exec "$@"do in an entrypoint script?” — Replaces the script process with the target command, preserving PID 1 - “Can you have multiple CMDs in a Dockerfile?” — Yes, but only the last one counts
Red flags (DO NOT say):
- “CMD and ENTRYPOINT are the same thing” (different semantics and override behavior)
- “I use shell form for convenience” (graceful shutdown is broken)
- “In K8s command and args supplement Docker ENTRYPOINT/CMD” (they completely replace!)
- “PID 1 doesn’t matter in a container” (critical for signal handling)
Related topics:
- [[What are the main instructions used in Dockerfile]] — all Dockerfile instructions
- [[What is Pod in Kubernetes]] — containers in K8s (signal handling is important)
- [[How to organize rolling update in Kubernetes]] — graceful shutdown during updates