moby: Cannot kill or detach a docker container using Ctrl-C or Ctrl-\
Hi,
Running docker 0.6.7 on Ubuntu 13.04.
I built a container whose CMD executes a uwsgi process (also tried with other executables). I run without detaching, and sigproxy is True.
Hitting Ctrl-C seems to have no effect over the running container and the only way to leave it or kill it is with docker kill
and docker stop
…
Is this a known issue?
About this issue
- Original URL
- State: closed
- Created 11 years ago
- Reactions: 9
- Comments: 74 (18 by maintainers)
Links to this issue
Commits related to this issue
- Dockerise the project Add a basic Dockerfile, using a lightweight node image to speed and size. Structure the Dockerfile to take advantage of layer caching. Dockerfile based on: - https://nodejs.org... — committed to dsingleton/unit-tracker by dsingleton 6 years ago
- adds -d thanks to https://github.com/moby/moby/issues/2838 — committed to Amdingo/fleapday by Amdingo 5 years ago
- Handle SIGINT signals Without this commit, you have to provide the --init argument to Docker. See https://github.com/moby/moby/issues/2838#issuecomment-402491110 This also adds a test that verifies ... — committed to tonari/backend by schra 5 years ago
- Fix ctrl+c by using -it Without `-it` ctrl+c won't work, TESTED BY ME ON windows. Issue resolved at link - https://github.com/moby/moby/issues/2838#issuecomment-29176882 — committed to CrescentKohana/docker-hy.github.io by sahilrajput03 4 years ago
Starting with docker 0.6.5, you can add
-t
to thedocker run
command, which will attach a pseudo-TTY. Then you can typeControl-C
to detach from the container without terminating it.If you use
-t
and-i
thenControl-C
will terminate the container. When using-i
with-t
then you have to useControl-P Control-Q
to detach without terminating.Test 1:
The container is still listed.
Test 2:
the container is not there (it has been terminated). If you type
Control-P Control-Q
instead ofControl-C
in the 2nd example, the container would still be running.A pull request to fix the docs for the Hello World daemon sample is here:
https://github.com/dotcloud/docker/pull/2845
I’m unaware of where you saw the recommendation to
Control-C
outside of this example. If you saw this reference somewhere else, can you please submit a new pull request to fix the docs you referenced?You might also find this mailing list thread helpful.
From what I can gather you need both
-t
and-i
for Ctrl-C to work as expected…@felipekm Try adding
--init
when starting your container. This will start Tini as PID 1, and Tini will ensure your application gets SIGINT (instead of being intercepted by /bin/sh).More details in the thread above.
Why was this closed? Can you please explain the reason?
I asked because it is obvious that the majority of the community does not want the current default behavior.
Also note that ctrl+pq does not work on Mac OS X running Ubuntu in VirtualBox.
1 year later we still can’t Ctrl+C a docker container
To have ctrl+c stop the container you must use -it To detach from the container you should use ctrl+pq
Closing.
Still don’t get it. Why Ctrl-C doesn’t send SIGINT?
I am VERY confused by all this.
The default behaviour when being in a shell prompt is that ^C kills the running foreground process. And if no such process exists, it just do nothing, except maybe show a new prompt. ^D on the other hand do exit the shell, without stopping the machine. This is what I expect, because this is what everyone else do.
So, why do Docker do it differently? And why do I read this strange discussion? Am I missing something?
@sebdelvalle You can. It’s just that not all docker containers respond to Ctrl+C. If you created software running in a docker container it’s your responsibility to handle Ctrl+C properly. If you don’t shutdown your software on Ctrl+C nobody will do it for you.
You see, when you run your software without docker you have a terminal and init system which does handle Ctrl+C. When you run it in docker, you don’t have any terminals. Your software becomes the system’s entrypoint. It’s like booting your software straight from reboot.
Just adding this as additional information (some of which is mentioned in earlier comments);
While using
--init
(or addingtini
in your image) can be a quick way to help with images that don’t handle signals properly, be sure you’re not “masking” an actual problem with the image.Tini provides the following features;
If you know that the process running inside the container is a “bad actor”, and doesn’t handle reaping, using
--init
is definitely a good choice to get you going. Be aware though, that you’re effectively running into a bug; be sure to report the issue with the maintainer/publisher of the software you’re running in the container: perhaps they’re not aware of this situation, and can fix it.If you’re using
--init
because of2.
, this may be because the image you’re running was not well-designed; Is the container’s main process actually the main process, or is it running in a shell?For example; the following
CMD
will start a shell (/bin/sh
or/bin/bash
, depending on the image) in whichmysqld
is started;Because of this,
/bin/sh
(notmysqld
) has become the container’s main process (PID-1), and any signal sent to the container will be handled by/bin/sh
(and not forwarded tomysqld
). Using--init
will “resolve” that situation (/bin/sh
now runs as PID-2, andmysqld
runs as PID-3), but still runs an unnescessary shell process in the container.To make the container’s process run without a shell, use the JSON (“exec” form). For example, below is the
CMD
for the official mysql image;But what if you need to run some commands when starting the container (before running the container’s main process), such as setting permissions, or doing some setup the first time the container is run?
These steps can be done in an entrypoint-script. The entrypoint script can run a shell, perform initialization (see for example the init steps in the official WordPress entrypoint script), and at the end switch to the container’s main process using
exec
.When using
exec
, the current process is replaced with another process, so when usingexec
at the end of the entrypoint script, the container’s main process will run as PID-1, and not be running inside a shell; here’s the last line of the WordPress entrypoint script;The Dockerfile uses both an
ENTRYPOINT
andCMD
, in which caseCMD
is used as parameter for theENTRYPOINT
;exec "$@"
will thus default toexec apache2-foreground
, but will be replaced with the command that’s used to start the container (for exampledocker run mysql echo "hello"
, will run the entrypoint script, thenexec echo "hello"
)TL;DR; the
--init
option is safe to use, and may help your situation, but be sure you’re not tapering over the actual problem in the image 😄@johshoff It depends on how
ping
was started by the image. Is it running inside a/bin/sh
? If so, the signal is sent to/bin/sh
, which ignores signals when run as pid 1.You can tell node.js to handle the signals:
If you don’t need
sh
, don’t run it; usingexec
saves you from one extra process running inside the container, which may be helpful.(Also, using
docker run --init
will automatically injecttini
in your container, without the need to add it)I had the same issue with my node.js apps… I fixed it with
Now it’s 2 years 🎂 Still getting the error on MacOSX.
I’m still confused about this. Example run:
So ctrl+c doesn’t send SIGINT to either the docker process or the ping process. Is
docker stop
my only option here? (ctrl+p, ctrl+c does also not work. I’m on OSX)This fixed my issue with
ctrl-c
not working, AND restored the output coloring in my terminal (present when running server outside docker).Thanks @FossPrime !
Can’t detach with CTRL+P,CTRL+Q in my Ubuntu 17.04 OS. Arrrghh
It’s possible to enable the init option as a default (by setting a daemon option); then all container, including those started as part of a service get
--init
. There’s a PR in progress https://github.com/docker/cli/pull/479Quoting my recommendation above:
Now you don’t care whether you use
sh
or you not in CMD.Another way if you’re using node like @alvarow you can use
npm start
and a rule inpackage.json
and npm will shut down onctrl-c
:Like this:
Put this to your alpine 3.4 Dockerfile:
And you’re good to go.
So there’s shell form and exec form. Shell form is used like this:
Exec form like this:
In first case the shell handles your signal, in the second case the nginx process
In summary:
docker run -it
won’t be enough if the program you run doesn’t handle it. specially problematic if it’s not your program… such as is the case when another program interprets your program in a limited way.ENTRYPOINT ["/sbin/tini", "--"]
the entry point… instead of your app.docker run -it --init
which will solve all your problems.@guiambros that is so useful it’s going in my aliases.
@felipekm in another terminal type
docker ps
and thendocker stop <container_id>
If you want
Ctrl+C
to work you’ll need to change your docker container to respond toSIGINT
.Here is my understanding of it.
When writing a Dockerfile, there are two commands relating to starting the container process:
ENTRYPOINT
andCMD
.ENTRYPOINT
defines the executable to be launched, andCMD
defines the arguments to be passed to the executable. By default,ENTRYPOINT
is equal to/bin/sh
.Therefore, when a Dockerfile doesn’t have a
ENTRYPOINT
and only has aCMD "node src/index.js"
, the process that is actually running in the container is something like:/bin/sh -c "node src/index.js"
Now for some reason I do not fully understand, when
sh
receives a SIGINT, whether it is through adocker stop
orctrl-c
indocker run -it ...
, it does not forward this signal to the process it started (node src/index.js
in that case).So the correct way of defining a Dockerfile to run a nodejs container would be:
Where
src/index.js
features a signal handler for SIGINT. Now,docker stop <container>
works perfectly.This can easily be reproduced for other types of processes, so I hope it helps 😃
@montanaflynn it was able just open another tab from terminal and put:
docker stop <container_id>
I agree with @cpuguy83 in that I don’t see a problem with docker here, the annoyance come from the fact that the signal is sent to
/bin/sh
. The very simple solution to this is usewhich replaces the shell process with the ping process instead of
When using
sh -c "exec ping google.com"
the signal (Ctrl-C) is sent toping
opposed tosh
. And ping does not ignore this signal when run as pid 1No, /bin/sh doesn’t ignore Ctrl-C. Ping doesn’t ignore it either. The issue here is missing
-t
flag:should’ve been
E.g.:
vs
vs
vs
The kernel doesn’t ignore it, the process does.
@rolkar Because there are two foreground processes in this case. The process you’re attached to in the container and the docker client.
I personally think this should behave in much the same way as SSH, though with a different escape sequence. FYI SSH’s escape sequence is
<enter>~.
Also for swarm mode:
The corresponding compose change was recently merged, so in the next version you’d be able to do this:
Finally you won’t have to modify images just to add
tini
so that your containers aren’t killed (exit code 137) when not responding to SIGTERM. Especially useful for databases to prevent data loss.Update: This has been answered here https://github.com/moby/moby/issues/37200
Real world use-case: running Docker container with tests inside CI with:
The CI does not support TTY so I get:
How do I propagate a SIGTERM up to the container entrypoint when I don’t have a TTY?
My desired process tree:
CI runner will send a SIGTERM to the bash script that will propagate to the docker run but since there is no TTY support it can’t run with -ti.
This works in my terminal.
You’re starting apache using
apache2-foreground
but then daemonize it using&
?Thanks, @cpuguy83, that makes it clearer.
ping
was indeed running under/bin/sh
.@Vanuan Yes, this is exactly as I said. The signal is still sent to the program, the program just doesn’t respond to it.
@lhazlewood Because the issue wasn’t about ctrl+pq it was about getting out of attach with ctrl-c, which is not supported since “attach” is litterally attaching you to the running process and should be expected behavior. If you just want the stdout+stderr streams you should use
docker logs
not attach. I see this as a training issue and not a Docker issue.If we want to discuss changing ctrl-pq, and I know I’ve seen other issues around it that’s fine. I’m not sure that we can change it at this point. We talked about introducing a configurable command for it but was implemented server side and just wasn’t ideal and implementing it client-side is difficult.
And I write all this in the friendliest of tone, I’m terse by nature, sorry about that.