在docker swarm服务中执行命令

时间:2016-09-07 06:12:29

标签: docker-swarm

  1. 初始化群模式:

    The method documentationConfiguration(RestDocumentation) in the type MockMvcRestDocumentation is not applicable for the arguments (JUnitRestDocumentation)
  2. 加入第二个节点:

    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:
    
  3. 要向此群添加管理员,请运行“docker swarm join-token manager”并按照说明操作。

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

    如上所示,redis拥有它的复制品,而miniconda 似乎复制

    我通常登录miniconda容器来输入这些命令:

    # 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
    

    问题是/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 命令不适用于swarm模式。

12 个答案:

答案 0 :(得分:26)

有一个班轮可以访问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。

答案 1 :(得分:16)

编辑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 swarm模式服务上运行docker exec。但您仍然可以找到运行容器的节点,然后直接在容器上运行exec。 E.g。

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会显示一些有用的错误消息..?

答案 2 :(得分:9)

使用Docker API

目前,Docker没有为此提供docker service execdocker stack exec等API。但就此而言,已经存在两个处理此功能的问题:

(关于第一个问题,对我来说,并不是直接明确这个问题涉及这种功能。但Exec for Swarm已关闭并标记为Docker service exec问题的副本。)

通过HTTP使用Docker守护程序

BMitch run docker exec from swarm manager所述,您还可以将Docker守护程序配置为使用HTTP,而不是连接到每个节点而不需要ssh。但是你应该使用已经集成到Docker中的TLS authentication来保护它。之后你就可以像这样执行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守护程序套接字,以便能够在本地执行docker exec 有关更多信息,请查看:skopos-plugin-swarm-exec

使用docker swarm helpers

还有一个名为docker swarm helpers的项目似乎或多或少是sshdocker exec的包装。

参考:

答案 3 :(得分:6)

您可以通过过滤容器名称来执行命令,而无需仅通过服务名称就传递整个swarm容器哈希。像这样:

TextInputEditText

答案 4 :(得分:4)

您可以跳转到Swarm节点并列出使用以下命令运行的docker容器:

docker container ls

这将为您提供类似于以下格式的容器名称:containername.1.q5k89uctyx27zmntkcfooh68f

然后,您可以使用常规exec选项在其上运行命令:

docker container exec -it containername.1.q5k89uctyx27zmntkcfooh68f bash

答案 5 :(得分:3)

我通过服务名称在docker swarm中将脚本写入了exec命令。例如,它可以在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

答案 6 :(得分:3)

为我们的docker swarm集群创建了一个小脚本。 该脚本需要3个参数。首先是要连接的服务,其次要运行的任务可以是/bin/bash或要运行的任何其他进程。第三是可选的,它将为bash或sh填充-c选项

-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"

注释:这要求docker节点通过在工作节​​点上的端口2375上暴露docker来接受tcp连接

答案 7 :(得分:1)

对于具有多个副本并且只想在其中任何一个中运行命令的用户,这是另一个快捷方式:

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

答案 8 :(得分:0)

请参阅附录2 ...

在节点my_db上输入数据库master的oneliner示例:

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

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的{​​{1}}或master配置中,就可以了。


作为附录:

非虫群模式的旧版本读起来很简单

s2

resp。

docker exec -it master mysql my_db

附录2:

如示例所示,术语DB_ID=master && $(docker exec -it $DB_ID mysql -e "SET GLOBAL max_connections = 1000") && docker exec -it $DB_ID mysql tmp 在某些情况下可能返回错误的值。

以下方法可以正常工作:

docker ps -q -f name=$DB_NODE_ID

您可以相应地替换上面的示例。


附录3:

嗯,这些术语看起来很糟糕,而且键入起来肯定很麻烦,因此您可能希望简化工作。在Linux上,每个人都知道如何执行此操作。在Windws上,您可能要使用AHK。

这是我使用的AHK术语:

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

因此,当我输入:*:ii::DB_NODE_ID=$(docker ps -a | grep "_." | awk '{{}print $1{}}') && docker exec -it $id ash{Left 49} 时(这很简单),我将光标放在适当的位置就可以得到所需的术语,而只需填写容器名称。

答案 9 :(得分:0)

我发现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"

这断言您具有对$SWARM_MANAGER_HOST的ssh访问权限,以及当前正在运行服务任务的swarm节点。

这也断言您已经安装了jqapt install jq),但是如果您不能安装或不想安装它并且安装了python,则可以创建以下别名(基于在this answer上)

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

答案 10 :(得分:0)

我编辑了上面添加的脚本 Brian van Rooijen。因为声望太低,无法添加

#! /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 不存在容器的问题。在执行中。

答案 11 :(得分:-1)

看看我的解决方案:https://github.com/binbrayer/swarmServiceExec

这种方法基于Docker Machines。我还创建了脚本的原型,以异步方式调用容器,因此可以同时调用容器。