How to execute an arbitrary command on any docker container running in a docker swarm ?
There is no way of directly executing a ‘docker exec’ on a container in the swarm.
On a swarm we can define stack of services and directly only services are visible. The containers that run the actual service and their location is hidden to us.
STEP 1: Find the task associated to a service
To find out the tasks associated with a service execute on a swarm manager node:
# docker service ps -q ${SERVICE_NAME} | head -n $index
Where:
– SERVICE_NAME = a variable containing the fully qualified name of a service stackname+servicename
– index = a variable indicating the index of a service replica. In case the service has several replicas the “docker service ps” command returns the list of task IDs of the replicas.
The -q parameter ensure that we will return just the list of tasks IDs.
Note that a service can have several tasks associated, but each task has only one container associated. With the above I return only the one task from the list.
STEP 2: Find the container ID associated to a task
With the following command inspect a task from the swarm with a given filter:
# docker inspect -f "{{.Status.ContainerStatus.ContainerID}}" ${TASK_ID}
Where TASK_ID = a variable containing the task ID found at STEP 1
STEP 3: Find the ID of the swarm node where the task is running
With the following command inspect the task with a given filter:
# docker inspect -f "{{.NodeID}}" ${TASK_ID}
Where TASK_ID = a variable containing the task ID found at STEP 1
STEP 4: Find the IP of the swarm node where the task is running
With the following command inspect the node with a given filter:
# docker inspect -f {{.Status.Addr}} ${NODE_ID}
Where NODE_ID = a variable containing the node ID found at STEP 3
STEP 5: Execute with ssh a remote docker exec
We assume that ssh is setup between the manager node and all the other nodes of the swarm as a passwordless login, using certificates.
On the swarm manager node execute the following to generate the ssh key pair.
# ssh-keygen
Then using ssh-cpy-id copy the public key of the swarm manager to all the other nodes
# ssh-copy-id -i .ssh/id_rsa_pub worker1
The following command will execute the remote docker exec command in a bash heredoc block:
ssh -T ${NODE_IP} << EOSSH docker exec ${CONT_ID} bash -c "echo 'host.name=${SERVICE_NAME}' >> /var/lib/jetty/resources/server.properties"
EOSSH
STEP 6: Put everything in one script.
The simple case is when a service has only one replica. In this case we have only one task associated with a service.
cat docker-exec.sh
#!/bin/bash
SERVICE_NAME=$1
COMMAND=$2
TASK_ID="$(docker service ps -q ${SERVICE_NAME})"
CONT_ID="$(docker inspect -f "{{.Status.ContainerStatus.ContainerID}}" ${TASK_ID})"
NODE_ID="$(docker inspect -f "{{.NodeID}}" ${TASK_ID})"
NODE_IP="$(docker inspect -f {{.Status.Addr}} ${NODE_ID})"
ssh -T ${NODE_IP} << EOSSH
docker exec ${CONT_ID} bash -c "${COMMAND}"
EOSSH
To use the new script do the following:
docker-exec.sh stack_db "echo 'host.name=${SERVICE_NAME}' >> /var/lib/jetty/resources/server.properties"
The same can be done for “docker cp” with the note that data that is copied to/from the container will reside on the local node where the container runs.
Contribute to this site maintenance !
This is a self hosted site, on own hardware and Internet connection. The old, down to earth way 🙂. If you think that you found something useful here please contribute. Choose the form below (default 1 EUR) or donate using Bitcoin (default 0.0001 BTC) using the QR code. Thank you !
€1.00