Search code examples
dockerrustwindows-subsystem-for-linux

Unable to stop my Docker container with Ctrl-C


I'm using WSL2 on Windows 10 using an Ubuntu image, and Docker for Desktop Windows (2.2.2.0) with the WSL integration.

I have a Rust TCP server. When I run it with cargo run (or the binary after cargo install), it does the right thing, and I can send Ctrl-C to it to terminate. I don't do any explicit signal handling in the code.

I turned it into a Docker image. Here's the Dockerfile.

FROM rust:1.40 as builder
COPY . .
RUN cargo install --path . --root .

FROM debian:buster-slim
COPY --from=builder ./bin/myserver ./myserver
EXPOSE 8080
ENTRYPOINT ["./myserver"]

I then do:

docker build -t myserver .
docker run -it --rm -p 8080:8080 myserver

Attempting to Ctrl-C the process shows the ^C character in the terminal, but the signal doesn't seem to reach the process. I have to use docker kill. I've read other posts like this and this. It suggests that a combination of -it and using the array parameter version of ENTRYPOINT or CMD should allow the signal to reach it, however these don't seem to be helping me.

To see if it was something to do with my setup (Docker for Desktop, WSL, etc.) or my Dockerfile, I followed the README for docker-http-https-echo, and I'm able to Ctrl-C the process. Inspecting the Dockerfile doesn't show that it's doing anything different than me, but clearly I'm missing something.


Solution

  • The reason for your problem is that the kernel treats a process with PID 1 specially, and does not, by default, kill the process when receiving the SIGTERM or SIGINT signals.

    You have two options:

    1. Add --init flag to docker run command. By that a special process with PID 1 will be created, which will be a parent for your process and will proxy all signals and properly reap your processes.
    2. Add explicit signal handling to your app, which is good if you want to do graceful shutdown.

    The good practice is to combine both methods.