Have you ever noticed that some containers stop almost instantly, while others hang for a full ten seconds before Docker gives up and kills them?
I ran into this with a front-end dev server, and I shared a quick workaround of shortening the grace period Compose waits before sending SIGKILL.
That gets rid of the pause, but it doesn't explain why the container ignored SIGTERM in the first place.
The answer has to do with which process is running under PID 1.
On Linux, the first process in a container runs as PID 1, and the kernel treats that process differently.
A normal process that receives SIGTERM without a handler just terminates, because that's the default action for the signal, but PID 1 doesn't get default actions.
Unless it explicitly registers a handler, the signal is silently ignored.
Plenty of programs were never written with PID 1 in mind.
For example, a dev server started with npm run dev may never register a SIGTERM handler, so Docker sends the signal, nothing happens, and you wait out the grace period until SIGKILL forces it to quit.
The fix is to stop running your dev server as PID 1 at all.
# docker-compose.yml
services:
frontend:
build: .
init: true
With init: true, Compose starts a tiny init process as PID 1 instead.
It forwards signals to your dev server, which now receives SIGTERM as an ordinary process and exits promptly.
Once that's in place, you can drop the shortened grace period, since the container now stops the way it was always supposed to.
Here to help,
Joel
P.S. Small config details like this one add up across a whole project. If you'd like a second set of eyes on yours, a code review will find the ones worth fixing.