выполнить команду в службе docker swarm

  1. Инициализировать режим роя:

    root@ip-172-31-44-207:/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:
    
  2. Присоединяйтесь ко второму узлу:

    docker swarm join \
    --token SWMTKN-1-4xvddif3wf8tpzcg23tem3zlncth8460srbm7qtyx5qk3ton55-6g05kuek1jhs170d8fub83vs5 \
    172.31.44.207:2377
    

Чтобы добавить менеджера в этот рой, запустите «docker swarm join-token manager» и следуйте инструкциям.

# start 2 services
docker service create continuumio/miniconda3 

docker service create --name redis redis:3.0.6


root@ip-172-31-44-207:/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 не работает в режиме роя.


person shantanuo    schedule 07.09.2016    source источник
comment
0 реплик означает, что контейнер не запустился. Я рекомендую вам настроить драйвер ведения журнала (например, драйвер системного журнала) на вашем демоне докеров, поскольку по умолчанию он проглатывает весь вывод контейнеров. Вероятно, он перезапускается снова и снова, и вы захотите знать, почему. В таком случае вы не сможете к нему прикрепиться и исправить; вместо этого вам нужно исправить команду службы docker, чтобы она не завершалась с ошибкой.   -  person Jilles van Gurp    schedule 07.09.2016


Ответы (12)


Вы можете выполнять команды, фильтруя имя контейнера, без необходимости передавать весь хэш контейнера роя, только по имени службы. Нравится:

docker exec $(docker ps -q -f name=servicename) ls

person isca    schedule 24.08.2018
comment
это должен быть рекомендуемый подход. если вам нужно что-то еще, вы можете легко создать сценарий из этого небольшого фрагмента. - person mad.meesh; 02.06.2020

Есть один лайнер для доступа к соответствующему экземпляру службы для 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 на требуемом узле.

person user1936595    schedule 22.03.2017
comment
Для однострочника требуется --no-trunc после -q - person raarts; 04.05.2017
comment
относительно сценария bash $ docker service ls ID NAME MODE REPLICAS IMAGE jiecd0kb524e bar replicated 3/3 jwilder/whoami:latest и когда я его вызываю $ ./swarm_bash bar 1 Executing in swarmm-agentpublic-31109991000004 bar.1.vj6lqkz4wi03hn7hr6574cipg Host does not exist: "swarmm-agentpublic-31109991000004" Error response from daemon: No such container: bar.1.vj6lqkz4wi03hn7hr6574cipg Могу ли я действительно выполнить запуск в режиме роя? Один лайнер у меня тоже не работает - person guillem; 06.05.2017
comment
Требуется --no-trunc и head -n1 - person Vanuan; 03.04.2018
comment
Я получил ошибку в docker-machine eval, используя недавнюю установку docker-ce, но остальная часть скрипта работала плавно. - person dragon788; 23.07.2018
comment
Этот ответ работает только для localhost. Хотя заявлено, возможно, еще немного подчеркните этот факт. Это решение не является общим ответом на выполнение команды в службе роя. Для bash автозавершение с помощью клавиши TAB по умолчанию выполняет свою работу и на локальном хосте: docs.docker. ru / compose / Завершение / # bash - person Trendfischer; 11.09.2018
comment
Если у вас нет докер-машины, но есть доступ по ssh, подойдет ssh -tt $docker_node sudo docker exec -ti $docker_fullname /bin/bash. - person Caesar; 19.12.2018
comment
Сложный сценарий можно упростить, используя параметр --format --format="{{.Node}}" для имени узла. - person Brian van Rooijen; 10.04.2019


РЕДАКТИРОВАТЬ 2017-10-06:

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

E.g.

$ 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 появляются полезные сообщения об ошибках ..?

person ronkot    schedule 07.09.2016

Использование Docker API

Прямо сейчас Docker не предоставляет для этого API типа docker service exec или docker stack exec. Но в связи с этим уже существуют две проблемы, связанные с этой функцией:

(Что касается первой проблемы, для меня было не совсем ясно, связана ли эта проблема именно с такой функциональностью. Но Exec for Swarm был закрыт и помечен как дубликат Docker service exec проблема.)

Использование демона Docker через HTTP

Как упоминалось BMitch на запустить docker exec из менеджера swarm, вы также можете настроить демон 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 run -v /var/run/docker.sock:/var/run/docker.sock \
    datagridsys/skopos-plugin-swarm-exec \
    task-exec <taskID> <command> [<arguments>...]

Насколько я понимаю, это работает путем создания другого контейнера на том же узле, где находится контейнер, где должен выполняться docker exec. На этом узле этот контейнер монтирует сокет демона докеров, чтобы иметь возможность выполнять там docker exec локально.
Для получения дополнительной информации см. skopos-plugin-swarm-exec

Использование помощников Docker Swarm

Существует также еще один проект под названием docker swarm helpers, который, похоже, является более или менее оберткой для ssh и docker exec.

Ссылка:

person Murmel    schedule 23.02.2018

Вы можете перейти в узел Swarm и перечислить запущенные докер-контейнеры, используя:

docker container ls

Это даст вам имя контейнера в формате, похожем на: имя_контейнера.1.q5k89uctyx27zmntkcfooh68f

Затем вы можете использовать обычную опцию exec для запуска на нем команд:

docker container exec -it containername.1.q5k89uctyx27zmntkcfooh68f bash
person JP Santana    schedule 21.04.2018
comment
Чтобы было ясно, это даст доступ только к службам, работающим на этом конкретном узле. - person Daniel C. Sobral; 05.09.2020

создал небольшой скрипт для нашего кластера 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 на рабочих узлах.

person Brian van Rooijen    schedule 10.04.2019

Я написал сценарий для команды exec в 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
person TIO    schedule 20.12.2018

Для тех, у кого есть несколько реплик и просто нужно запустить команду в любой из них, вот еще один ярлык:

docker exec -it $(docker ps -q -f name=SERVICE_NAME | head -1) bash
person Smallw00d    schedule 18.10.2020

Самая простая команда, которую я нашел для docker exec в узел роя (с менеджером роя в $SWARM_MANAGER_HOST), запускающим службу $SERVICE_NAME (например, mystack_myservice), выглядит следующим образом:

SERVICE_JSON=$(ssh $SWARM_MANAGER_HOST "docker service ps $SERVICE_NAME --no-trunc --format '{{ json . }}' -f desired-state=running")
ssh -t $(echo $SERVICE_JSON | jq -r '.Node') "docker exec -it $(echo $SERVICE_JSON | jq -r '.Name').$(echo $SERVICE_JSON | jq -r '.ID') bash"

Это означает, что у вас есть ssh-доступ к $SWARM_MANAGER_HOST, а также к узлу swarm, на котором в данный момент выполняется служебная задача.

Это также означает, что у вас установлен jq (apt install jq), но если вы не можете или не хотите его устанавливать и у вас установлен python, вы можете создать следующий псевдоним (на основе этот ответ):

alias jq="python3 -c 'import sys, json; print(json.load(sys.stdin)[sys.argv[2].partition(\".\")[-1]])'"
person Anthony O.    schedule 13.10.2020

См. приложение 2 ...

Пример единственного лайнера для входа в базу данных my_db на узле master:

DB_NODE_ID=master && docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql my_db

Если вы хотите настроить, скажите max_connections:

DB_NODE_ID=master && $(docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql -e "SET GLOBAL max_connections = 1000") && docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql my_db

Этот подход позволяет вводить все узлы базы данных (например, подчиненные), просто установив соответствующую переменную DB_NODE_ID.

Пример для ведомого s2:

DB_NODE_ID=s2 && docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql my_db

or

DB_NODE_ID=s2 && $(docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql -e "SET GLOBAL max_connections = 1000") && docker exec -it $(docker ps -q -f name=$DB_NODE_ID) mysql my_db

Поместите это в вашу KiTTY или PuTTY конфигурацию для master / s2 в разделе «Данные / команда», и все готово.


В качестве дополнения:

Старая версия без режима роя читается просто

docker exec -it master mysql my_db

соотв.

DB_ID=master && $(docker exec -it $DB_ID mysql -e "SET GLOBAL max_connections = 1000") && docker exec -it $DB_ID mysql tmp

Приложение 2:

Как выяснилось на примере, термин docker ps -q -f name=$DB_NODE_ID может возвращать неверные значения при определенных условиях.

Правильно работает следующий подход:

docker ps -a  | grep "_$DB_NODE_ID." | awk '{print $1}'

Вы можете соответствующим образом заменить приведенные выше примеры.


Приложение 3:

Что ж, эти термины выглядят ужасно, и их определенно сложно набирать, так что вы можете облегчить свою работу. В Linux все знают, как это сделать. В Windws вы можете использовать AHK.

Я использую этот термин AHK:

:*:ii::DB_NODE_ID=$(docker ps -a  | grep "_." | awk '{{}print $1{}}') && docker exec -it $id ash{Left 49} 

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

person kklepper    schedule 12.09.2019

Я редактировал сценарий, добавленный Брайаном ван Ройеном выше. Поскольку моя репутация слишком низкая, я не могу ее добавить

#! /bin/bash

set -e

service=${1}
shift
task="$*"

echo $task

serviceID=$(docker service ps -f name=$service -f desired-state=running $service -q --no-trunc |head -n1)
node=$(docker service ps -f name=$service -f desired-state=running $service --format="{{.Node}}"| head -n1 )
serviceName=$(docker service ps -f name=$service -f desired-state=running $service --format="{{.Name}}"| head -n1 )


docker -H $node exec -it $serviceName"."$serviceID $task

У меня была проблема, что контейнер не существует с жестко запрограммированным .1. в исполнении.

person Jelte Rienstra    schedule 16.07.2021

Взгляните на мое решение: https://github.com/binbrayer/swarmServiceExec.

Этот подход основан на Docker Machines. Я также создал прототип скрипта для асинхронного вызова контейнеров и одновременного вызова контейнеров.

person MBB    schedule 22.09.2019