k9s & stern
Summary
- Definition: k9s is a terminal UI that navigates live cluster state, and stern is a multi-pod log tailer; together they replace long chains of
kubectlcommands during triage. - Insight: Both are pure clients that use your existing kubeconfig and RBAC, so they never grant access you do not already have.
- Key Concepts: resource views and hotkeys in k9s, pod-name regex matching in stern, context switching, and read-only observability of running workloads.
- When to Use: during incident response, when a Deployment has many replicas, or when you need to see logs, describe, and shell into pods without retyping
kubectl. - Limitations: they are debugging aids, not automation; do not build pipelines on interactive tools.
Recipe
Install both, point them at a cluster, and drive triage from the terminal.
brew install k9s stern # or: go install / krew for k9s
k9s --context prodk9sopens a live UI; type:pods,:deploy, or:eventsto switch views.- Use stern for logs across many pods:
stern -n prod 'checkout-.*'. - Both honor your current kubeconfig context and namespace by default.
Working Example
Suppose the checkout service is throwing errors after a deploy.
Start k9s scoped to the namespace.
k9s -n checkoutInside k9s, navigate the incident.
:pods # list pods in the namespace
/checkout # filter to matching pods
<enter> on pod # drill into containers
l # stream that pod's logs
d # describe (events, restarts, image)
s # open a shell in the container
:events # cluster events, newest lastNow tail every checkout replica at once with stern to correlate errors.
stern -n checkout 'checkout-.*' \
--since 15m \
--container app \
--output raw | grep -i "error\|panic\|timeout"- The regex matches all replicas of the Deployment's pods.
--since 15mkeeps output to the recent window around the deploy.--container appavoids sidecar noise.--output rawemits just the log line sogrepworks cleanly.
To watch a rollout finish while you read logs, split terminals and run kubectl alongside.
kubectl -n checkout rollout status deploy/checkout --timeout=120sDeep Dive
How k9s navigates
k9s watches the API and renders resources as scrollable tables that update in place.
The command bar (:) jumps to any resource type, including CRDs like :certificates or :backups.
Hotkeys act on the selected row: l logs, d describe, s shell, y view YAML, Ctrl-d delete (with confirmation).
:ctx switches clusters and :ns switches namespaces without leaving the UI.
Because it uses your kubeconfig, k9s can only do what your RBAC allows; a read-only user sees a read-only UI.
How stern matches pods
stern's first positional argument is a regular expression matched against pod names, not a single pod.
That is the core advantage: one command follows a Deployment's pods as they come and go during a rollout.
Useful flags include --since (time window), --container (regex over container names), --tail (lines per pod on start), and --timestamps.
Output templates like --output raw or --template let you strip prefixes for piping into grep, jq, or a file.
stern reconnects to new pods automatically, so scaling up mid-tail just adds more streams.
Configuration and aliases
k9s reads config and skins from ~/.config/k9s, where you can define aliases and column layouts.
Commit a shared k9s config and a set of stern aliases to your team repo so everyone triages the same way.
Gotchas
Tailing too broadly floods the terminal. A bare stern . in a busy namespace is unreadable; always scope by namespace and a specific regex.
Forgetting the context. k9s and stern both act on your current context; run kubectl config current-context first so you are not debugging the wrong cluster.
Assuming write access exists. If a hotkey seems to do nothing, it is often RBAC denying the verb, not a bug; check with kubectl auth can-i.
Logs disappear after a crash. For a CrashLoopBackOff pod, use stern --tail 200 plus kubectl logs --previous to see the last run before the restart.
stern regex surprises. The argument is a regex, so a dot matches any character; quote patterns and anchor them when you mean a literal name prefix.
Alternatives
Plain kubectl works everywhere with no install, but is verbose for multi-pod log tailing and live navigation.
kubectl plugins via krew (for example kubectl-tail, stern itself packaged as a plugin) blend into your existing workflow if you prefer one binary.
Lens or Headlamp are graphical desktop dashboards; richer visuals, but heavier and less scriptable than terminal tools.
Cloud consoles (EKS, GKE, AKS dashboards) are fine for a glance, but slower for high-pressure, multi-pod debugging than k9s and stern.
Pick k9s and stern when you live in the terminal and want fast, keyboard-driven triage; pick a GUI when onboarding or sharing a screen with non-terminal users.
FAQs
Do k9s or stern need cluster-admin? No. They use your kubeconfig and are bound by your RBAC; a read-only role gives read-only behavior.
Can stern follow pods created after it starts? Yes. It matches on a pod-name regex and attaches to new matching pods automatically as they appear.
How do I see logs from a crashed container's previous run?
Use kubectl logs --previous for a single pod; stern shows current streams, so pair it with kubectl for prior instances.
Is k9s safe to run against production? Yes, for read and triage. Be careful with destructive hotkeys like delete, which prompt for confirmation but still act with your permissions.
Can I filter stern by label instead of name?
Yes. Use --selector app=checkout to match by label, which is more stable than pod-name regex across Deployments.
Related
- The Platform Engineer's Toolkit, Conceptually
- Platform Tools Basics
- cert-manager
- external-dns
- Platform Tools Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).