K9s Kubernetes CLI: Advanced Productivity Techniques for Platform Engineers
K9s Kubernetes CLI: Advanced Productivity Techniques for Platform Engineers
K9s has quietly become the default terminal interface for serious Kubernetes work. Once you're managing more than a handful of clusters, raw kubectl becomes a productivity tax — every debug loop turns into a 6-command dance of get, describe, logs, exec, and edit.
At Target-Ops we use K9s every day across EKS, GKE, and self-managed clusters. Over time we've built a library of custom views, plugins, and keyboard workflows that cut a typical investigation from 15 minutes to under 2. This guide distills the techniques that actually move the needle — the ones we rely on in production, not the tutorial basics.
If you already know what K9s is and you're comfortable moving around in it, this article will make you faster. If you're a platform lead rolling out standardized tooling to your team, the custom views, plugins, and aliases here are directly copy-pasteable into your onboarding repo.
Why K9s Beats Raw kubectl for Operations Work
Raw kubectl is a great API client. It's a mediocre investigation tool. The difference matters when you're on call at 2 AM.
The Cost of Context Switches
Every time you run kubectl get pods, then kubectl describe pod, then kubectl logs, you're re-parsing output, re-typing names, and re-building mental state. K9s keeps the state on screen — selection, namespace, filters — and turns investigation into a navigation problem instead of a typing problem.
What this looks like in practice:
- Pod crash investigation: 15+ kubectl commands → 6 keystrokes in K9s
- Multi-pod log tailing with filtering: shell scripts and
tee→ built-in feature - Cross-namespace comparison: scripted loops →
:pods -Awith live filtering - Editing a ConfigMap and verifying the pod reloaded: 4 terminals → a single K9s session
In our experience, standardizing on K9s for on-call work consistently cuts alert-to-insight time by 30–50%. The path from "something's wrong" to "I know what's wrong" is just dramatically shorter than it is with raw kubectl.
Installation and First-Run Configuration
# macOS
brew install k9s
# Linux
curl -sS https://webinstall.dev/k9s | bash
# Windows
scoop install k9s
On first launch, K9s creates $HOME/.k9s/ with its config directory. The files that matter most:
config.yaml— global behavior, refresh rates, skinsviews.yaml— custom columns per resource typeplugins.yaml— your custom commands bound to shortcutsaliases.yaml— short names for frequently-used commandshotkeys.yaml— custom keybindings
We'll use each of these below.
Custom Resource Views: See What Actually Matters
The default pod view is fine for demos. In real operations, you need node placement, QoS class, and resource metrics at a glance.
# $HOME/.k9s/views.yaml
k9s:
views:
v1/pods:
columns:
- NAME
- READY
- STATUS
- RESTARTS
- CPU
- MEM
- "%CPU/R"
- "%CPU/L"
- "%MEM/R"
- "%MEM/L"
- IP
- NODE
- QOS
- AGE
apps/v1/deployments:
columns:
- NAME
- READY
- UP-TO-DATE
- AVAILABLE
- IMAGE
- AGE
v1/services:
columns:
- NAME
- TYPE
- CLUSTER-IP
- EXTERNAL-IP
- PORT(S)
- SELECTOR
- AGE
Why this matters: The %CPU/R and %MEM/R columns show usage relative to requests — the single best signal for spotting pods that are about to get OOMKilled or that are wasting resources. Having these visible by default means your team catches problems passively instead of reactively.
Plugins: Turn Hard-Won Tribal Knowledge Into Keyboard Shortcuts
Plugins are K9s' most underused feature. Any shell command, any context menu, any investigation pattern can become a single keystroke. Here are the ones our team uses daily.
Plugin: Show Recent Events for Selected Resource
# $HOME/.k9s/plugins.yaml
plugins:
events:
shortCut: Ctrl-E
description: Recent events
scopes:
- all
command: sh
background: false
args:
- -c
- "kubectl events --for $KIND/$NAME -n $NAMESPACE | less"
Select any resource, hit Ctrl-E, immediately see its events. This one plugin has saved our team hundreds of hours of kubectl describe | grep -A 20 Events over the years.
Plugin: Open a Debug Shell on a Node
node-shell:
shortCut: Shift-S
description: Debug shell on node
scopes:
- nodes
command: kubectl
background: false
args:
- debug
- node/$NAME
- -it
- --image=busybox
Node troubleshooting without SSH keys, without bastion hops. Uses ephemeral containers — works even on locked-down managed Kubernetes.
Plugin: Dump All Pod Logs to a File
log-dump:
shortCut: Ctrl-D
description: Dump pod logs
scopes:
- pods
command: sh
background: false
args:
- -c
- "kubectl logs $NAME -n $NAMESPACE --all-containers=true --since=1h > /tmp/$NAME-$(date +%s).log && echo Wrote /tmp/$NAME-*.log"
For incident postmortems when you need to walk away with logs.
Plugin: Find Stuck Deployments
stuck-deployments:
shortCut: Ctrl-X
description: Stuck deployments
scopes:
- all
command: sh
background: false
args:
- -c
- |
kubectl get deployments -A -o json | jq -r '
.items[] |
select(.spec.replicas != .status.availableReplicas) |
"\(.metadata.namespace)\t\(.metadata.name)\t\(.spec.replicas)/\(.status.availableReplicas // 0)"
' | column -t -s