execute a command within docker swarm service

后端 未结 11 1775
眼角桃花
眼角桃花 2020-12-04 15:16
  1. Initialize swarm mode:

    root@ip-172-31-44-207:/home/ubuntu# docker swarm init --advertise-addr 172.31.44.207
    
    Swarm initialized: current node (4mj61o         
    
    
            
相关标签:
11条回答
  • 2020-12-04 16:08

    There is one liner for accessing corresponding instance of the service for localhost:

    docker exec -ti stack_myservice.1.$(docker service ps -f 'name=stack_myservice.1' stack_myservice -q --no-trunc | head -n1) /bin/bash
    

    It is tested on PowerShell, but bash should be the same. The oneliner accesses the first instance, but replace '1' with the number of the instance you want to access in two places to get other one.

    More complex example is for distributed case:

    #! /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
    

    This script could be used later as:

    swarm_bash stack_task 1
    

    It just execute bash on required node.

    0 讨论(0)
  • 2020-12-04 16:08

    I wrote script to exec command in docker swarm by service name. For example it can be used in cron. Also you can use bash pipelines and passes all params to docker exec command. But works only on same node where service started. I wish it could help someone

    #!/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;
    

    Example of using:

    ./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
    
    0 讨论(0)
  • 2020-12-04 16:13

    You can jump in a Swarm node and list the docker containers running using:

    docker container ls
    

    That will give you the container name in a format similar to: containername.1.q5k89uctyx27zmntkcfooh68f

    You can then use the regular exec option to run commands on it:

    docker container exec -it containername.1.q5k89uctyx27zmntkcfooh68f bash
    
    0 讨论(0)
  • 2020-12-04 16:15

    Using the Docker API

    Right now, Docker does not provide an API like docker service exec or docker stack exec for this. But regarding this, there already exists two issues dealing with this functionality:

    • github.com - moby/moby - Docker service exec
    • github.com - docker/swarmkit - Support for executing into a task

    (Regarding the first issue, for me, it was not directly clear that this issue deals with exactly this kind of functionality. But Exec for Swarm was closed and marked as duplicate of the Docker service exec issue.)

    Using Docker daemon over HTTP

    As mentioned by BMitch on run docker exec from swarm manager, you could also configure the Docker daemon to use HTTP and than connect to every node without the need of ssh. But you should protect this using TLS authentication which is already integrated into Docker. Afterwards you would be able to execute the docker exec like this:

    docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \
        -H=$HOST:2376 exec $containerId $cmd
    

    Using skopos-plugin-swarm-exec

    There exists a github project which claims to solve the problem and provide the desired functionality binding the docker daemon:

    docker run -v /var/run/docker.sock:/var/run/docker.sock \
        datagridsys/skopos-plugin-swarm-exec \
        task-exec <taskID> <command> [<arguments>...]
    

    As far as I can see, this works by creating another container at same node where the container reside where the docker exec should by executed on. On this node this container mounts the docker daemon socket to be able to execute docker exec there locally.
    For more information have a look at: skopos-plugin-swarm-exec

    Using docker swarm helpers

    There is also another project called docker swarm helpers which seems to be more or less a wrapper around ssh and docker exec.

    Reference:

    • https://github.com/docker/swarmkit/issues/1895#issuecomment-302147604
    • https://github.com/docker/swarmkit/issues/1895#issuecomment-358925313
    0 讨论(0)
  • 2020-12-04 16:18

    See addendum 2...

    Example of a oneliner for entering the database my_db on node master:

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

    In case you want to configure, say 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

    This approach allows to enter all database nodes (e.g. slaves) just by setting the DB_NODE_ID variable accordingly.

    Example for slave 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

    Put this into your KiTTY or PuTTY configuration for master / s2 under Data/Command and you are set.


    As an addendum:

    The old, non swarm mode version reads simply

    docker exec -it master mysql my_db
    

    resp.

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

    Addendum 2:

    As it turned out by example, the term docker ps -q -f name=$DB_NODE_ID may return wrong values under certain conditions.

    The following approach works correctily:

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

    You may substitute the examples above accordingly.


    Addendum 3:

    Well, these terms look awful and they certainly are painful to type, so you may want to ease your work. On Linux, everybody knows how to do this. On Windws, you may want to use AHK.

    This is the AHK term I use:

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

    So when I type ii -- which is as simple as it can get -- I get the desired term with the cursor in place and just have to fill in the container name.

    0 讨论(0)
提交回复
热议问题