19

Hey I'm running a kubernetes cluster and I want to run a command on all pods that belong to a specific service.

As far as I know kubectl exec can only run on a pod and tracking all my pods is a ridiculous amount of work (which is one of the benefits of services).

Is there any way or tool that gives you the ability to "broadcast" to all pods in a service?

Thanks in advance for your help!

Yonah Dissen
  • 1,197
  • 1
  • 8
  • 16
  • have a look at DaemonSet in kubernetes, if it suits your requirements. – Prateek Jain Jun 25 '18 at 16:10
  • 2
    I don't think there is a direct way using kubectl. Although you can use a combination of kubectl get pods -l and then pipe to kubectl exec. I saw some gist that wraps this in a shell. https://gist.github.com/mnadel/4ddcc0ba07d398b35dad89b4dfdc8308 – Bal Chua Jun 25 '18 at 22:46
  • 1
    @BalChua you should write that as an Answer, rather than a comment, because it is exactly correct – mdaniel Jun 26 '18 at 05:58

5 Answers5

21

Here's a simple example with kubectl pipe to xargs, printing env of each pod:

k get pod \
    -l {your label selectors} \
    --field-selector=status.phase=Running \
    -o custom-columns=name:metadata.name --no-headers \
    | xargs -I{} kubectl exec {} env
Dusan Jovanovic
  • 411
  • 4
  • 6
8

As Bal Chua wrote, kubectl has no way to do this, but you can use bash script to do this:

 #!/usr/bin/env bash

PROGNAME=$(basename $0)

function usage {
    echo "usage: $PROGNAME [-n NAMESPACE] [-m MAX-PODS] -s SERVICE -- COMMAND"
    echo "  -s SERVICE   K8s service, i.e. a pod selector (required)"
    echo "     COMMAND   Command to execute on the pods"
    echo "  -n NAMESPACE K8s namespace (optional)"
    echo "  -m MAX-PODS  Max number of pods to run on (optional; default=all)"
    echo "  -q           Quiet mode"
    echo "  -d           Dry run (don't actually exec)"
}

function header {
    if [ -z $QUIET ]; then
        >&2 echo "###"
        >&2 echo "### $PROGNAME $*"
        >&2 echo "###"
    fi
}

while getopts :n:s:m:qd opt; do
    case $opt in
        d)
            DRYRUN=true
            ;;
        q)
            QUIET=true
            ;;
        m)
            MAX_PODS=$OPTARG
            ;;
        n)
            NAMESPACE="-n $OPTARG"
            ;;
        s)
            SERVICE=$OPTARG
            ;;
        \?)
            usage
            exit 0
            ;;
    esac
done

if [ -z $SERVICE ]; then
    usage
    exit 1
fi

shift $(expr $OPTIND - 1)

while test "$#" -gt 0; do
    if [ "$REST" == "" ]; then
        REST="$1"
    else
        REST="$REST $1"
    fi

    shift
done

if [ "$REST" == "" ]; then
    usage
    exit 1
fi

PODS=()

for pod in $(kubectl $NAMESPACE get pods --output=jsonpath={.items..metadata.name}); do
    echo $pod | grep -qe "^$SERVICE" >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        PODS+=($pod)
    fi
done

if [ ${#PODS[@]} -eq 0 ]; then
    echo "service not found in ${NAMESPACE:-default}: $SERVICE"
    exit 1
fi

if [ ! -z $MAX_PODS ]; then
    PODS=("${PODS[@]:0:$MAX_PODS}")
fi

header "{pods: ${#PODS[@]}, command: \"$REST\"}"

for i in "${!PODS[@]}"; do
    pod=${PODS[$i]}
    header "{pod: \"$(($i + 1))/${#PODS[@]}\", name: \"$pod\"}"

    if [ "$DRYRUN" != "true" ]; then
        kubectl $NAMESPACE exec $pod -- $REST
    fi
done
Nick Rak
  • 2,629
  • 13
  • 19
4

Here:

kubectl -n alex get pods -l app=alex-admin-api -o name | xargs -I{} kubectl -n alex exec {} -- cat alexAdminApi.log >> alex-admin-api_pods.logs
tuxErrante
  • 1,274
  • 12
  • 19
1

I have written a simple kubectl plugin that "boardcast"s commands to all pods, using Tmux. Assuming that all your pods in the service should share the same labels in their spec, app=foobar for instance, you can use the command below,

kubectl tmux-exec -l app=foobar bash

The plugin is available on Github: predatorray/kubectl-tmux-exec. Hope it will help you!

Wenhao Ji
  • 5,121
  • 7
  • 29
  • 40
0

there is also a kubectl plugin called kubectl-exec-all https://github.com/jpdasma/kubectl-exec-all that is doing a good job. Can't work with krew index but you can save the content of https://raw.githubusercontent.com/jpdasma/kubectl-exec-all/master/unix/exec-all.sh to /usr/local/bin/kubectl-exec_all and don't forget to make it executable by running

chmod +x /usr/local/bin/kubectl-exec_all

then it work like this:

kubectl plugin exec-all daemonset docker-daemon -- docker system prune -a -f
DevTheJo
  • 2,179
  • 2
  • 21
  • 25