Чи можливо запустити сеанс оболонки в запущеному контейнері (без ssh)


341

Я наївно очікував, що ця команда запустить bash shell у запущеному контейнері:

docker run "id of running container" /bin/bash

схоже, це неможливо, я отримую помилку:

2013/07/27 20:00:24 Internal server error: 404 trying to fetch remote history for 27d757283842

Отже, якщо я хочу запустити bash shell у запущеному контейнері (наприклад, для діагностики)

чи потрібно запускати на ньому SSH-сервер та входити через ssh?


1
docker run CONTAINERпланується в 1.0
колипто

7
Оскільки докер 1.3 ви дійсно повинні зробити так, як описано у цій відповіді
Thomasleveil

1
простоdocker attach container_name
maxbellec

1
Здається, що друга відповідь сьогодні набагато краща, ніж прискорена - ви могли б переглянути зміну прийнятої відповіді?
jsbueno

Відповіді:


285

EDIT: Тепер ви можете використовувати docker exec -it "id of running container" bash( doc )

Раніше відповідь на це питання була:

Якщо ви дійсно повинні, і ви знаходитесь в середовищі налагодження, ви можете зробити це: sudo lxc-attach -n <ID> Зауважте, що ідентифікатор повинен бути повним ( docker ps -notrunc).

Однак настійно рекомендую проти цього.

повідомлення: -notruncзастаріло, воно буде замінено --no-truncнайближчим часом.


1
чому ти рекомендуєш проти цього?
Макс Л.

7
Я рекомендую проти цього, оскільки 1) воно вимагає зовсім недавнього ядра; Також докер може зараз використовувати lxc, але немає гарантії, що це буде робити це назавжди.
скрип

1
Спробуйте оновити до 0.7.6. Докер досі використовує lxc і lxc-attachповинен працювати чудово. Я просто подвоїв перевірку, і це працює на мене. (Зверніть увагу, що воно не працюватиме з ядром до 3.8).
скрип

2
станом на 0,9 докер за замовчуванням більше не працює з LXC. Вам слід було б запустити docker -d -e lxc
докерного димана

2
Макс Л., ваш випадок використання можна вирішити за допомогою обсягів даних . Чи не тестувався приклад: 1) запустити контейнер з Nginx колод в обсязі даних: docker run -v /var/log/nginx -name somename imagename command; 2) запустити інший контейнер для перегляду вмісту томи даних: docker run -volumes-from somename -i -t busybox /bin/sh.
ciastek

615

З докер 1.3 є нова команда docker exec. Це дозволяє ввести запущений докер:

docker exec -it "id of running container" bash

2
Це спрацювало для мене чудово. Дуже корисне доповнення для запуску докера.
oraserrata

Що робити, якщо я вносив зміни під час виконання запущеного контейнера і хотів відобразити зміни в Інтернеті? які найкращі практики?
mediaroot

Дуже корисний. Дякую
luongnv89

використовувати, docker psщоб отримати ідентифікатор запущених екземплярів
muon

Примітка: У контейнера може бути не bash (»exec:" bash ": виконавчий файл не знайдено«). Використовуйте, docker inspect <image>щоб побачити, яка оболонка доступна. Наприклад, docker exec -it <container id> /bin/shзамість цього запустіть .
піксельні брекети

14

Просто роби

docker attach container_name

Як зазначалося в коментарях, щоб від'єднатись від контейнера, не зупиняючи його, наберіть Ctrlpпотім Ctrlq.


5
Дякую!! Це допомогло. І в контексті власне питання я хотів би щось додати. Після налагодження нашого контейнера використовуйте, docker attach container_nameвикористовуйте ctrl pта ctrl qзамість цього exit. exitкоманда зупиняє контейнер, де як ctrlpі ctrl qпросто від'єднує цей контейнер і продовжує його працювати
Phoenix

10

Оскільки речі змінюються, на даний момент використовується рекомендований спосіб доступу до запущеного контейнера nsenter.

Ви можете знайти більше інформації в цьому сховищі github . Але загалом ви можете використовувати nsenter так:

PID=$(docker inspect --format {{.State.Pid}} <container_name_or_ID>)
nsenter --target $PID --mount --uts --ipc --net --pid

або ви можете використовувати обгортку docker-enter:

docker-enter <container_name_or_ID>

Приємне пояснення по темі можна знайти в записі в блозі Jérôme Petazzoni: Чому вам не потрібно запускати sshd у ваших докерних контейнерах


на жаль, змінні env змішуються за допомогою цього підходу (якщо ви хочете перевірити змінні, створені за посиланням). Я пропоную зробити source /proc/*/environ.
Томаш Томечек

8

Перше, що ти не можеш запустити

docker run "existing container" command

Оскільки ця команда очікує зображення, а не контейнер, і в будь-якому випадку це призведе до породження нового контейнера (не того, якого ви хотіли переглянути)

Я погоджуюся з тим, що з docker ми повинні змусити себе мислити по-іншому (тому ви повинні знайти способи, щоб вам не потрібно було входити в контейнер), але я все-таки вважаю це корисним, і ось як я працюю навколо нього.

Я запускаю свої команди через супервізор в режимі DEAMON.

Тоді я виконую те, що я називаю docker_loop.sh . Вміст приблизно такий:

#!/bin/bash
/usr/bin/supervisord
/usr/bin/supervisorctl
while ( true )
    do
    echo "Detach with Ctrl-p Ctrl-q. Dropping to shell"
    sleep 1
    /bin/bash
done

Що це робить, це те, що дозволяє "приєднати" до контейнера і представити supervisorctlінтерфейс для зупинки / запуску / перезавантаження та перевірки журналів. Якщо цього не повинно вистачити, ви можете, Ctrl+Dі ви потрапите в оболонку, яка дозволить вам зазирнути, ніби це була звичайна система.

ЗАБУДУЙТЕ ТАКОЖ ВІДПОВІДАТИСЯ НА РОЗВИТОК, що ця система не настільки безпечна, як контейнер без оболонки, тому вживайте всіх необхідних заходів, щоб закріпити контейнер.


5

Слідкуйте за цим запитом на потяг: https://github.com/docker/docker/pull/7409

Яка реалізує майбутню docker exec <container_id> <command>утиліту. Коли це доступно, слід мати можливість, наприклад, запустити та зупинити службу ssh всередині запущеного контейнера.

Для цього також nsinitпотрібно зробити: "nsinit надає зручний спосіб доступу до оболонки всередині простору імен запущеного контейнера" , але запускати його важко. https://gist.github.com/ubergarm/ed42ebbea293350c30a6


docker execприземлився в Docker 1.3, тому тепер можна створити і приєднатись до нового сеансу оболонки в запущеному контейнері
foz


1

Насправді є спосіб мати оболонку в контейнері.

Припустимо, що ви /root/run.shзапускаєте процес, менеджер процесів (керівник) чи будь-що інше.

Створіть за /root/runme.shдопомогою декількох фокусів на gnu-екрані:

# Spawn a screen with two tabs
screen -AdmS 'main' /root/run.sh
screen -S 'main' -X screen bash -l
screen -r 'main'

Тепер ви маєте свої демони на вкладці 0 та інтерактивну оболонку в вкладці 1. docker attachв будь-який час, щоб побачити, що відбувається всередині контейнера.

Ще одна порада - створити зображення «розшарування розробки» поверх виробничого зображення з усіма необхідними інструментами, включаючи цей екранний трюк.


1

ось моє рішення

частина DOckerfile:

...
RUN mkdir -p /opt
ADD initd.sh /opt/
RUN chmod +x /opt/initd.sh
ENTRYPOINT ["/opt/initd.sh"]

частина "initd.sh"

#!/bin/bash
...
/etc/init.d/gearman-job-server start
/etc/init.d/supervisor start
#very important!!!
/bin/bash

після побудови зображення у вас є два варіанти, використовуючи exec та вкласти:

  1. за допомогою exec (яким я користуюсь) запустіть:

docker run - ім’я $ CONTAINER_NAME -dt $ IMAGE_NAME

тоді

docker exec - це $ CONTAINER_NAME / bin / bash

і використовувати

CTRL + D для від'єднання

  1. із вкладкою, запустіть:

запустити докер - ім’я $ CONTAINER_NAME -dit $ IMAGE_NAME

тоді

докер приєднати $ CONTAINER_NAME

і використовувати

CTRL + P і CTRL + Q від'єднати

різниця між параметрами в параметрі -i


1

Є два способи.

З кріпленням

$ sudo docker attach 665b4a1e17b6 #by ID

З викон

$ sudo docker exec - -t 665b4a1e17b6 #by ID


0

Корисно призначити ім'я під час запуску контейнера. Вам не потрібно посилатися на контейнер_id.

docker run --name container_name yourimage docker exec -it container_name bash


0

спочатку отримайте ідентифікатор контейнера потрібного контейнера за

docker ps

ви отримаєте щось подібне:

CONTAINER ID        IMAGE                  COMMAND             CREATED             STATUS                          PORTS                    NAMES
3ac548b6b315        frontend_react-web     "npm run start"     48 seconds ago      Up 47 seconds                   0.0.0.0:3000->3000/tcp   frontend_react-web_1

тепер скопіюйте цей ідентифікатор контейнера та запустіть таку команду:

docker exec -it container_id sh

docker exec -it 3ac548b6b315 sh


-2

Можливо, ви були введені в оману, як я міркував над термінами VM під час розробки контейнерів. Моя порада: Спробуйте не робити.

Контейнери - це як і будь-який інший процес. Дійсно, ви можете «прив’язати» їх до налагодження (подумайте про / proc // env або strace -p), але це дуже особливий випадок.

Зазвичай ви просто "запускаєте" процес, тому, якщо ви хочете змінити конфігурацію або прочитати журнали, просто створіть новий контейнер і переконайтеся, що ви пишете журнали поза ним, обмінюючись каталогами, пишучи в stdout (так докерські журнали працюють) чи щось подібне.

Для налагодження ви можете запустити оболонку, потім ваш код, а потім натисніть CTRL-p + CTRL-q, щоб залишити оболонку недоторканою. Таким чином ви можете повторно вкласти, використовуючи:

docker attach <container_id>

Якщо ви хочете налагодити контейнер, оскільки він робить щось, чого ви цього не очікували, спробуйте його налагодити: /server/596994/how-can-i-debug-a-docker-container -ініціалізація


Це абсолютно неправильно. Можливість проаналізувати простір імен LXC, у якому працює ваша програма, не є «особливим випадком», це звичайна / щоденна діяльність для будь-якого розробника.
сонливий

@sleepycal "будь-який розробник" звучить трохи упереджено. У будь-якому випадку я використовую самоаналіз процесів, тому те саме стосується контейнерів. Ось ідея налагодження. Ви додаєте відладчик до процесу (який може мати кліп). Думаючи, що ви "ввійшли" в контейнер, для мене все ще вводять в оману.
estani

-4

Ні. Це неможливо. Використовуйте щось на зразок, supervisordщоб отримати ssh-сервер, якщо це потрібно. Хоча, я точно сумніваюся у необхідності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.