Почему Docker контейнер выходит немедленно


240

Я запускаю контейнер в фоновом режиме, используя

 docker run -d --name hadoop h_Service

это быстро выходит. Но если я бегу на переднем плане, все работает нормально. Я проверил журналы, используя

docker logs hadoop

ошибки не было Любые идеи?

DOCKERFILE

 FROM java_ubuntu_new
 RUN wget http://archive.cloudera.com/cdh4/one-click-install/precise/amd64/cdh4-repository_1.0_all.deb
 RUN dpkg -i cdh4-repository_1.0_all.deb
 RUN curl -s http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh/archive.key | apt-key add -
 RUN  apt-get update
 RUN apt-get install -y hadoop-0.20-conf-pseudo
 RUN dpkg -L hadoop-0.20-conf-pseudo
 USER hdfs
 RUN hdfs namenode -format
 USER root
 RUN apt-get install -y sudo
 ADD . /usr/local/
 RUN chmod 777 /usr/local/start-all.sh
 CMD ["/usr/local/start-all.sh"]

start-all.sh

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start
 /etc/init.d/hadoop-hdfs-datanode start
 /etc/init.d/hadoop-hdfs-secondarynamenode start
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start
 /bin/bash

1
Золотое правило заключается в том, что вы должны предотвращать демонизацию ваших докеризованных серверов. Большинство серверных пакетов имеют опции для принудительного их вывода на передний план, поскольку демонизация является нормальным случаем.
Арно Море

Все , что вы надеетесь достичь, chmod 777является небезопасным и неправильно. Вы должны вернуться к нормальным разрешениям (вероятно, 755 в этом случае).
tripleee

Ответы:


125

Контейнер Docker завершается, когда завершается его основной процесс.

В этом случае он завершится, когда start-all.shзакончится ваш скрипт. Я не знаю достаточно о hadoop, чтобы рассказать вам, как это сделать в этом случае, но вам нужно либо оставить что-то запущенное на переднем плане, либо использовать диспетчер процессов, такой как runit или supervisord, для запуска процессов.

Я думаю, вы должны ошибаться, если вы не укажете -d; это должно иметь точно такой же эффект. Я подозреваю, что вы запустили его с немного другой командой или с помощью -itкоторой что-то изменится.

Простое решение может быть добавить что-то вроде:

while true; do sleep 1000; done

до конца сценария. Однако мне это не нравится, так как скрипт должен реально отслеживать запущенные процессы.

(Я должен сказать, что украл этот код с https://github.com/sequenceiq/hadoop-docker/blob/master/bootstrap.sh )


218

Это помогло мне:

docker run -dit ubuntu

После этого я проверил процессы, запущенные с помощью:

docker ps -a

Для прикрепления контейнера

docker attach CONTAINER_NAME

СОВЕТ: Для выхода без остановки типа контейнера: ^P^Q


15
@Tommy, из docs.docker.com/engine/reference/commandline/run -d, --detach Отдельный режим: запустить команду в фоновом режиме, -i, --interactive Оставить STDIN открытым, даже если он не подключен, -t, - Выделить псевдо-TTY -ditпросто стенография

3
@ am17torres правильно, извините, позвольте мне прояснить мой запутанный вопрос; d отстранен и я интерактивен, поэтому сочетание d и i сбивает меня с толку. Я думал, что я должен был запустить его как фоновый (неинтерактивный) процесс.
Томми

2
@Tommy Когда эти параметры объединены, контейнер перейдет в интерактивный режим в фоновом режиме .
Йон

2
@Tommy, @ am17torres -di- необходимый минимум, этот -tпараметр является избыточным при использовании с, -dесли я правильно понимаю
Renaud

2
На самом деле вы не сможете увидеть ваше приглашение, если -tподключите его снова, но не включите его, но я обычно execкаждый раз получаю новый bash, когда не замечаю. У меня были проблемы с отсоединением от Mac, но, возможно, я делаю это неправильно ..
Renaud

65

Я хотел бы расширить или осмелиться сказать, улучшить ответ упомянутый camposer

Когда ты бежишь

docker run -dit ubuntu

вы в основном запускаете контейнер в фоновом режиме в интерактивном режиме.

Когда вы присоединяете и выходите из контейнера с помощью сочетания клавиш CTRL + D (наиболее распространенный способ сделать это), вы останавливаете контейнер, потому что вы просто уничтожили основной процесс, который вы запустили в свой контейнер с помощью приведенной выше команды.

Используя преимущества уже запущенного контейнера, я бы просто запустил еще один процесс bash и получил псевдо TTY, запустив:

docker exec -it <container ID> /bin/bash

29

всякий раз, когда я хочу, чтобы контейнер оставался после завершения выполнения скрипта, я добавляю

&& tail -f /dev/null

в конце команды. Так и должно быть:

/usr/local/start-all.sh && tail -f /dev/null

19

Почему Docker контейнер выходит немедленно?

Если вы хотите заставить изображение зависать (для того, чтобы что-то отладить или проверить состояние файловой системы), вы можете переопределить точку входа, чтобы изменить его на оболочку:

docker run -it --entrypoint=/bin/bash myimagename

18

Хорошим подходом было бы запустить ваши процессы и службы, запустив их в фоновом режиме, и использовать wait [n ...]команду в конце вашего скрипта. В bash команда ожидания заставляет текущий процесс:

Дождитесь каждого указанного процесса и верните его статус завершения. Если n не задано, ожидаются все активные в данный момент дочерние процессы, а статус возврата равен нулю.

Я получил эту идею из стартового сценария Себастьяна Пухадаса для его лося .

Исходя из исходного вопроса, ваш start-all.sh будет выглядеть примерно так ...

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start &
 /etc/init.d/hadoop-hdfs-datanode start &
 /etc/init.d/hadoop-hdfs-secondarynamenode start &
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start &
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start &
 wait

5

Добавьте это в конец Dockerfile:

CMD tail -f /dev/null

Пример файла Docker:

FROM ubuntu:16.04

# other commands

CMD tail -f /dev/null

Ссылка


CMD tail -f /dev/nullпроходит через это sh -c "...". Можем ли мы использовать execвместо этого форму? То естьCMD ["tail", "-f", "/dev/null"]
Мельо

4

Моя практика в Dockerfile запустить оболочку, которая не будет выходить сразу CMD [ "sh", "-c", "service ssh start; bash"], а затем запустить docker run -dit image_name. Таким образом, служба (ssh) и контейнер работают.


1

Я добавил readзаявление оболочки в конце. Это поддерживает основной процесс контейнера - сценарий запуска оболочки.


1

Добавление

exec "$@"

в конце моего сценария оболочки было мое исправление!


Это просто означает, что он запустит ваш cmd, если ваш cmd просто 'bash', то он все равно не будет работать
Shardj

1

Если вы проверяете Dockerfile из контейнеров, например fballiano / magento2-apache-php

вы увидите, что в конце своего файла он добавляет следующую команду: while true; спать 1; сделано

Теперь, что я рекомендую, это то, что вы делаете это

docker container ls --all | grep 127

Затем вы увидите, что в вашем образе докера произошла ошибка, если он завершился с 0, то, вероятно, ему нужна одна из этих команд, которая будет спать вечно.


0

Существует много возможных способов немедленного выхода из докера. Для меня это была проблема с моей Dockerfile. В этом файле была ошибка. Я имел ENTRYPOINT ["dotnet", "M4Movie_Api.dll]вместо ENTRYPOINT ["dotnet", "M4Movie_Api.dll"]. Как вы видите, я пропустил одну цитату (") в конце.

Чтобы проанализировать проблему, я запустил свой контейнер и быстро прикрепил свой контейнер, чтобы понять, в чем именно заключалась проблема.

C:\SVenu\M4Movie\Api\Api>docker start 4ea373efa21b


C:\SVenu\M4Movie\Api\Api>docker attach 4ea373efa21b

Где 4ea373efa21b - мой идентификатор контейнера. Это сводит меня к актуальной проблеме.

введите описание изображения здесь

После обнаружения проблемы мне пришлось снова собирать, восстанавливать, публиковать свой контейнер.


0

Исходя из дубликатов, я не вижу здесь никакого ответа, который бы касался очень распространенного антипаттерна, состоящего в том, чтобы выполнять основную рабочую нагрузку в качестве фонового задания, а затем удивляться, почему Docker завершает работу.

Проще говоря, если у вас есть

my-main-thing &

затем либо возьмите, &чтобы запустить задание на переднем плане, либо добавьте

wait

в конце скрипта, чтобы он дождался всех фоновых заданий.

Затем он все равно завершится, если основная рабочая нагрузка завершится, поэтому, возможно, запустите его в while trueцикле, чтобы принудительно перезапустить его навсегда:

while true; do
    my-main-thing &
    other things which need to happen while the main workload runs in the background
    maybe if you have such things
    wait
done

(Обратите также внимание на то, как писать while true. Часто можно видеть глупые вещи, которые, как это происходит, while [ true ]или while [ 1 ]которые случайно происходят, работают, но не имеют в виду то, что, по мнению автора, они должны иметь в виду.)


0

Вам нужно запустить его с флагом -d, чтобы он работал в фоновом режиме как демон.

docker run -d -it Ubuntu Bash


-5

Вы можете запустить контейнер, используя этот флаг перезапуска.

docker run -d --name=<some-name> -p xxxx:xxxx ... <image-name> --restart=unless-stopped

-8

Поскольку образ является linux, нужно проверить, чтобы все сценарии оболочки, используемые в контейнере, имели окончание строки Unix. Если у них есть ^ M в конце, то они являются окончаниями строки Windows. Один из способов исправить это с помощью dos2unix в /usr/local/start-all.sh, чтобы конвертировать их из windows в unix. Запуск докера в интерактивном режиме может помочь решить другие проблемы. Вы могли бы иметь опечатку имени файла или что-то. см. https://en.wikipedia.org/wiki/Newline

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.