SIGTERM and Docker images running as PID 1
Or, why doesn’t docker stop
work for my Docker image?
I’ve had a Docker image which is intended to be approximately the most basic HTTP-compatible responder for a while. But, I built this originally for playing with Kubernetes, which doesn’t really give you direct access to anything.
When actually using it with Docker, I discovered that it wouldn’t actually shut
down correctly with Ctrl-C
or docker stop
, and Docker would eventually have
to docker kill
it.
For those of you more familiar with Linux signals handling, this means that
SIGTERM
was ignored, so it had to escalate to SIGKILL
. But, why? It’s not
like the actual program in question had any specific SIGTERM
handling (most
don’t).
It turns out that the Dockerfile results in an image where the resulting executable runs as PID 1.
FROM rust:alpine as builder
WORKDIR /usr/src/app
COPY . .
RUN cargo install --path .
FROM scratch
COPY --from=builder /usr/local/cargo/bin/minimal-http-responder /usr/local/bin/minimal-http-responder
ENTRYPOINT ["minimal-http-responder"]
And, PID 1 is special, because it’s usually the init process on a Linux
machine. For all other processes, there’s an automatically installed SIGTERM
handler which exits the program, which is why you don’t usually need to add one.
But in this Docker scenario, you actually need to install your own!
Thankfully this is pretty easy in Rust using the ctrlc
crate:
ctrlc::set_handler(|| {
println!("Received SIGTERM");
std::process::exit(0);
})
.unwrap();
And now, it exits with docker stop
! (minimal-http-responder v0.1.2
has been
released with this fix)