Выполнить команду в сервисе роуминга докеров
-
Инициализировать режим роя:
[email protected]:/home/ubuntu# docker swarm init --advertise-addr 172.31.44.207
Swarm initialized: current node (4mj61oxcc8ulbwd7zedxnz6ce) is now a manager.
To add a worker to this swarm, run the following command:
-
Присоедините второй node:
docker swarm join \
--token SWMTKN-1-4xvddif3wf8tpzcg23tem3zlncth8460srbm7qtyx5qk3ton55-6g05kuek1jhs170d8fub83vs5 \
172.31.44.207:2377
Чтобы добавить менеджера в этот рой, запустите "диспетчер подключений маркеров докеров" и следуйте инструкциям.
# start 2 services
docker service create continuumio/miniconda3
docker service create --name redis redis:3.0.6
[email protected]:/home/ubuntu# docker service ls
ID NAME REPLICAS IMAGE COMMAND
2yc1xjmita67 miniconda3 0/1 continuumio/miniconda3
c3ptcf2q9zv2 redis 1/1 redis:3.0.6
Как показано выше, redis имеет реплику, в то время как miniconda делает не реплицированным.
Обычно я подключаюсь к контейнеру miniconda для ввода следующих команд:
/opt/conda/bin/conda install jupyter -y --quiet && mkdir /opt/notebooks && /opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser
Проблема заключается в том, что команда docker exec -it XXX bash
не работает с режимом роя.
Ответы
Ответ 1
Существует один вкладыш для доступа к соответствующему экземпляру службы для localhost:
docker exec -ti stack_myservice.1.$(docker service ps -f 'name=stack_myservice.1' stack_myservice -q --no-trunc | head -n1) /bin/bash
Он протестирован на PowerShell, но bash должен быть таким же. Oneliner обращается к первому экземпляру, но замените "1" номером экземпляра, к которому вы хотите получить доступ, в двух местах, чтобы получить другой.
Более сложный пример для распределенного случая:
#! /bin/bash
set -e
exec_task=$1
exec_instance=$2
strindex() {
x="${1%%$2*}"
[[ "$x" = "$1" ]] && echo -1 || echo "${#x}"
}
parse_node() {
read title
id_start=0
name_start='strindex "$title" NAME'
image_start='strindex "$title" IMAGE'
node_start='strindex "$title" NODE'
dstate_start='strindex "$title" DESIRED'
id_length=name_start
name_length='expr $image_start - $name_start'
node_length='expr $dstate_start - $node_start'
read line
id=${line:$id_start:$id_length}
name=${line:$name_start:$name_length}
name=$(echo $name)
node=${line:$node_start:$node_length}
echo $name.$id
echo $node
}
if true; then
read fn
docker_fullname=$fn
read nn
docker_node=$nn
fi < <( docker service ps -f name=$exec_task.$exec_instance --no-trunc -f desired-state=running $exec_task | parse_node )
echo "Executing in $docker_node $docker_fullname"
eval 'docker-machine env $docker_node'
docker exec -ti $docker_fullname /bin/bash
Этот скрипт может быть использован позже как:
swarm_bash stack_task 1
Он просто выполняет bash на требуемом узле.
Ответ 2
РЕДАКТИРОВАТЬ 2017-10-06:
В настоящее время вы можете создать оверлейную сеть с флагом --attachable
чтобы позволить любому контейнеру присоединиться к сети. Это отличная функция, поскольку она обеспечивает большую гибкость.
Например
$ docker network create --attachable --driver overlay my-network
$ docker service create --network my-network --name web --publish 80:80 nginx
$ docker run --network=my-network -ti alpine sh
(in alpine container) $ wget -qO- web
<!DOCTYPE html>
<html>
<head>
....
Вы правы, вы не можете запустить docker exec
в сервисе Docker Swarm Mode. Но вы все равно можете узнать, на каком узле выполняется контейнер, а затем запустить exec непосредственно в контейнере. Например
docker service ps miniconda3 # find out, which node is running the container
eval 'docker-machine env <node name here>'
docker ps # find out the container id of miniconda
docker exec -it <container id here> sh
В вашем случае вы сначала должны выяснить, почему сервис не может поднять контейнер Miniconda. Может быть, при запуске docker service ps miniconda3
показывает некоторые полезные сообщения об ошибках..?
Ответ 3
Использование Docker API
Прямо сейчас Docker не предоставляет API, такой как docker service exec
docker stack exec
или docker stack exec
Docker для этого. Но в связи с этим уже существуют две проблемы, связанные с этой функциональностью:
(Что касается первой проблемы, для меня неясно, что эта проблема касается именно такой функциональности. Но Exec for Swarm был закрыт и помечен как дубликат проблемы exec службы Docker.)
Использование Docker через HTTP
Как упомянуто BMitch при запуске docker exec из swarm manager, вы также можете настроить демон Docker на использование HTTP и затем подключаться к каждому узлу без использования ssh. Но вы должны защитить это с помощью аутентификации TLS, которая уже интегрирована в Docker. После этого вы сможете выполнить docker exec
следующим образом:
docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \
-H=$HOST:2376 exec $containerId $cmd
Использование skopos-plugin-swarm-exec
Существует проект github, который утверждает, что решает проблему и обеспечивает желаемую функциональность, привязывающую демон docker:
docker run -v /var/run/docker.sock:/var/run/docker.sock \
datagridsys/skopos-plugin-swarm-exec \
task-exec <taskID> <command> [<arguments>...]
Насколько я вижу, это работает, создавая другой контейнер в том же узле, где находится контейнер, в котором должен выполняться docker exec
. На этом узле этот контейнер монтирует сокет демона docker exec
локального выполнения docker exec
.
Для получения дополнительной информации взгляните на: skopos-plugin-swarm-exec
Использование помощников Docker Swarm
Существует также другой проект, называемый docker swarm helpers, который, похоже, является более или менее оболочкой для ssh
и docker exec
.
Ссылка:
Ответ 4
Вы можете выполнять команды путем фильтрации имени контейнера без необходимости передавать весь хэш контейнера Swarm, только по имени службы. Как это:
docker exec $(docker ps -q -f name=servicename) ls
Ответ 5
Вы можете перейти в узел Swarm и перечислить докер-контейнеры, работающие с использованием:
docker container ls
Это даст вам имя контейнера в формате, похожем на: containername.1.q5k89uctyx27zmntkcfooh68f
Затем вы можете использовать обычную опцию exec для запуска команд:
docker container exec -it containername.1.q5k89uctyx27zmntkcfooh68f bash
Ответ 6
Я написал скрипт для выполнения команды в Docker Swarm по имени службы. Например, его можно использовать в cron. Также вы можете использовать конвейеры bash и передавать все параметры в команду docker exec
. Но работает только на том же узле, где запущен сервис. Я хотел бы, чтобы это могло помочь кому-то
#!/bin/bash
# swarm-exec.sh
set -e
for ((i=1;i<=$#;i++)); do
val=${!i}
if [ ${val:0:1} != "-" ]; then
service_id=$(docker ps -q -f "name=$val");
if [[ $service_id == "" ]]; then
echo "Container $val not found!";
exit 1;
fi
docker exec ${@:1:$i-1} $service_id ${@:$i+1:$#};
exit 0;
fi
done
echo "Usage: $0 [OPTIONS] SERVICE_NAME COMMAND [ARG...]";
exit 1;
Пример использования:
./swarm-exec.sh app_postgres pg_dump -Z 9 -F p -U postgres app > /backups/app.sql.gz
echo ls | ./swarm-exec.sh -i app /bin/bash
./swarm-exec.sh -it some_app /bin/bash
Ответ 7
создал небольшой скрипт для нашего кластера Docker Swarm. этот скрипт занимает 3 параметра. во-первых, это служба, к которой вы хотите подключиться, во-вторых, задача, которую вы хотите запустить, это может быть /bin/bash
или любой другой процесс, который вы хотите запустить. Третий не обязателен и заполнит опцию -c для bash или sh
-n является необязательным для принудительного подключения к узлу
он извлекает узел, который запускает службу, и запускает команду.
#! /bin/bash
set -e
task=${1}
service=$2
bash=$3
serviceID=$(sudo docker service ps -f name=$service -f desired-state=running $service -q --no-trunc |head -n1)
node=$(sudo docker service ps -f name=$service -f desired-state=running $service --format="{{.Node}}"| head -n1 )
sudo docker -H $node exec -it $service".1."$serviceID $bash -c "$task"
примечание: для этого требуется, чтобы док-узлы принимали tcp-соединения, предоставляя докер через порт 2375 на рабочих узлах