Как выполнить команду из одного контейнера докеров в другой
Я создаю приложение, которое позволит пользователям загружать видеофайлы, которые затем будут подвергнуты некоторой обработке.
У меня есть два контейнера.
Nginx
контейнер, обслуживающий веб-сайт, куда пользователи могут загружать свои видеофайлы.- Контейнер обработки видео с
FFmpeg
и еще кое-что для обработки.
Чего я хочу добиться. Мне нужен контейнер 1, чтобы иметь возможность запускать сценарий bash в контейнере 2.
Насколько я понимаю, одна из возможностей - заставить их общаться через HTTP через API. Но тогда мне нужно было бы установить веб-сервер в контейнер 2 и написать API, который кажется немного излишним. Я просто хочу выполнить сценарий bash.
Какие-либо предложения?
5 ответов
У вас есть несколько вариантов, но первые два, которые приходят в голову, это:
- В контейнере 1 установите Docker CLI и привяжите mount
/var/run/docker.sock
(вам нужно указать монтирование привязки с хоста при запуске контейнера). Затем внутри контейнера вы сможете использоватьdocker
команды для подключенного сокета, как если бы вы выполняли их с хоста (вам также может потребоватьсяchmod
сокет внутри контейнера, чтобы позволить это сделать пользователю без полномочий root. - Вы можете установить
SSHD
на контейнере 2, а затемssh
из контейнера 1 и запустите свой скрипт. Преимущество здесь в том, что вам не нужно вносить какие-либо изменения внутри контейнеров, чтобы учесть тот факт, что они работают в Docker, а не на голом железе. Обратной стороной является то, что вам нужно будет добавить настройку SSHD в свой Dockerfile или в сценарии запуска.
Большинство других идей, которые я могу придумать, - это просто варианты варианта (2) с заменой SSHD каким-либо другим инструментом.
Также имейте в виду, что сеть Docker немного странная (по крайней мере, на хостах Mac), поэтому вам нужно убедиться, что контейнеры используют одну и ту же сеть докеров и могут обмениваться данными по ней.
Я написал пакет python специально для этого варианта использования.
Flask-Shell2HTTP - это расширение Flask для преобразования инструмента командной строки в RESTful API с помощью всего 5 строк кода.
Пример кода:
from flask import Flask
from flask_executor import Executor
from flask_shell2http import Shell2HTTP
app = Flask(__name__)
executor = Executor(app)
shell2http = Shell2HTTP(app=app, executor=executor, base_url_prefix="/commands/")
shell2http.register_command(endpoint="saythis", command_name="echo")
shell2http.register_command(endpoint="run", command_name="./myscript")
можно легко назвать,
$ curl -X POST -H 'Content-Type: application/json' -d '{"args": ["Hello", "World!"]}' http://localhost:4000/commands/saythis
Вы можете использовать это для создания микросервисов RESTful, которые могут асинхронно выполнять предварительно определенные команды / сценарии оболочки с динамическими аргументами и получать результат.
Он поддерживает загрузку файлов, обратный вызов fn, реактивное программирование и многое другое. Я рекомендую вам ознакомиться с примерами.
Запуск docker
команда из контейнера непростая и не очень хорошая идея (на мой взгляд), потому что:
- Вам нужно будет установить докер в контейнер (и сделать докер в докере)
- Вам нужно будет совместно использовать сокет unix, что не очень хорошо, если вы не знаете, что делаете.
Итак, остается два решения:
- Установите ssh на свой контейнер и выполните команду через ssh
- Поделитесь томом и получите процесс, который будет следить за тем, чтобы что-то запустило вашу партию
Об этом упоминалось здесь ранее, но разумный, полувакансный вариант - установить SSH в оба контейнера, а затем использовать ssh для выполнения команд в другом контейнере:
# install SSH, if you don't have it already
sudo apt install openssh-server
# start the ssh service
sudo service start ssh
# start the daemon
sudo /usr/sbin/sshd -D &
Предполагая, что вы не хотите всегда быть пользователем root, вы можете добавить пользователя по умолчанию (в данном случае 'foobob'):
useradd -m --no-log-init --system --uid 1000 foobob -s /bin/bash -g sudo -G root
#change password
echo 'foobob:foobob' | chpasswd
Сделайте это как для исходного, так и для целевого контейнеров. Теперь вы можете выполнить команду из контейнера_1 в контейнер_2.
# obtain container-id of target container using 'docker ps'
ssh foobob@<container-id> << "EOL"
echo 'hello bob from container 1' > message.txt
EOL
Вы можете автоматизировать пароль с помощью ssh-agent, или вы можете использовать немного более взломанных с sshpass
(сначала установите его, используя sudo apt install sshpass
):
sshpass -p 'foobob' ssh foobob@<container-id>
Я верю
docker exec -it <container_name> <command>
должно работать даже внутри контейнера.
Вы также можете попытаться смонтировать docker.sock
в контейнере вы пытаетесь выполнить команду из:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...