kubectl Is Fine. kubectl + Krew Is Actually Good.
Out of the box, kubectl is a solid CLI. It can do almost anything. The problem is that “almost anything” often means a wall of --output jsonpath='{.items[*].spec.containers[*].image}' that makes your eyes cross at 11 PM when you’re trying to figure out why a deployment is stuck.
Krew fixes this. It’s the official plugin manager for kubectl, maintained by the kubernetes-sigs org, not some random GitHub repo. You install plugins, they show up as kubectl <plugin-name>, and suddenly you feel like a person again.
Here’s what Krew is, how to install it, and which plugins you’ll actually reach for on a k3s home lab.
Installing Krew
No root required. Krew installs per-user into ~/.krew/bin. The install script is a one-liner:
( set -x; cd "$(mktemp -d)" && OS="$(uname | tr '[:upper:]' '[:lower:]')" && ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" && KREW="krew-${OS}_${ARCH}" && curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" && tar zxvf "${KREW}.tar.gz" && ./"${KREW}" install krew)Then add Krew’s bin dir to your PATH. Drop this into your ~/.bashrc or ~/.zshrc:
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"Source the file or open a new shell, then verify:
kubectl krew version# GitTag v0.5.0# GitCommit ...# IndexURI https://index.krew.sigs.k8s.ioFrom here, the workflow is simple:
kubectl krew update # fetch latest plugin indexkubectl krew search # browse available pluginskubectl krew install <name> # install a pluginkubectl krew list # what's installedkubectl krew upgrade # update all installed pluginsThat’s it. No Helm charts, no cluster permissions, no crying.
The Plugins Worth Installing
Not everything in the Krew index is gold. Some plugins are abandoned, some overlap with built-in functionality that got added in newer kubectl versions (kubectl debug replaced kubectl-debug, for instance, skip that one). The list below is what’s actually useful on a home lab cluster.
kubectl-neat, Clean Up That YAML
You run kubectl get deployment myapp -o yaml and get 200 lines of noise: managedFields, creationTimestamp, resourceVersion, uid, status junk. You just wanted the spec.
kubectl-neat strips all the generated/server-side fields and gives you clean, copyable YAML.
kubectl krew install neat# Before: 200 lines of noisekubectl get deployment myapp -o yaml
# After: just what you wrotekubectl neat get deployment myapp -o yamlSample output, clean enough to paste directly into a new manifest or a PR:
apiVersion: apps/v1kind: Deploymentmetadata: name: myapp namespace: defaultspec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - image: myapp:1.3.0 name: myapp ports: - containerPort: 8080Honestly, this should be built into kubectl. It isn’t. Install it anyway.
kubectl-tree, See Who Owns What
Kubernetes ownership is a DAG of mystery. A deployment makes a ReplicaSet, which makes Pods, which have PVCs. When something breaks, tracing that chain with kubectl get and kubectl describe is tedious.
kubectl-tree renders the owner-reference chain as an actual tree:
kubectl krew install treekubectl tree deployment myappNAMESPACE NAME READY REASON AGEdefault Deployment/myapp - 3ddefault └─ReplicaSet/myapp-7d6b9f8c9 - 3ddefault ├─Pod/myapp-7d6b9f8c9-4xk2p True 3ddefault └─Pod/myapp-7d6b9f8c9-9vwrq True 3dUse it to quickly check whether a CronJob’s Jobs are cleaning up, whether a StatefulSet’s PVCs are hanging around after scale-down, or why there are three ReplicaSets for one Deployment (rolling update in progress, probably).
kubectx + kubens, Context and Namespace Switching
If you’re only running one cluster, skip these. If you’re juggling a k3s home lab, a managed cloud cluster, and maybe a dev cluster, you need these.
kubectl krew install ctxkubectl krew install ns# List and switch contextskubectl ctx# minikube# homelab# * prod-gke
kubectl ctx homelab# Switched to context "homelab".
# List and switch namespaceskubectl ns# default# kube-system# monitoring# * ingress-nginx
kubectl ns monitoring# Context "homelab" set to namespace "monitoring".These are the same tools as the standalone kubectx/kubens binaries, if you already have those in PATH, you don’t need the Krew versions. But if you want everything under the kubectl umbrella, the Krew install is cleaner.
stern, Multi-Pod Log Tailing
kubectl logs -f pod/myapp-xyz follows one pod. kubectl logs -f -l app=myapp works but mangles the output when multiple pods write simultaneously. stern does this right: color-codes each pod, prefixes lines with the pod name, and lets you filter by regex.
kubectl krew install stern# Tail all pods matching "myapp" in current namespacekubectl stern myapp
# Tail across all namespaces, filter to lines containing "error"kubectl stern --all-namespaces myapp --include error
# Tail by labelkubectl stern -l app=myappSample output (color in the terminal, monotone here):
myapp-7d6b9f8c9-4xk2p myapp 2026-07-25T03:14:12Z INFO request handled in 42msmyapp-7d6b9f8c9-9vwrq myapp 2026-07-25T03:14:12Z INFO request handled in 38msmyapp-7d6b9f8c9-4xk2p myapp 2026-07-25T03:14:13Z ERROR failed to connect to dbYour 2 AM self will appreciate not having to remember which pod name has the logs you actually need.
kubectl-images, What’s Running in Your Cluster
You want to audit image versions, find containers still on latest, or just figure out what’s deployed. kubectl-images gives you a deduplicated list.
kubectl krew install imageskubectl images -n monitoring[Summary]: 1 namespaces, 6 pods, 9 containers
CONTAINER IMAGE prometheus prom/prometheus:v2.53.0 alertmanager prom/alertmanager:v0.27.0 grafana grafana/grafana:11.1.0 node-exporter prom/node-exporter:v1.8.1 kube-state-metrics registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.13.0Useful for periodic image hygiene checks. Pipe it through grep latest to find the offenders.
kubectl-resource_capacity, Node Utilization at a Glance
kubectl top nodes gives you raw metrics. It doesn’t tell you what percentage of allocatable CPU/memory you’re using, or how much headroom you have before the scheduler starts having a bad time.
kubectl krew install resource-capacitykubectl resource-capacity --sort cpu.utilNODE CPU REQUESTS CPU LIMITS CPU UTIL MEMORY REQUESTS MEMORY LIMITS MEMORY UTILhomelab-01 1250m (31%) 2500m (62%) 420m (10%) 3.2Gi (41%) 6.4Gi (83%) 2.1Gi (27%)homelab-02 800m (20%) 1600m (40%) 310m (7%) 2.1Gi (27%) 4.2Gi (54%) 1.4Gi (18%)Add --pods to break it down by pod. Add --util to show actual utilization alongside requests/limits. This is the dashboard you run before adding more workloads to a node.
kubectl-view-secret, Decode Secrets Like a Human
Reading a Kubernetes Secret without plugins is an exercise in masochism:
kubectl get secret myapp-db -o jsonpath='{.data.password}' | base64 -dkubectl-view-secret skips the ceremony:
kubectl krew install view-secret# List all keys in a secretkubectl view-secret myapp-db
# Decode a specific keykubectl view-secret myapp-db password# hunter2
# Decode all keyskubectl view-secret myapp-db -a# DB_HOST=postgres.default.svc.cluster.local# DB_NAME=myapp# DB_PASSWORD=hunter2# DB_USER=myappNote: this decodes base64, not actual encryption. If you’re using Sealed Secrets or SOPS, this shows the decrypted-at-rest values that live in etcd. Treat the output accordingly.
kubectl-deprecations, Find API Breaks Before They Break You
You’re upgrading k3s from 1.29 to 1.31 and you’re wondering if any of your manifests use APIs that got removed. kubectl-deprecations scans your cluster and tells you.
kubectl krew install deprecationskubectl deprecationsCOMPONENT NAMESPACE KIND VERSION REPLACEMENT REMOVED DEPRECATEDcert-manager/webhook cert-manager ModuleSpec policy/v1beta1 policy/v1 1.25 1.21ingress-nginx/controller ingress-nginx Ingress networking.k1 networking.k1 - 1.22Run this before every minor version upgrade. It’s a lot less painful than discovering a removed API mid-upgrade because your Helm chart is two versions old.
kubectl-node-shell, Drop Into a Node
Sometimes you need to poke around on the node itself, check disk usage, look at host network state, inspect containerd’s storage. kubectl-node-shell creates a privileged debug pod on the target node and drops you into a shell with host PID, network, and IPC namespaces.
kubectl krew install node-shellkubectl node-shell homelab-01spawning "nsenter-xk4bq" on "homelab-01"If you don't see a command prompt, try pressing enter.root@homelab-01:/#You’re now in the host namespace. ps aux shows all host processes. df -h shows host disk. crictl images shows containerd’s image cache. Exit like a normal shell, the pod cleans up automatically.
Use this sparingly and purposefully. You’re root on the host.
kubectl-iexec, Interactive Container Picker for exec
kubectl exec requires you to know the full pod name. When pods have random suffixes and you just want to exec into the app container, kubectl-iexec gives you a fuzzy picker:
kubectl krew install iexeckubectl iexec myappIt presents an interactive list of matching pods and containers, you pick one, and you’re dropped into an exec session. Saves typing, saves copy-pasting pod names from a separate terminal tab.
kubectl-explore, Fuzzy-Find on kubectl explain
kubectl explain is great if you remember the exact resource name and field path. kubectl-explore adds fuzzy search across the full API schema:
kubectl krew install explorekubectl explore pod# Interactive fuzzy finder across pod spec fields# Type to filter: tolerations# → pod.spec.tolerations# → pod.spec.tolerations[].effect# → pod.spec.tolerations[].keyGood for those “what’s the field called again?” moments when writing manifests from scratch.
Writing Your Own Plugin (It’s Easier Than You Think)
Anything named kubectl-<something> that’s executable and in your PATH is automatically a kubectl plugin. No registration, no Krew required.
Here’s a 10-line bash wrapper that shows a quick cluster health summary, call it kubectl-myhelper:
#!/usr/bin/env bash# kubectl-myhelper — quick cluster health snapshot# Usage: kubectl myhelper
set -euo pipefail
echo "=== Nodes ==="kubectl get nodes -o wide
echo ""echo "=== Unhealthy Pods ==="kubectl get pods --all-namespaces --field-selector='status.phase!=Running,status.phase!=Succeeded' 2>/dev/null || echo "All pods healthy"
echo ""echo "=== Recent Events (Warnings) ==="kubectl get events --all-namespaces --field-selector=type=Warning --sort-by='.lastTimestamp' | tail -10Drop it in ~/.local/bin/kubectl-myhelper, make it executable:
chmod +x ~/.local/bin/kubectl-myhelperkubectl myhelperThat’s it. kubectl discovers it automatically. The kubectl- prefix is the only contract. You can write plugins in Python, Go, or anything else that produces an executable, bash is just the quickest to iterate on.
Keeping Things Updated
The Krew plugin index is separate from the plugins themselves. Update the index first, then upgrade your plugins:
kubectl krew update # refresh the indexkubectl krew upgrade # update all installed pluginsDo this before any cluster upgrade. Plugin maintainers often push updates when new Kubernetes versions drop, and running old plugin binaries against a new API server can produce cryptic errors.
The Bottom Line
Krew is low-overhead and high-payoff. It installs to ~/.krew, doesn’t touch your cluster, and the plugins are just binaries. The best ones, neat, tree, stern, view-secret, resource-capacity, node-shell, cover the exact gaps that make raw kubectl tedious for day-to-day cluster management.
Start with these six, add the others as you hit the use cases, and write a custom plugin the first time you find yourself running the same three-command sequence more than twice in a week.
Your future self, squinting at logs at 2 AM, will thank you.