Shell form
PID 1 is a shell, so docker stop waits the full grace period and then kills
CMD /app/server --port 8080
Work out what a container actually executes, and what ends up as PID 1. The answer decides whether docker stop is graceful or a ten second wait followed by a kill.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Test. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
PID 1 is a shell, so docker stop waits the full grace period and then kills
CMD /app/server --port 8080
The CMD is thrown away entirely, and nothing says so
ENTRYPOINT /app/server CMD ["--port", "8080"]
They replace the whole CMD rather than merging with it
ENTRYPOINT ["/app/server"] CMD ["--port", "8080"] docker run -d myimage --verbose
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
PID 1 becomes /bin/sh, which does not forward SIGTERM. Every stop waits the full grace period and ends in SIGKILL, so no shutdown handler ever runs.
Instead:Use exec form: ENTRYPOINT ["/app/server"]. If a shell is genuinely needed, exec through it so your process replaces the shell.
CMD is only appended to an exec-form ENTRYPOINT. In shell form it is discarded, so the defaults you wrote are never used and nobody is told.
Instead:Put the ENTRYPOINT in exec form, then CMD becomes its default arguments as intended.
Any argument on docker run replaces the whole CMD, so all the defaults disappear at once.
Instead:Keep required flags in the ENTRYPOINT and use CMD only for things a caller should be able to change.
That single fact is behind most of the questions about why containers take so long to stop and why shutdown handlers never run.
Docker sends SIGTERM to PID 1 and waits ten seconds. With shell form, PID 1 is /bin/sh -c and your program is its child, so the shell receives the signal, does nothing with it, and your process never hears about it. After the grace period Docker sends SIGKILL. Every stop takes the full ten seconds, no cleanup runs, and in-flight requests are dropped rather than drained.
ENTRYPOINT ["/app/server"] makes your binary PID 1, so the signal arrives where the handler is. This is the form to use for anything long-running, and the only reason not to is if you genuinely need shell features like variable expansion or a pipe.
ENTRYPOINT ["/bin/sh", "-c", "exec /app/server"] runs the shell, and exec replaces the shell process with yours, so your program ends up as PID 1 anyway. Without the exec keyword the shell stays and the problem returns.
CMD is appended to ENTRYPOINT only when ENTRYPOINT is in exec form. In shell form the whole thing becomes one string and the CMD is never used, so default arguments silently do nothing and arguments passed to docker run do nothing either.
They do not merge. A CMD carrying three default flags loses all three the moment somebody passes one argument, which is how a container ends up running without flags nobody realised were defaults. Anything that must always apply belongs in the ENTRYPOINT.
It reaps orphaned child processes. A program that never wrote that code accumulates zombies when it spawns subprocesses. --init inserts a tiny init that handles both reaping and signal forwarding, and is the right answer when the program at PID 1 was never designed to be one.