Four kubectl plugins I keep coming back to
kubectl has a first-class plugin system (anything named kubectl-foo in your PATH becomes kubectl foo). Over the past year I have accumulated a handful of tiny scripts that solve small but recurring annoyances. Here are the four I use daily.
1. kubectl-events
kubectl get events sorted by lastTimestamp is a pain to remember. My plugin is one line:
#!/bin/sh
# kubectl-events
exec kubectl get events --sort-by=.lastTimestamp "$@"
Saved me many times when triaging. I often run:
kubectl events -A | tail -30
and get a time-ordered tail of the cluster’s recent events. This is the kind of thing you wish were default.
2. kubectl-why
When a pod is in Pending, I want to know why without digging. My kubectl-why pulls the most useful fields:
#!/bin/bash
# kubectl-why
ns=${KUBECTL_PLUGINS_CURRENT_NAMESPACE:-default}
pod="$1"
if [ -z "$pod" ]; then
echo "usage: kubectl why <pod>"
exit 1
fi
phase=$(kubectl -n "$ns" get pod "$pod" -o jsonpath='{.status.phase}')
echo "Phase: $phase"
echo
kubectl -n "$ns" get pod "$pod" -o jsonpath='{range .status.conditions[*]}{.type}: {.status} {.reason} {.message}{"\n"}{end}'
echo
echo "Events:"
kubectl -n "$ns" get events --field-selector involvedObject.name="$pod" --sort-by=.lastTimestamp | tail -10
echo
echo "Container statuses:"
kubectl -n "$ns" get pod "$pod" -o jsonpath='{range .status.containerStatuses[*]}{.name}: {.state} last: {.lastState}{"\n"}{end}'
Usage:
kubectl why my-pod-xyz
# Phase: Pending
# PodScheduled: False Unschedulable 0/5 nodes are available: 5 Insufficient memory.
# ...
# Events:
# 2m Warning FailedScheduling default-scheduler 0/5 nodes are available
Probably 80% of “why is this pod not happy” questions get answered by this plugin’s output.
3. kubectl-nsh
kubectl exec -it POD -n NS -- bash is tedious when I want to drop into the first container in a pod quickly. Plus picking the right pod is annoying when there are multiple replicas.
#!/bin/bash
# kubectl-nsh
ns="${KUBECTL_PLUGINS_CURRENT_NAMESPACE:-default}"
selector=""
while [ $# -gt 0 ]; do
case "$1" in
-n|--namespace) ns="$2"; shift 2;;
-l|--selector) selector="-l $2"; shift 2;;
*) pod="$1"; shift;;
esac
done
if [ -n "$selector" ]; then
pod=$(kubectl -n "$ns" get pod $selector -o jsonpath='{.items[0].metadata.name}')
fi
exec kubectl -n "$ns" exec -it "$pod" -- sh -c 'bash 2>/dev/null || sh'
Usage:
kubectl nsh -n app -l app=api
Picks the first pod matching the selector, shells into it, tries bash, falls back to sh.
4. kubectl-ages
Sometimes I want a quick column of “when were these pods created” sorted freshest first. I realize kubectl get pods shows age, but it does not sort by age, and a long-running environment is noisy. My plugin prints a clean sorted table:
#!/bin/bash
# kubectl-ages
kubectl get pods "$@" --sort-by=.metadata.creationTimestamp \
-o custom-columns=NAME:.metadata.name,NS:.metadata.namespace,AGE:.metadata.creationTimestamp,PHASE:.status.phase \
--no-headers | awk '{ cmd="date -d "$3" +%s"; cmd | getline t; close(cmd); now=systime(); age=now-t; printf "%-50s %-20s %8ds %s\n", $1, $2, age, $4 }'
Output:
kubectl ages -A | head -10
# coredns-abc kube-system 27400s Running
# cert-manager-def cert-manager 14400s Running
# ...
The --sort-by plus custom-columns is close to what you want, but the conversion to a clean integer age field makes it easier to pipe into awk.
Installation
Drop all four into ~/.local/bin and make them executable. kubectl plugin system picks them up automatically. Verify with:
kubectl plugin list
# /home/merce/.local/bin/kubectl-ages
# /home/merce/.local/bin/kubectl-events
# /home/merce/.local/bin/kubectl-nsh
# /home/merce/.local/bin/kubectl-why
Some of these overlap with krew plugins that are more polished. kubectl-neat, kubectl-tree, kubectl-stern are the three I use from krew. The four above are narrow enough that a 20-line shell script is the right size.
What I did not write
- A plugin for diffing live manifest vs last-applied.
kubectl diffalready exists, and server-side apply means I rarely need it. - A cordon/drain helper.
kubectl drainis already the right verb. - A log follower across pods.
sterndoes this so well that duplicating would be silly.
The test for “should this be a plugin” is “do I type the same 30+ character command more than once a day?”. If yes, make it a three-line script.
Reflection
These four plugins save me maybe 5 minutes a day individually, but more importantly they reduce the friction of doing the right lookup rather than an approximation. kubectl events sorted is the tool I want when something is going wrong; before I wrote the plugin, I would sometimes settle for unsorted events because the flag was annoying to remember. Small friction makes a difference.
If you have similar friction in your kubectl workflow, write the plugin. Related: see my post on a CRD design mistakes I made early on for more “I got sloppy with my k8s tooling” content.