Q: A microservice running a Node.js web server spawns child processes (`child_process.fork`) to handle PDF report generation. Over several days, SREs observe that the container exhausts the host PID limit (`kernel.pid_max`), preventing any new containers or shell sessions from starting. Running `ps aux` inside the container reveals over 32,000 `<defunct>` zombie processes. Furthermore, when Kubernetes or Docker issues `docker stop`, the container ignores the signal and hangs for 10 seconds before being brutally killed with SIGKILL. You must resolve the PID 1 zombie reaping and signal forwarding defect.
Understand how the Linux kernel treats PID 1 in containers, why orphan child processes become defunct zombies (`Z` state), and how to configure Tini to ensure clean process reaping and SIGTERM graceful shutdown.
Want to master this scenario in a live sandbox? KodeKloud's Docker Certified Associate (DCA) Hands-On Lab Course covers this exact problem with hands-on terminal drills.
🛠️ Production Runbook & Step-by-Step Resolution
Understand the Linux Kernel PID 1 Contract
In Linux, PID 1 (init) has two unique kernel responsibilities: reaping adopted orphaned child processes (via `wait()`/`waitpid()`) and registering default signal handlers. Standard applications (Node.js, Python, Java) do not implement child reaping loops, leaving defunct child processes in the process table indefinitely.
<!-- Process Hierarchy -->
Without Init (Broken):
PID 1: node server.js (Does not reap child processes!)
└── Child: worker (Exits, becomes <defunct> Zombie)
└── Child: worker (Exits, becomes <defunct> Zombie) -> 30,000 Zombies exhaust Host PID limit!
With Tini (Healthy):
PID 1: /sbin/tini -- node server.js
├── Forwards SIGTERM to node server.js
└── Reaps exited orphaned child processes via waitpid()
Reproduce Zombie Accumulation in a Minimal Test Container
Demonstrate the defect using a Python or shell script that forks children without calling `os.wait()`.
# Python script creating zombie processes
cat << 'EOF' > zombie_test.py
import os, time
for _ in range(5):
if os.fork() == 0:
exit(0) # Child exits immediately
time.sleep(60) # Parent sleeps without reaping
EOF
docker run --rm -v $(pwd):/app python:3.11-alpine python /app/zombie_test.py &
docker exec $(docker ps -lq) ps -eo pid,ppid,stat,comm
# Output displays processes in 'Z' (Zombie) status
Integrate Tini as the Container Entrypoint
Add `tini` into the Dockerfile as the official PID 1 entrypoint. Tini acts as a lightweight C-based init system (size < 100KB) that forwards signals to application child processes and reaps zombies.
FROM node:20-alpine
# Install tini
RUN apk add --no-cache tini
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
# Set tini as entrypoint and node application as CMD
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]
Utilize Native Docker `--init` Flag and Kubernetes Alternatives
Docker provides built-in Tini support via the `--init` flag, injecting Docker's internal `docker-init` binary without modifying the Dockerfile. In Kubernetes, share process namespaces across the pod using `shareProcessNamespace: true` so the pause container reaps zombies.
# Run container using Docker native built-in init
docker run -d --init --name safe-app node-app:latest
# In Kubernetes Pod spec:
# spec:
# shareProcessNamespace: true
- W
- e
- r
- e
- s
- o
- l
- v
- e
- d
- h
- o
- s
- t
- P
- I
- D
- t
- a
- b
- l
- e
- e
- x
- h
- a
- u
- s
- t
- i
- o
- n
- a
- n
- d
- s
- l
- o
- w
- 1
- 0
- -
- s
- e
- c
- o
- n
- d
- s
- h
- u
- t
- d
- o
- w
- n
- h
- a
- n
- g
- s
- b
- y
- a
- d
- o
- p
- t
- i
- n
- g
- T
- i
- n
- i
- a
- s
- t
- h
- e
- P
- I
- D
- 1
- e
- n
- t
- r
- y
- p
- o
- i
- n
- t
- a
- c
- r
- o
- s
- s
- o
- u
- r
- D
- o
- c
- k
- e
- r
- i
- m
- a
- g
- e
- s
- .
- T
- i
- n
- i
- r
- e
- l
- i
- a
- b
- l
- y
- h
- a
- n
- d
- l
- e
- s
- o
- r
- p
- h
- a
- n
- e
- d
- c
- h
- i
- l
- d
- p
- r
- o
- c
- e
- s
- s
- r
- e
- a
- p
- i
- n
- g
- a
- n
- d
- i
- n
- s
- t
- a
- n
- t
- l
- y
- f
- o
- r
- w
- a
- r
- d
- s
- S
- I
- G
- T
- E
- R
- M
- s
- i
- g
- n
- a
- l
- s
- t
- o
- a
- p
- p
- l
- i
- c
- a
- t
- i
- o
- n
- w
- o
- r
- k
- e
- r
- s
- ,
- e
- n
- s
- u
- r
- i
- n
- g
- c
- l
- e
- a
- n
- e
- x
- i
- t
- s
- a
- n
- d
- z
- e
- r
- o
- z
- o
- m
- b
- i
- e
- a
- c
- c
- u
- m
- u
- l
- a
- t
- i
- o
- n
- .