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)