— or why I wrote procjail
The problem I kept running into
I’ve worked with containers long enough to be comfortable with them. Docker, Kubernetes, YAML, dashboards — all of that is familiar.
And yet, every serious production incident followed the same pattern:
- OOM kills that didn’t make sense
- Processes that ignored SIGTERM
- Containers that refused to shut down
- Zombie processes quietly piling up
When that happened, the abstractions stopped helping.
At some point, I had to answer questions like:
- What process is actually running?
- Who is PID 1?
- What does the kernel think is happening?
I realized something uncomfortable:
I could use containers very well, but I could not always explain their failures without hand-waving.
The idea: remove everything
Instead of adding more tooling, I decided to remove it.
I wanted the smallest possible program that would:
- create Linux namespaces explicitly
- apply cgroup resource limits directly
- run a process as PID 1
- forward signals manually
- do nothing “helpful” behind the scenes
That program became procjail.
You can find it here: github.com/Emmanuel326/procjail
The uncomfortable truth about containers
Building this forced me to internalize something very simple:
A container is just a Linux process.
More precisely:
- a process with a modified view of the system (namespaces)
- a process constrained by kernel-enforced limits (cgroups)
- often running as PID 1, whether it expects to or not
Everything else is tooling layered on top.
When things break, it is the kernel you are debugging — not Docker.
PID 1 is not a normal process
If procjail taught me one thing clearly, it’s this:
PID 1 has responsibilities that most programs are not written to handle.
As PID 1:
- signal handling semantics change
- ignored signals stay ignored
- zombie reaping becomes your job
- exiting tears down the entire environment
Many real-world container bugs are just this fact surfacing late.
What surprised me most
What surprised me wasn’t how complex this was.
It was how little code it took to reproduce real production failure modes.
A few syscalls. A few mounts. One badly behaved process.
And suddenly:
- SIGTERM doesn’t shut things down
- children outlive their parents
- memory limits kill processes abruptly
Containers are thin abstractions. That’s not a criticism — it’s a warning.
Why procjail stops here
I deliberately stopped adding features.
No networking. No image pulling. No overlay filesystems.
Those solve Day-1 problems.
Procjail exists for Day-2 — when you are staring at a broken system and the kernel is the only thing left that tells the truth.
The moment the kernel pushed back
This stopped being an academic exercise the time I tried to shut my laptop down.