How to fix ctrl+c inside a docker container
Asked Answered
S

11

65

If I connect to a docker container

$> docker exec -it my_container zsh

and inside it I want to kill something I started with ctrl+c I noticed that it takes forever to complete. I've googled around and it seems that ctrl+c works a bit different than you would expect. My question, how can I fix ctrl+c inside a container ?

Solutrean answered 12/12, 2016 at 9:26 Comment(0)
I
75

The problem is that Ctrl-C sends a signal to the top-level process inside the container, but that process doesn't necessarily react as you would expect. The top-level process has ID 1 inside the container, which means that it doesn't get the default signal handlers that processes usually have. If the top-level process is a shell, then it can receive the signal through its own handler, but doesn't forward it to the command that is executed within the shell. Details are explained here. In both cases, the docker container acts as if it simply ignores Ctrl-C.

Starting with docker 0.6.5, you can add -t to the docker run command, which will attach a pseudo-TTY. Then you can type Control-C to detach from the container without terminating it.

If you use -t and -i then Control-C will terminate the container. When using -i with -t then you have to use Control-P Control-Q to detach without terminating.

Test 1:

$ ID=$(sudo docker run -t -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-P Control-Q
$ sudo docker ps

The container is still listed.

Test 2:

$ ID=$(sudo docker run -t -i -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-C
$ sudo docker ps

the container is not there (it has been terminated). If you type Control-P Control-Q instead of Control-C in the 2nd example, the container would still be running.

Wrap the program with a docker-entrypoint.sh bash script that blocks the container process and is able to catch ctrl-c. This bash example might help: https://rimuhosting.com/knowledgebase/linux/misc/trapping-ctrl-c-in-bash

#!/bin/bash

# trap ctrl-c and call ctrl_c()
trap ctrl_c INT

function ctrl_c() {
        echo "** Trapped CTRL-C"
}

for i in `seq 1 5`; do
    sleep 1
    echo -n "."
done
Insensible answered 12/12, 2016 at 10:44 Comment(4)
I get the impression (and please correct me if I'm wrong) that what you describe ctrl+c is for exiting the container, which is not what I want. I want to stop a program I'v manually startedSolutrean
Please elaborate on how a script would block the container process, and what is supposed to be done in the Ctrl-C trap.Bristle
OT: I think stopping the container with CTRL+C is a bad design...I keep accidentally stopping the container simply because of a habit of exiting shell process this way.Blotch
Thanks! Now I really know why it would be a good idea to always add -it. By the way, it is easy to remember too. Just docker run -it ...! :-DDiogenes
W
23

In some cases, when I used ctrl-C to terminate a process inside a container, the container terminates.

Additionally, I've seen cases where processes running inside containers leave zombie processes.

I have found that when starting a container with the --init switch, both of these problems are addressed. This appears to make my containers operate in a more "normal, expected UNIX-like manner".

Note: --init is different from -i, which is short for --interactive

If you want more information on what the --init switch does, please read up on it on the Docker web pages that include information on docker run. The information on that web page says "Run an init inside the container that forwards signals and reaps processes".

Wolf answered 7/4, 2020 at 15:17 Comment(1)
The solution that really works for me.Berneicebernelle
B
19

Use Ctrl+\ instead of Ctrl+C
it kills the process instead of politely asking it to shut down.(read more here.)

Balough answered 30/12, 2016 at 6:58 Comment(2)
It does not work for me. When the running docker container does not respond to Ctrl+C then it ignore Ctrl+\ tooEvoke
It worked for me. I was connected (ssh) to an EC2 instance (amazon Linux) on which I ran a docker container. I used iTerm2 on a Mac.Thruster
Y
9
when your docker terminal is not responding to Ctrl+C/Ctrl+D/Ctrl+/, try these steps:

#1>> Open another terminal session and enter the command:

    **`docker container ls`** 
        or
    **`docker container list`**


#2>> locate the container id from the above list and issue the docker container stop command:
    

**`docker stop <<containerId>>`**

#3>> next time when you launch the docker container, use the flag "**-it**"  to respond to the Ctrl+C event
    

docker run -it <>

    Now you can stop ,with control+C
Yale answered 25/6, 2022 at 13:49 Comment(2)
Easy and simple to use. ThanksBellow
Sadly this doesn't work for me.Reconstructionism
E
8

I had the similar problem when I was trying to run mdbook (the Rust executable) in the docker container. The mdbook starts simple webserver and I want to stop it via Ctrl+C which did not work.

$ docker -ti --rm -p 4321:4321 my-docker-image mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C^C

Be inspired by @NID's answer I encapsulated the mdbook executable by universal bash script docker-entrypoint.sh which did the trick (without the need to explicitly catch the INT signal).

$ docker -ti --rm -p 4321:4321 my-docker-image docker-entrypoint.sh mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C $

The content of the docker-entrypoint.sh is very simple:

#!/bin/bash

$@
Evoke answered 16/8, 2019 at 14:24 Comment(3)
This is nice, thnx. The only downside I see with this is that you have to write down the whole commandSolutrean
Open your favorite editor, write there the two lines mentioned above and save it as docker-entrypoint.sh :-) Then add this file to the image via ADD command in your Dockerfile.Evoke
I had a similar issue with mdbook and Ctrl+C, and adding --init worked for me. Here is my full command: docker run --rm -t -i --init -p 6400:6400 -v ${PWD}:/book $$(docker build -q .) mdbook serve --hostname 0.0.0.0 --port 6400 /book. The dockerfile does not include ENTRYPOINT.Sequin
F
6

I tried the --init solution by @Remy Orange and it worked for me. After some searching, including i)How to use --init parameter in docker run, ii) What is advantage of Tini? and iii) init, I wrote the detailed solution below:

  1. Install tini on Ubuntu:
  • via launching:
$ sudo apt update && sudo apt install tini
  • Or, if tini is not available in your distribution or is too old, please check a Dockerfile to add tini at here.
  1. Run your Docker container with --init:
docker run -ti --init --rm YOUR_DOCKER_CONTAINER_EXMAPLE bash
  1. Then you come into your docker container and you can run some processes or experiments. E.g., run a Python code, then you can launch Ctrl + C to cancel this Python code, just as what you can do on Ubuntu (i.e., the regular terminal which is outside the docker container).

  2. See the screenshot in my case:

  • launching Ctrl + C (i.e., ^C) to cancel the python process: enter image description here

  • It stops, showing KeyboardInterrupt as expected: enter image description here

Fernandefernandel answered 23/6, 2020 at 7:2 Comment(2)
I am using Ubuntu 16.04.Fernandefernandel
Or you can also 1) run "docker exec -it SOME_CONTAINER_ID ps -aus" to find the SOME_PID in the container; then 2) run "docker exec -it SOME_CONTAINER_ID kill -9 SOME_PID" to kill the process inside the docker container.Fernandefernandel
J
4

If you use Docker Compose, you can add the init parameter to forward signals to the container:

version: "2.4"
services:
  web:
    image: alpine:latest
    init: true

To make it work you need to have the option -ti in your docker exec command.

Judy answered 2/2, 2021 at 15:22 Comment(0)
L
3

Wasted about 2 hours.

New commands -- (Working fine)

sudo docker stop 
sudo docker rm   
sudo docker run -t

Old commands -- (Not working anymore)

sudo docker stop
sudo docker rm   
sudo docker run
Ctrl + C
sudo docker start

Hope that helps someone.

Ludicrous answered 4/1, 2020 at 9:33 Comment(0)
F
2

For whom still have this issue, worked for me the Ctrl+d. Neither Ctrl+c or Ctrl+z worked.

Farquhar answered 3/8, 2020 at 18:33 Comment(2)
Ctrl+Z works fine after docker run, thanks!Droop
@Droop noooooDandy
V
2

For me Ctrl+C works only after running a container with docker run -it <container id/name>

Veinstone answered 18/6, 2022 at 12:54 Comment(1)
This simply doesn't work for me.Reconstructionism
A
0

With the base image node:14, I could stop the container.

But when I tried node:18 and node:20 it stopped working.

I don't know what changed, but this is not convenient.

Fortunately, the workaround above helped me: press Control+\ to stop the container.

Adequate answered 12/2 at 13:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.