Better Kubectl Interaction

As many of you know, kubectl is official command-line client for interacting with the kubernetes cluster. Although kubectl allow us to do almost anything with the cluster, it has a convoluted interface. Especially for interacting with basic entities such pods. Pods are ephemeral entities, and each instance gets an unique name. If a deployment name is kafka-consumer then pods names might be kafka-consumer-654b7df6b-mfx46, kafka-consumer-654b7df6b-yy49i. This name changes every time pod is updated or restarted and all commands which needs to interact with pods needs this unique pod name as its parameter.

So the interaction might look like

$ kubectl get pods
NAME                                   READY   STATUS    RESTARTS   AGE
consumer-654b7df6b-mfx46               1/1     Running   0          21d
server-7df6b9903-oc9m6                 1/1     Running   0          22d

$ kubectl delete pod consumer-654b7df6b-mfx46

Apart from irritating user by asking him/her to copy some string every time, this interaction breaks all conventional shell workflow. We can’t use reverse shell history search (Ctrl+r), it is not composable, it is not repeatable, and it clutters clipboard.

There are many tools which attempts to solve this, but most of them approach this by hiding kubectl. They provide a wrapper with their own set of options and syntax. Although this might work in most scenarios, there are few concerns: tool might not expose all options of kubectl, more documentation available online for kubectl, and we have to learn new tool. I wanted to solve this without hiding kubectl so that if I need to do something advanced I can always extend. One way to achieve this is by having “template command” which insert pod name each time we execute it.

Subshell & fzf to the rescue

$(...) is way one of executing a command in separate shell. $(...) will be replaced with its output.

Consider this

mkdir $(read name && echo "hello-$name")

Here we read user input from STDIN and return it with a “hello-” prefix. If input is “world”, command will be mkdir hello-world. Important thing to note here is that subshell command is executed before root command, and we can use this to insert a parameter to the command.

fzf gives an interactive user interface for “choosing something” from a list. It reads lines from STDIN, ask user for choice and writes this entry to STDOUT.

ls -1 | fzf | wc -c

This returns count of characters in the filename depending on our choice.

Combining both

We use subshell and fzf to dynamically select pod name and pass that to kubectl command template.

kubectl delete pod $(kubectl get pods | fzf)

We can use shell functions and alias to make this composable by add these to init file. such as ~/.profile or ~/.oh-my-zsh/config.zsh

function kselect {
    kubectl get "$@" --no-headers -o custom-columns=POD:.metadata.name | fzf --height 25% --border --exact
}

alias select_pod='kselect pods'

Now our command to:

kubectl delete pod $(select_pod)
Post selection in action!

We can use kselect for all kubernetes resource objects

alias select_deployment='kselect deployment'
alias select_statefulset='kselect statefulset'
alias select_configmap='kselect configmap'
alias select_service='kselect service'
alias select_secret='kselect secret'