#!/bin/bash # this command helper depends on key-based (passwordless) SSH access by the current user to each of the docker swarm nodes. # usage help. usage() { echo echo "Usage: docker-service-exec [OPTIONS] SERVICE COMMAND [ARG...]" echo echo "Run a command in a running swarm service" echo echo "Options: -i, --interactive Keep STDIN open even if not attached -u, --user string Username or UID (format: [:]) -w, --workdir string Working directory inside the container" exit 2 } # parse the arguments PARSED_ARGUMENTS=$(getopt -q -a -n docker-service-exec -o iu:w: -l interactive,it,user:,workdir: -- "$@") VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then usage fi # use below for diagnostics only. # echo "PARSED_ARGUMENTS is $PARSED_ARGUMENTS" eval set -- "$PARSED_ARGUMENTS" while : do case "$1" in -i | --it | --interactive) OPT_INTERACTIVE="-it"; shift ;; -u | --user) OPT_USER="-u $2"; shift 2 ;; -w | --workdir) OPT_WORKDIR="-w $2"; shift 2 ;; # -- means the end of the arguments; drop this, and break out of the while loop --) shift; break ;; # If invalid options were passed, then getopt should have reported an error, # which we checked as VALID_ARGUMENTS when getopt was called... *) echo "Unexpected option: $1 - this should not happen." usage;; esac done # discover docker server vars. SERVICE_NAME=$1; shift TASK_ID=$(docker service ps --filter 'desired-state=running' $SERVICE_NAME -q) NODE_ID=$(docker inspect --format '{{ .NodeID }}' $TASK_ID) CONTAINER_ID=$(docker inspect --format '{{ .Status.ContainerStatus.ContainerID }}' $TASK_ID) NODE_HOST=$(docker node inspect --format '{{ .Description.Hostname }}' $NODE_ID) # connect to the docker host through SSH export DOCKER_HOST="ssh://$(whoami)@$NODE_HOST.$(hostname -d)" # execute the command docker exec $OPT_INTERACTIVE $OPT_USER $OPT_WORKDIR $CONTAINER_ID "$@"