Как исправить ctrl+c внутри контейнера докеров

Если я подключаюсь к док-контейнеру

$> docker exec -it my_container zsh

и внутри него я хочу убить то, с чего начал ctrl+c Я заметил, что это занимает целую вечность. Я погуглил, и кажется, что ctrl+c работает немного иначе, чем вы ожидаете. Мой вопрос, как я могу исправить ctrl+c внутри контейнера?


person Jeanluca Scaljeri    schedule 12.12.2016    source источник


Ответы (8)


Проблема в том, что Ctrl-C посылает сигнал процессу верхнего уровня внутри контейнера, но этот процесс не обязательно реагирует так, как вы ожидаете. Процесс верхнего уровня имеет идентификатор 1 внутри контейнера, что означает, что он не получает обработчики сигналов по умолчанию, которые обычно имеют процессы. Если процесс верхнего уровня является оболочкой, то он может получать сигнал через свой собственный обработчик, но не перенаправляет его команде, которая выполняется внутри оболочки. Подробности объясняются здесь. В обоих случаях док-контейнер действует так, как будто он просто игнорирует Ctrl-C.

Начиная с docker 0.6.5, вы можете добавить -t к команде запуска docker, которая прикрепит файл pseudo-TTY. Затем вы можете ввести Control-C, чтобы отсоединиться от контейнера, не прерывая его.

Если вы используете -t и -i, то Control-C завершит работу контейнера. При использовании -i with -t вам нужно использовать Control-P Control-Q для отсоединения без завершения.

Тест 1:

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

Контейнер все еще указан.

Тест 2:

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

контейнера там нет (он был завершен). Если вы наберете Control-P Control-Q вместо Control-C во втором примере, контейнер все равно будет работать.

Оберните программу bash-скриптом docker-entrypoint.sh, который блокирует процесс контейнера и способен перехватывать ctrl-c. Этот пример bash может помочь: 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
person NID    schedule 12.12.2016
comment
У меня сложилось впечатление (и, пожалуйста, поправьте меня, если я ошибаюсь), что то, что вы описываете ctrl+c, предназначено для выхода из контейнера, а это не то, чего я хочу. Я хочу остановить программу, которую я запустил вручную - person Jeanluca Scaljeri; 12.12.2016
comment
Пожалуйста, уточните, как скрипт будет блокировать процесс контейнера и что предполагается делать в ловушке Ctrl-C. - person Greg Bell; 07.01.2017
comment
OT: Я думаю, что остановка контейнера с помощью CTRL+C — это плохая идея... Я продолжаю случайно останавливать контейнер просто из-за привычки таким образом выходить из процесса оболочки. - person Maciek Rek; 08.08.2020
comment
Спасибо! Теперь я точно знаю, почему было бы неплохо всегда добавлять -it. Кстати, это тоже легко запомнить. Просто docker run -it ...! :-Д - person RayLuo; 06.02.2021

Используйте Ctrl+\ вместо Ctrl+C
, это убивает процесс, а не вежливо просит его выключить. (Подробнее читайте здесь.)

person asedsami    schedule 30.12.2016
comment
У меня не работает. Когда запущенный докер-контейнер не отвечает на Ctrl+C, он также игнорирует Ctrl+\ - person eNca; 16.08.2019
comment
FML у меня нет английской раскладки клавиатуры - person gekkedev; 18.01.2021

В некоторых случаях, когда я использовал ctrl-C для завершения процесса внутри контейнера, контейнер завершался.

Кроме того, я видел случаи, когда процессы, работающие внутри контейнеров, покидали процессы-зомби.

Я обнаружил, что при запуске контейнера с ключом "--init" решаются обе эти проблемы. Похоже, это заставляет мои контейнеры работать более «нормальным, ожидаемым UNIX-подобным образом».

Если вам нужна дополнительная информация о том, что делает переключатель «--init», ознакомьтесь с ним на веб-страницах Docker, которые включают информацию о «запуске докера». Информация на этой веб-странице гласит: «Запустите инициализацию внутри контейнера, который пересылает сигналы и собирает процессы».

person Remy Orange    schedule 07.04.2020

У меня была похожая проблема, когда я пытался запустить mdbook (исполняемый файл Rust) в контейнере докера. mdbook запускает простой веб-сервер, и я хочу остановить его с помощью Ctrl+C, что не сработало.

$ 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

Вдохновившись ответом @NID, я инкапсулировал исполняемый файл mdbook с помощью универсального скрипта bash docker-entrypoint.sh, который сделал свое дело (без необходимости явно перехватывать сигнал INT).

$ 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 $

Содержание docker-entrypoint.sh очень простое:

#!/bin/bash

$@
person eNca    schedule 16.08.2019
comment
Это хорошо, спасибо. Единственный недостаток, который я вижу в этом, заключается в том, что вам нужно записать всю команду - person Jeanluca Scaljeri; 18.08.2019
comment
Откройте ваш любимый редактор, напишите там две упомянутые выше строки и сохраните его как docker-entrypoint.sh :-) Затем добавьте этот файл в образ с помощью команды ADD в вашем Dockerfile. - person eNca; 29.02.2020

Я попробовал решение --init от @Remy Orange, и оно сработало для меня. После некоторого поиска, в том числе i) Как использовать параметр --init в докере run, ii) В чем преимущество Tini? и iii) init я написал подробное решение ниже:

  1. Установите tini в Ubuntu:
  • через запуск:
$ sudo apt update && sudo apt install tini
  • Или, если tini недоступен в вашем дистрибутиве или слишком стар, проверьте Dockerfile, чтобы добавить tini по адресу здесь.
  1. Запустите свой контейнер Docker с помощью --init:
docker run -ti --init --rm YOUR_DOCKER_CONTAINER_EXMAPLE bash
  1. Затем вы заходите в свой док-контейнер и можете запускать какие-то процессы или эксперименты. Например, запустите код Python, затем вы можете запустить Ctrl + C, чтобы отменить этот код Python, точно так же, как вы можете сделать в Ubuntu (т. Е. Обычный терминал, который находится вне контейнера докера).

  2. Смотрите скриншот в моем случае:

  • запуск Ctrl + C (i.e., ^C) для отмены процесса Python: введите здесь описание изображения

  • Он останавливается, показывая KeyboardInterrupt как и ожидалось: введите здесь описание изображения

person ccj5351    schedule 23.06.2020
comment
Я использую Убунту 16.04. - person ccj5351; 23.06.2020
comment
Или вы также можете 1) запустить docker exec -it SOME_CONTAINER_ID ps -aus, чтобы найти SOME_PID в контейнере; затем 2) запустите docker exec -it SOME_CONTAINER_ID kill -9 SOME_PID, чтобы убить процесс внутри контейнера докера. - person ccj5351; 28.06.2020

Потерял около 2 часов.

Новые команды -- (работают нормально)

sudo docker stop 
sudo docker rm   
sudo docker run -t

Старые команды -- (больше не работают)

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

Надеюсь, это поможет кому-то.

person Manohar Reddy Poreddy    schedule 04.01.2020

Если вы используете Docker Compose, вы можете добавить init для пересылки сигналов в контейнер:

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

Чтобы это работало, вам нужно иметь опцию -ti в вашей команде docker exec.

person Kwadz    schedule 02.02.2021

У кого все еще есть эта проблема, у меня работал Ctrl+d. Ни Ctrl+c, ни Ctrl+z не работали.

person Gi Tavares    schedule 03.08.2020
comment
Ctrl+Z отлично работает после запуска докера, спасибо! - person Nigrimmist; 03.01.2021