kubectl alias done right
It is not uncommon to see people having an alias for kubectl
to save few
keystrokes. It is admittedly useful, but I find it is not easy to get it
right.
Let’s start from the basic form:
# ${HOME}/.zshrc
alias k=kubectl
This is what I get when I have my laptop configured by the company automation tool. If you are satisfied with it, then you probably can close this page.
For me, however, this barely resolves the actual issue: switching contexts back and forth is painful.
$ k --context=<ctx1> ...
$ ...
$ k --context=<ctx2> ...
To the rescue, I wanted to leverage the tmux window name so that a context switch becomes a window switch:
if [[ ${TMUX} ]]; then
wname=$(tmux display-message -p '#W')
kubectl config get-contexts ${wname} &>/dev/null
if [[ $? -eq 0 ]]; then
alias k="kubectl --context=${wname}"
fi
fi
This becomes much easier for me because there is no more mental effort to check
the current context I’m operating on. But wait, won’t you be able to solve this
by enabling kube-ps1
zsh plugin which shows the current context name.
There are two issues with kube-ps1
. For one, it is still painful to switch
contexts even though I get a little bit of visual feedback. However, the more
tricky issue is, I may still end up with using an incorrect context name. I
typically work on multiple tmux windows / panels, and if I switched context from
one window, and then when I start to work on a different window, chances are
that I may forget that the prompt I see is actually no longer correct.
Let’s come back to this again:
alias k="kubectl --context=${wname}"
It is great that now I have an alias per tmux window, but there is a problem in
it - It doesn’t work with kubectl plugin because the plugin name is supposedly
to follow kubectl
immediately.
The solution to this situation is that I should move --context=${wname}
to the
end:
function k() {
kubectl $@ --context=${wname}
}
Here, instead of using an alias, I defined a function k
which I can make sure
--context=${wname}
appears at the end so that kubectl plugins can still work.
As a side note, I observed that people just create another alias for kubectl
plugins like alias kshell=kubectl shell
.
I have been happy with this k
function for a long time, until recently it
failed for me in this case:
$ k exec -it <pod> -c <container> -- bash
This didn’t work and failed in a pretty bad way because it ended up with executing something like below:
$ kubectl exec -it <pod> -c <container> -- bash --context=${wname}
This command didn’t specify a context name at all, and the --context=${wname}
parameter actually became the parameter of bash
.
The flaw is that we can’t just put --context=${wname}
at the end because there
are cases where it doesn’t make sense. The right place should be right before
--
instead.
function k() {
# TODO: I'm pretty sure there is a better way to do this!
KUBECTL_ARGS_1=()
KUBECTL_ARGS_2=()
KUBECTL_HAS_ARGS_2=false
for p in ${@}; do
if [[ $p == "--" && ${KUBECTL_ARGS_2} != true ]]; then
KUBECTL_HAS_ARGS_2=true
continue
fi
if [[ ${KUBECTL_HAS_ARGS_2} = true ]]; then
KUBECTL_ARGS_2+=(${p})
else
KUBECTL_ARGS_1+=(${p})
fi
done
if [[ ${KUBECTL_HAS_ARGS_2} = true ]]; then
kubectl ${KUBECTL_ARGS_1} --context=${wname} -- ${KUBECTL_ARGS_2}
else
kubectl ${KUBECTL_ARGS_1} --context=${wname}
fi
}
In this case, I’m traversing all the parameters and find where --
is, and then
put --context=${wname}
right in the middle.
Maybe there are more cases where it may fail, but so far this is the version which works for me in a lot of situations.
By sharing this little story, I think it is clear that a simple thing may not actually be as simple as you thought, and there are always complexities with it.