Как запустить остановленный контейнер Docker другой командой?


251

Я хотел бы запустить остановленный контейнер Docker с помощью другой команды, так как команда по умолчанию вылетает, то есть я не могу запустить контейнер и затем использовать 'docker exec'.

По сути, я хотел бы запустить оболочку, чтобы я мог проверить содержимое контейнера.

К счастью, я создал контейнер с опцией -it!

Ответы:


380

Найдите свой остановленный идентификатор контейнера

docker ps -a

Зафиксируйте остановленный контейнер:

Эта команда сохраняет измененное состояние контейнера в новом образе user/test_image

docker commit $CONTAINER_ID user/test_image

Запустите / запустите с другой точкой входа:

docker run -ti --entrypoint=sh user/test_image

Описание аргумента точки входа: https://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime

Примечание:

Шаги выше просто запустить остановленный контейнер с тем же состоянием файловой системы. Это отлично подходит для быстрого расследования. Но переменные среды, конфигурация сети, подключенные тома и другие сотрудники не наследуются, вы должны указать все эти аргументы явно.

Шаги для запуска остановленного контейнера были заимствованы отсюда: (последний комментарий) https://github.com/docker/docker/issues/18078


1
нет, изображения только для чтения. Сохраняет измененное состояние контейнера в новом образе. Test_image
Dmitriusan

4
это пропускает почти все настройки env, volume, UID, ... Все, что общего с остановленным контейнером, это файловая система (которой, может быть, хватит для некоторых)
Флориан Кляйн

4
Было бы здорово, если бы я мог как-то получить ту же среду, конфигурацию сети, подключенные тома. Можно ли преобразовать inspectвыходные данные в конфигурацию, которая используется при последующем запуске?
Отей

2
@ Webman, да, но это не так для томов, которые были смонтированы перед остановкой контейнера. При следующем запуске контейнера вам придется явно присоединить те же тома
Dmitriusan

1
@ EmreTapcı, я думаю, что это противоречит идеологии Докера. Контейнеры предназначены для одноразового использования, в отличие от виртуальных машин. Вы можете попытаться следовать ответу aaa90210 , но это будет взлом.
Дмитриусан

126

Отредактируйте этот файл (соответствующий вашему остановленному контейнеру):

vi /var/lib/docker/containers/923...4f6/config.json

Измените параметр «Path», чтобы он указывал на вашу новую команду, например / bin / bash. Вы также можете установить параметр «Args» для передачи аргументов в команду.

Перезапустите службу Docker (обратите внимание, что это остановит все запущенные контейнеры):

service docker restart

Перечислите ваши контейнеры и убедитесь, что команда изменилась:

docker ps -a

Запустите контейнер и прикрепите к нему, теперь вы должны быть в вашей оболочке!

docker start -ai mad_brattain

Работал на Fedora 22 с использованием Docker 1.7.1.

ПРИМЕЧАНИЕ. Если ваша оболочка не является интерактивной (например, вы не создали оригинальный контейнер с параметром -it), вместо этого вы можете изменить команду на «/ bin / sleep 600» или «/ bin / tail -f / dev / null» чтобы дать вам достаточно времени, чтобы сделать "docker exec -it CONTID / bin / bash" как еще один способ получения оболочки.

ПРИМЕЧАНИЕ 2. В более новых версиях Docker есть файл config.v2.json, в котором вам нужно будет изменить либо Entrypoint, либо Cmd (спасибо user60561).


44
мои глаза. мои глаза. Я надеюсь, что это где-то запрос функции для правильной обработки в Docker.
gertvdijk

2
@AlexeyStrakh вы можете попробовать запустить "/ usr / bin / sleep 600", а затем выполнить "docker exec -it / bin / bash", чтобы получить оболочку. Хотя я не уверен, как поместить параметры в эту переменную Path. В противном случае попробуйте найти другую команду, которая останется в живых достаточно долго, чтобы вы могли выполнить задание, или посмотрите ответ Дмитриусана.
aaa90210

3
это единственный действительно точный ответ на вопрос: все другие предложения запускают «почти такой же» контейнер, но они забывают о томах, env, UID,…
Флориан Кляйн

3
В моем случае / usr / bin / sleep не было доступно. У меня был успех с..."Path":"tail","Args":["-f","/dev/null"]...
nevrome

4
Новые версии докера есть config.v2.json, где вам нужно будет изменить либо Entrypointили Cmd.
user60561

20

Добавьте проверку в начало вашего скрипта Entrypoint

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

Если у вас еще нет сценария Entrypoint, создайте тот, который выполняет все команды, которые вам нужны для вашего контейнера. Затем в верхней части этого файла добавьте эти строки в entrypoint.sh:

# Run once, hold otherwise
if [ -f "already_ran" ]; then
    echo "Already ran the Entrypoint once. Holding indefinitely for debugging."
    cat
fi
touch already_ran

# Do your main things down here

Чтобы убедиться, что catсоединение удерживается, вам может потребоваться предоставить TTY. Я запускаю контейнер с моим скриптом Entrypoint следующим образом:

docker run -t --entrypoint entrypoint.sh image_name

Это приведет к тому, что скрипт будет запущен один раз, создав файл, который указывает, что он уже запущен (в виртуальной файловой системе контейнера). Затем вы можете перезапустить контейнер для выполнения отладки:

docker start container_name

Когда вы перезапустите контейнер, already_ranфайл будет найден, в результате чего скрипт Entrypoint остановится cat(который просто вечно ожидает ввода, который никогда не поступит, но сохраняет контейнер живым). Затем вы можете выполнить bashсеанс отладки :

docker exec -i container_name bash

Во время работы контейнера вы также можете удалить already_ranи вручную запустить entrypoint.shсценарий для его повторного запуска, если вам необходимо выполнить отладку таким способом.


3
Кроме того, вы можете запустить точку входа /bin/shвместо cat- тогда вы всегда можете войти, просто перезапустившись. Ваше решение ошеломляет!
Дэнни

4

Моя проблема:

  • Я начал контейнер с docker run <IMAGE_NAME>
  • А потом добавил несколько файлов в этот контейнер
  • Затем я закрыл контейнер и попытался запустить его снова той же командой, что и выше.
  • Но когда я проверял новые файлы, они отсутствовали
  • когда я бежал, docker ps -aя мог видеть два контейнера.
  • Это означает, что каждый раз, когда я запускал docker run <IMAGE_NAME>команду, создавался новый образ

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

  • docker ps получить контейнер вашего контейнера
  • docker container start <CONTAINER_ID> запустить существующий контейнер
  • Тогда вы можете продолжить с того места, где вы ушли. напримерdocker exec -it <CONTAINER_ID> /bin/bash
  • Затем вы можете решить создать новое изображение из него

Это не отвечает на вопрос. ОП хочет знать, как перезапустить контейнер, но с аргументами, отличными от тех, которые использовались вdocker run <containerID>
CodeBlooded

2

Я взял ответ @ Dmitriusan и превратил его в псевдоним:

псевдоним docker-run-prev-container = 'prev_container_id = "$ (docker ps -aq | head -n1)" && docker commit "$ prev_container_id" "prev_container / $ prev_container_id" && docker run -it --entrypoint = bash "prev_container / $ prev_container_id "»

Добавьте это в свой ~/.bashrcфайл псевдонимов, и у вас будет отличный новый docker-run-prev-containerпсевдоним, который поместит вас в оболочку в предыдущем контейнере.

Полезно для отладки не удалось docker builds.


2

Это не совсем то, что вы просите, но вы можете использовать docker exportостановленный контейнер, если вам нужно только проверить файлы.

mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR

1

Не было указано, выходит ли контейнер, только то, что ваш код падает, и вам нужно посмотреть, что происходит в контейнере. Если это не выход, вот еще одно потенциальное решение.

Получить идентификатор контейнера с docker ps

docker exec -it 665b4a1e17b6 /bin/sh

Если точка входа настроена на что-то проблематичное, она также может быть переопределена, как предлагается в ответе Дмитриусана. Следует также отметить, что вы можете прикрепить к любому работающему контейнеру с помощью docker attach. Так много решений, разные решения. Я просто не вижу необходимости фиксировать изображение. Это кажется ненужным.

Документы для Docker exec - https://docs.docker.com/engine/reference/commandline/exec/

Документы для прикрепления Docker - https://docs.docker.com/engine/reference/commandline/attach/


-12

Я на самом деле не согласен с обоими этими ответами. Если вы просто хотите увидеть, что находится в контейнере, вы можете запустить эту команду, чтобы получить оболочку. Не нужно менять точку входа вообще или какие-либо конфиги.

docker run -it <image_name> bash

12
Это не работает, так как оператор спрашивает о контейнере, а не об изображении.
Петр Врабель

Я полагаю, что вы правы, но не вижу причин для этого. Вы можете docker logs <container_id> --followпередавать логи в stdout и дать вам то, что вам нужно. Другой вариант - использовать указанную выше команду, а затем запустить службу аварийного завершения для этого образа с той же командой в файле docker и выполнить отладку оттуда.
deadbabykitten

4
Команда run создает новый контейнер из изображения. Он не запускает остановленный контейнер.
Валид Абдулла

2
Ммм ... не в этом ли смысл докера в том, что каждое изображение может вращаться одинаково? Это сводит на нет ваш аргумент. Ему НЕ НУЖНО запускать остановленный контейнер. Любой контейнер точно такой же, поэтому не имеет значения, какой контейнер он запускает или останавливает. Он просто пытается проверить содержимое. Самый простой способ сделать это - подключить и запустить вывод команды или канала команды в журналы. Вы, ребята, иногда предлагаете самые сложные решения простых проблем.
deadbabykitten

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