Запуск сценарію всередині контейнера докера за допомогою сценарію оболонки


85

Я намагаюся створити сценарій оболонки для налаштування контейнера докера. Мій файл сценарію виглядає так:

#!bin/bash

docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash

Запуск цього файлу сценарію запустить контейнер у щойно викликаному bash.

Тепер мені потрібно запустити файл скрипта (test.sh), який уже знаходиться в контейнері із вказаного вище сценарію оболонки. (Наприклад: cd /path/to/test.sh && ./test.sh) Як це зробити?


1
Чому б не використовувати WORKDIRі CMD?
Дхарміт

1
Ви, мабуть, не хочете використовувати тут --privileged. Дивіться: stackoverflow.com/questions/36425230/…
CMP

Відповіді:


121

Ви можете запустити команду в запущеному контейнері, використовуючи docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:

docker exec mycontainer /path/to/test.sh

І для запуску з сеансу bash:

docker exec -it mycontainer /bin/bash

Звідти ви можете запустити свій сценарій.


6
що, якщо мені спочатку потрібно увійти в / bin / bash, а потім запустити команду всередині цього bash?
zappy

44
Ви також можете запустити локальний сценарій безпосередньо з хосту. docker exec -i mycontainer bash < mylocal.sh Це читає сценарій локального хосту та запускає його всередині контейнера. Ви можете зробити це з іншими речами (наприклад, файлами .tgz, перекладеними у tar) - це просто за допомогою '-i' для введення даних std в процес контейнера.
Марвін

@Marvin, що еквівалентно в PowerShell? символ "<" не розпізнається.
Nicekiwi

1
Я не гуру PowerShell (на щастя), але я побродив навколо SO і знайшов stackoverflow.com/a/11788475/500902 . Тож, можливо Get-Content mylocal.sh | docker exec -i mycontainer bash. Я не знаю, чи це працює, хоча.
Марвін,

97

Припускаючи, що ваш контейнер докера запущений і працює, ви можете запускати команди як:

docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"

2
Мені подобається ця відповідь; вам не потрібно входити в контейнер докера для виконання команди або набору команд. Дякую!
Хатем Джабер

Чи знаєте ви, як зробити цей крок далі і передати всю команду ( /bin/sh -c "cmd1; cmd2; ...; cmdn") як значення змінної оболонки? Я запитую, тому що "запуск докера", здається, очікує однієї команди та окремих аргументів без котирувань, а не рядка в лапках.
davidA

@meowsqueak: Ця відповідь розповідає, як запускати декілька команд у вже створеному та запущеному контейнері без входу в цей контейнер, що корисно для автоматизації. Однак якщо ви хочете запускати кілька команд під час створення контейнера (PS: команда запуску докера створює та запускає контейнер), ви можете досягти цього, виконавши відповіді в цьому ж потоці stackoverflow.com/a/41363989/777617
Cyclops

Замість cmd1, мені потрібно передати цілий цикл for - але він очікує ;після оператора циклу та оператора do . Як я можу запустити весь цикл for-loop як одну команду, тобто cmd1? Це можливо?
Микола К

18

Я шукав відповідь на це саме питання і знайшов ENTRYPOINT у рішенні Dockerfile для мене.

Докерфайл

...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

Тепер сценарії виконуються, коли я запускаю контейнер, і я отримую підказку bash після виконання сценаріїв.


6

Ви також можете підключити локальний каталог до вашого образу докера та створити скрипт у вашому .bashrc. Не забувайте, що сценарій повинен складатися з функцій, якщо ви не хочете, щоб він виконувався на кожній новій оболонці. (Це застаріло, див. Повідомлення про оновлення.)

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

Ось як ви пов’язуєте свій поточний каталог:

docker run -it -v $PWD:/scripts $my_docker_build /bin/bash

Тепер ваш поточний каталог прив'язаний до /scriptsвашого екземпляра докера.

(Застаріло) Щоб зберегти .bashrcзміни, зафіксуйте робочий образ за допомогою цієї команди:

docker commit $container_id $my_docker_build

Оновлення

Щоб вирішити проблему, щоб відкрити нову оболонку для кожної зміни, я зараз роблю наступне:

У сам файл docker я додаю RUN echo "/scripts/bashrc" > /root/.bashrc". Всередині zshrcя експортую каталог сценаріїв у шлях. Каталог скриптів тепер містить кілька файлів замість одного. Тепер я можу безпосередньо викликати всі сценарії, не відкриваючи додаткову оболонку при кожній зміні.

До речі, ви також можете визначити файл історії поза вашим контейнером. Таким чином, більше не потрібно виконувати зміни баша.


Запізно..! @javier вже показує пряме рішення !! Я відчуваю, що один все-таки кращий.
заппі

2
@zappy рішення від javier не вирішило цю проблему зручно для мене - але моє рішення зробило, я вважав, що було б цікаво тим, хто мав подібну проблему, коли вони не хочуть перезапускати зображення докера, щоб оновити переглядати потрібні їм функції. Наприклад, якщо ви використовуєте кілька зображень докера одночасно, щоб закрутити кластер розробників, ви не хочете їх перезапускати постійно.
Devpool

3

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

Видаліть ітеративні -i -tаргументи tty і скористайтеся цим:

    $ docker run ubuntu:bionic /bin/bash /path/to/script.sh

Це буде (не перевіряти) також працюватиме для інших сценаріїв:

    $ docker run ubuntu:bionic /usr/bin/python /path/to/script.py


0

Якщо ви хочете запустити одну і ту ж команду на декількох примірниках, ви можете зробити це:

for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.