Unable to stop my Docker container with Ctrl-C

Viewed 3573

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.

2 Answers

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.

I hope not being late, Nikscorp provides one of the possible reasons why your container could be no stopping, but this could happen in other cases like below:

  • Your ENTRYPOINT is a sheel script and you are not using Exec: usually, when you run your container from a shell script, your container runs on a new process causing your container won't receive any signals, this can be solved using the exec command

  • Don't use Pipeline in your Exec entrypoint: in some cases this can generate your application run in a subshell, which causes the no signals (SIGINT, SIGTERM, SIGKILL)

  • Using an incorrect form of Entrypoint: the Entrypoint Form recommended is the exec form, like this one (This happened to me and solved my problem)

    ENTRYPOINT ["/app/bin/your-app", "arg1", "arg2"]

I based my answer on this post and this one

Related