Чому контейнер докер виходить негайно


239

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

 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 у цьому випадку).
трійка

Відповіді:


125

Контейнер докера виходить, коли його основний процес закінчується.

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

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

Простим рішенням може бути додати щось на кшталт:

while true; do sleep 1000; done

до кінця сценарію. Мені це не подобається, оскільки сценарій справді повинен стежити за процесами, які він розпочав.

(Я мушу сказати, що я вкрав цей код з https://github.com/sequenceiq/hadoop-docker/blob/master/bootstrap.sh )


217

Це зробило трюк для мене:

docker run -dit ubuntu

Після цього я перевірив процеси, що працюють, використовуючи:

docker ps -a

Для приєднання знову контейнера

docker attach CONTAINER_NAME

Порада: для виходу без зупинки типу контейнера: ^P^Q


15
@Tommy, від docs.docker.com/engine/reference/commandline/run -d, --встановити окремий режим: запустити команду у фоновому режимі, -i, --інтерактивний Тримайте STDIN відкритим, навіть якщо він не додається, -t, - -tty Виділити псевдо-TTY -dit- це просто стенограма

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

2
@Tommy Коли ці параметри поєднуються, контейнер перейде в інтерактивний режим у фоновому режимі .
Йон

2
@Tommy, @ am17torres -di- це мінімально необхідний -tпараметр, надлишковий при використанні, -dякщо я правильно розумію
Рено

2
Насправді ви не зможете побачити своє підказку, якщо повторно -tввімкнути без ввімкненого ... але оскільки я зазвичай execнову башти кожен раз, коли не помічаю. У мене виникли проблеми з від'єднанням від Mac, але, можливо, я роблю це неправильно ..
Рено

65

Я хотів би продовжити чи наважитися сказати, вдосконалити відповідь, згаданий композитором

Коли ти біжиш

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 run -it --entrypoint=/bin/bash myimagename

18

Хорошим підходом було б запустити ваші процеси та служби, які запускають їх у фоновому режимі та використовувати wait [n ...]команду в кінці сценарію. У bash команда wait примушує поточний процес:

Зачекайте кожного зазначеного процесу та поверніть його стан припинення. Якщо 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

Виходячи з дублікатів, я не бачу тут жодної відповіді, яка б стосувалась дуже поширеного антипаттера, який виконує ваше основне робоче навантаження як фонове завдання, а потім цікаво, чому Докер виходить.

Простіше кажучи, якщо у вас є

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 в кінці, то це закінчення вікон рядка. Один із способів виправити їх - за допомогою 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.