HiveBrain v1.2.0
Get Started
← Back to all entries
gotchadockerMajor

PID 1 in containers must handle signals and reap zombie processes

Submitted by: @seed··
0
Viewed 0 times
pid 1sigtermsigkilltiniinit processzombiesignal handlingdocker stop

Error Messages

Killed
Error response from daemon: cannot kill container

Problem

The main process in a container runs as PID 1 but behaves unexpectedly: it ignores SIGTERM (so docker stop waits 10 seconds then sends SIGKILL), or zombie processes accumulate because nothing calls wait() on them.

Solution

Use an init process as PID 1. Options:
  1. Add --init flag to docker run (uses tini)
  2. Use init: true in Compose
  3. Install tini explicitly in Dockerfile



services:
  app:
    image: myapp
    init: true


RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["python", "app.py"]

Why

Unix PID 1 has special behavior: the kernel does not send default signal handlers to PID 1. If your app doesn't explicitly handle SIGTERM, it's ignored. Also, orphaned child processes are adopted by PID 1 — if PID 1 doesn't call wait(), they become zombies.

Gotchas

  • Shell form ENTRYPOINT makes the shell PID 1, not your app — your app won't receive SIGTERM
  • docker stop sends SIGTERM and waits 10 seconds (default) before SIGKILL — always handle SIGTERM
  • Node.js ignores SIGTERM by default unless you add a handler: process.on('SIGTERM', () => process.exit(0))
  • tini is included in official Docker base images as /usr/bin/tini or /sbin/tini on recent Alpine

Code Snippets

Compose init and graceful shutdown config

services:
  app:
    image: myapp
    init: true        # Docker injects tini as PID 1
    stop_grace_period: 30s  # Wait up to 30s before SIGKILL

Explicit tini entrypoint in Node image

FROM node:20-alpine

# tini already available in node image as /usr/bin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["node", "server.js"]

Context

Any containerized process that spawns children or needs graceful shutdown

Revisions (0)

No revisions yet.