Stopping Gracefully
In one sentence: stop is a negotiation — SIGTERM, a grace period (default 10 s), then SIGKILL — and it only works if the container's PID 1 actually receives and handles signals, which is why init processes matter.
You already know
- From Lesson 4: the container's main process is PID 1 in its own PID namespace.
- From Lesson 21: "user stopped it" travels with the exit event and gates restarts.
Ask, wait, insist
SIGTERM means "please finish up": close connections, flush buffers, release locks. SIGKILL means "you no longer exist" — unhandleable, uncleanable. The grace period between them is the app's contract with the platform: handle TERM within N seconds or lose the right to clean up. The engine picks N per workload — 10 s suits a web server; a database checkpointing to disk may need minutes. Exit codes tell the story afterward: 143 (128+15) means TERM was honored; 137 (128+9) means the deadline passed and KILL fired.
The PID 1 trap
Two kernel quirks make PID 1 special inside a namespace: signals with default handlers are ignored for it (an app that never installs a TERM handler simply won't die politely), and orphaned child processes reparent to it, becoming zombies unless someone reaps them. Shell-wrapper entrypoints hit both — the shell holds PID 1, doesn't forward signals, doesn't reap. The fix is a tiny init as PID 1 that forwards signals to the real app and reaps orphans.
flowchart TB E["engine: stop c-42"] --> SH["shim"] SH -- "SIGTERM" --> I["tiny init (PID 1)
forwards signals · reaps zombies"] I -- "forward TERM" --> APP["app (PID 2)
closes conns, flushes"] APP -. "orphaned children
reparent here" .-> I SH -. "if deadline passes:
SIGKILL (unblockable)" .-> I
sequenceDiagram
participant E as Engine
participant S as Shim
participant P as PID 1
E->>S: stop (grace: 10s)
S->>P: SIGTERM
alt app handles TERM in time
P->>P: cleanup, exit(0)
S-->>E: exited 143 — graceful
else deadline passes
S->>P: SIGKILL
S-->>E: exited 137 — forced, no cleanup ran
end
E->>E: mark "user-stopped" (restart policies stand down — L21)
Anchor these
- stop = TERM → grace period → KILL. The grace period is the app's cleanup contract.
- PID 1 ignores unhandled signals and inherits orphans — use a tiny init.
- Exit 143 = graceful; 137 = the deadline won. The code is the audit trail.
See what actually stuck.
Take the practice scenarios now.