Mastering K9s: The Kubernetes CLI on Steroids
Intro
If you’re working with Kubernetes, you’ve probably experienced the pain of juggling multiple terminal windows, typing long kubectl commands, and constantly switching contexts. Enter K9s - a terminal-based UI that transforms how you interact with your Kubernetes clusters.
In this guide, I’ll show you how to level up your K9s skills with custom shortcuts, plugins, and configurations that will make your Kubernetes workflow smoother and more efficient.
Getting Started with K9s
K9s provides an intuitive terminal UI for navigating, observing, and managing your Kubernetes resources. If you haven’t installed it yet, you can get it from the official GitHub repository.
Insight: K9s is a terminal-based UI that simplifies Kubernetes cluster management. It provides a more interactive and efficient way to navigate, observe, and manage your Kubernetes resources compared to traditional kubectl commands.
Essential Hotkeys
Let’s start with the basics. These are the hotkeys you’ll use constantly:
Navigation Basics
- SHIFT + ? - Help menu (your best friend when starting out)
- SHIFT + : - Command mode (with tab autocompletion)
- CTRL + r - Refresh the current view
- / - Filter resources in the current view
Context and Namespace Navigation
In command mode, you can quickly switch contexts and namespaces:
:context <CONTEXT> # or :ctx for short
:namespace <NAMESPACE> # or :ns for short
Resource Management
- e - Edit resource
- y - View resource in YAML format
- d - Describe resource (kubectl describe format)
- CTRL + d - Delete resource (with confirmation)
- CTRL + k - Delete resource (without confirmation - use with caution!)
- c - Copy resource name
- n - Copy current namespace
Pod-Specific Commands
When viewing pods:
- l - View logs
- f - Toggle fullscreen mode
- w - Toggle line wrapping
- a - Show logs from all containers
- s - Shell into the pod
- p - View logs from the previous pod instance
Deployment Commands
- r - Rollout restart
- Enter - View pods managed by this deployment
- i - Set image
Helm Commands
- v - View values
- r - View releases
Secret Management
- u - See which Pods or ServiceAccounts are using this Secret
- x - Decode base64-encoded Secret values to human-readable text
Power User Customizations
Now let’s dive into how you can extend K9s to fit your workflow perfectly.
Custom Aliases
Here are the aliases I use in my K9s configuration:
# In ~/.k9s/aliases.yaml
aliases:
sb: storage.cnrm.cloud.google.com/v1beta1/storagebuckets
arr: artifactregistry.cnrm.cloud.google.com/v1beta1/artifactregistryrepositories
bqds: bigquery.cnrm.cloud.google.com/v1beta1/bigquerydatasets
fk: kustomizations flux-system
ipm: iam.cnrm.cloud.google.com/v1beta1/iampolicymembers
isa: iam.cnrm.cloud.google.com/v1beta1/iamserviceaccounts
iua: imageupdateautomations
ip: imagepolicies
ir: image.toolkit.fluxcd.io/v1beta2/imagerepositories
dp: apps/v1/deployments
sec: v1/secrets
jo: batch/v1/jobs
cr: rbac.authorization.k8s.io/v1/clusterroles
crb: rbac.authorization.k8s.io/v1/clusterrolebindings
ro: rbac.authorization.k8s.io/v1/roles
rb: rbac.authorization.k8s.io/v1/rolebindings
np: networking.k8s.io/v1/networkpolicies
mqu: rabbitmq.com/v1beta1/users
Insight: Aliases save you from typing long resource names and API versions. For example, typing
:dp
is much faster than:deployments
or:apps/v1/deployments
. The aliases above cover standard Kubernetes resources, RBAC objects, Flux CD components, and GCP-specific resources.
You can access these aliases in command mode with :alias
.
Custom Keyboard Shortcuts
I’ve defined these keyboard shortcuts for quick access to resources:
# In ~/.k9s/hotkey.yml
hotKeys:
# Hitting Shift-0 navigates to your pod view
shift-0:
shortCut: Shift-0
description: Viewing pods
command: pods
# Hitting Shift-1 navigates to your deployments
shift-1:
shortCut: Shift-1
description: View deployments
command: dp
# Hitting Shift-2 navigates to your xray deployments
shift-2:
shortCut: Shift-2
description: ConfigMaps
command: cm
shift-3:
shortCut: Shift-3
description: ConfigMaps
command: sec
# Hitting "h" navigates to helm releases
h:
shortCut: h
description: Helm Releases
command: helmreleases
# Hitting "k" navigates to all namespaces
shift-k:
shortCut: Shift-K
description: All Kustomizations
command: fk
shift-E:
shortCut: Shift-E
description: Events
command: events
Core Configuration
My K9s configuration file controls the behavior and appearance of the UI:
# In ~/.k9s/config.yaml
k9s:
liveViewAutoRefresh: false
refreshRate: 2
maxConnRetry: 5
ui:
enableMouse: false
headless: false
logoless: false
noIcons: false
crumbsless: false
# skin: catppuccin
skin: nightfox
reactive: true
readOnly: false
imageScans:
enable: false
noExitOnCtrlC: false
shellPod:
image: busybox:1.35.0
namespace: default
limits:
cpu: 100m
memory: 100Mi
skipLatestRevCheck: false
logger:
tail: 100
buffer: 5000
sinceSeconds: 60
#fullScreen: false
textWrap: false
showTime: false
thresholds:
cpu:
critical: 90
warn: 75
memory:
critical: 90
warn: 75
# screenDumpDir: $XDG_HOME/k9s/screendumps/
disablePodCounting: false
Insight: This configuration optimizes K9s for performance and usability. The
refreshRate: 2
provides a good balance between real-time updates and API server load. TheshellPod
configuration defines a lightweight container (busybox) for shelling into pods that don’t have a shell. The resource thresholds help identify problematic pods by highlighting them when they exceed CPU or memory thresholds.
Custom Views
I’ve customized the columns displayed for Flux CD Kustomizations:
# In ~/.k9s/views.yaml
views:
kustomize.toolkit.fluxcd.io/v1/kustomizations:
columns:
- NAME
- STATUS
- SUSPENDED:.spec.suspend
- DISABLED:.metadata.annotations.kustomize\.toolkit\.fluxcd\.io/reconcile
- READY
- AGE
Insight: Custom views are particularly valuable for Custom Resource Definitions (CRDs) like Flux CD Kustomizations. This view surfaces important information that’s normally buried in the resource spec, such as whether a Kustomization is suspended or has reconciliation disabled.
Plugins for Extended Functionality
Here are the plugins I use to extend K9s functionality:
# In ~/.k9s/plugin.yml
plugins:
# View logs using stern
stern:
shortCut: Ctrl-L
confirm: false
description: "Logs <Stern>"
scopes:
- pods
- deployments
command: bash
background: false
args:
- -c
- >-
stern $NAME -n $NAMESPACE --context $CONTEXT --color always 2>&1 | fzf --ansi --tail 1000 --tac --no-sort --exact --wrap
--bind 'enter:execute:kubectl exec -it {1} -n $NAMESPACE --context $CONTEXT -- bash'
--header 'Press CTRL-Y to copy selected line' --header-lines=1
Insight: The stern plugin combines the power of stern (multi-pod/container log viewing) with fzf (fuzzy finding) to create an interactive log experience. You can search logs in real-time, and even execute commands on pods directly from the log view by pressing Enter on a log line.
# Edit decoded secrets
edit-secret:
shortCut: Ctrl-X
confirm: false
description: "Edit Decoded Secret"
scopes:
- secrets
command: kubectl
background: false
args:
- modify-secret
- --namespace
- $NAMESPACE
- --context
- $CONTEXT
- $NAME
Insight: The edit-secret plugin simplifies secret management by allowing you to edit decoded secret values directly. This eliminates the need to manually decode, edit, and re-encode secrets.
# View tree of resources created by selected Kustomization
flux-tree:
shortCut: t
confirm: false
scopes:
- kustomizations
description: Flux tree Kustomization
command: bash
background: false
args:
- -c
- >-
flux tree kustomization $NAME --context $CONTEXT -n $NAMESPACE | less -K
Insight: The flux-tree plugin visualizes the entire dependency tree of resources created by a Kustomization, making it easier to debug issues with GitOps deployments.
# Get all suspended Kustomizations
get-suspended-kustomizations:
shortCut: Shift-S
confirm: false
description: Suspended Kustomizations
scopes:
- kustomizations
command: sh
background: false
args:
- -c
- >-
kubectl get
--context $CONTEXT
--all-namespaces
kustomizations.kustomize.toolkit.fluxcd.io -o json
| jq -r '.items[] | select(.spec.suspend==true) | [.metadata.name,.spec.suspend] | @tsv'
| less -K
# Check selected Kustomization suspend status
kustomization-suspend-status:
shortCut: s
confirm: false
description: Kustomization Suspend Status
overwriteOutput: true
scopes:
- kustomizations
command: sh
background: true
args:
- -c
- >-
kubectl get kustomization $NAME
--namespace $NAMESPACE
--context $CONTEXT
-o json | jq -r '.spec | if has("suspend") then "Suspended" else "Not Suspended" end' | less -K
# Toggle reconcile annotation for Kustomization
toggle-kustomization-annotation:
shortCut: Shift-D
confirm: true
scopes:
- kustomizations
description: Toggle reconcile annotation for Kustomization
command: bash
background: true
args:
- -c
- >-
annotation="kustomize.toolkit.fluxcd.io/reconcile";
current=$(kubectl --context $CONTEXT get kustomization -n $NAMESPACE $NAME -o=jsonpath="{.metadata.annotations['$annotation']}");
if [[ "$current" == "disabled" ]]; then
kubectl --context $CONTEXT annotate kustomization -n $NAMESPACE $NAME $annotation-;
else
kubectl --context $CONTEXT annotate kustomization -n $NAMESPACE $NAME $annotation="disabled" --overwrite;
fi
Insight: This plugin toggles the reconciliation annotation on Kustomizations, allowing you to temporarily disable reconciliation without suspending the entire resource. This is useful when you want to make manual changes without Flux immediately overwriting them.
# Suspend/Resume selected Kustomization
toggle-kustomization:
shortCut: Shift-T
confirm: true
scopes:
- kustomizations
description: Toggle to suspend or resume Kustomization
command: bash
background: true
args:
- -c
- >-
suspended=$(kubectl --context $CONTEXT get kustomizations -n $NAMESPACE $NAME -o=custom-columns=TYPE:.spec.suspend | tail -1); verb=$([[ $suspended == "true" ]] && echo "resume" || echo "suspend"); flux $verb kustomization --context $CONTEXT -n $NAMESPACE $NAME
# Get all suspended HelmReleases
get-suspended-helmreleases:
shortCut: Shift-S
confirm: false
description: Suspended HelmReleases
scopes:
- helmreleases
command: sh
background: false
args:
- -c
- >-
kubectl get
--context $CONTEXT
--all-namespaces
helmreleases.helm.toolkit.fluxcd.io -o json
| jq -r '.items[] | select(.spec.suspend==true) | [.metadata.name,.spec.suspend] | @tsv'
| less -K
# Suspend/Resume selected HelmRelease
toggle-hr:
shortCut: Shift-T
confirm: true
scopes:
- helmreleases
description: Toggle to suspend or resume HelmRelease
command: bash
background: true
args:
- -c
- >-
suspended=$(kubectl --context $CONTEXT get hr -n $NAMESPACE $NAME -o=custom-columns=TYPE:.spec.suspend | tail -1); verb=$([[ $suspended == "true" ]] && echo "resume" || echo "suspend"); flux $verb hr --context $CONTEXT -n $NAMESPACE $NAME
# Reconcile selected Kustomization
reconcile-ks:
shortCut: r
confirm: false
description: Flux reconcile
scopes:
- kustomizations
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile kustomization -n $NAMESPACE $NAME"
# Reconcile selected Kustomization with force
reconcile-ks-force:
shortCut: Shift-F
confirm: false
description: Flux reconcile Kustomization force
scopes:
- kustomizations
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile ks -n $NAMESPACE $NAME --force"
Insight: The force reconciliation plugin is valuable when you need to override drift detection and force resources to match the desired state in Git, even if Kubernetes reports them as already in sync.
# Reconcile selected Kustomization with source
reconcile-ks-with-source:
shortCut: Shift-R
confirm: false
description: Flux reconcile with source
scopes:
- kustomizations
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile kustomization -n $NAMESPACE $NAME --with-source"
Insight: This plugin reconciles both the Kustomization and its source (like a GitRepository), ensuring that the latest changes from Git are pulled before reconciling. This is useful when you’ve just pushed changes and want to apply them immediately.
# Reconcile selected HelmRelease
reconcile-hr:
shortCut: r
confirm: false
description: Flux reconcile HelmRelease
scopes:
- helmreleases
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile hr -n $NAMESPACE $NAME"
# Reconcile selected HelmRelease with force
reconcile-hr-force:
shortCut: Shift-F
confirm: false
description: Flux reconcile HelmRelease force
scopes:
- helmreleases
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile hr -n $NAMESPACE $NAME --force"
# Reconcile selected HelmRelease with source
reconcile-hr-with-source:
shortCut: Shift-R
confirm: false
description: Flux reconcile HelmRelease with-source
scopes:
- helmreleases
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile hr -n $NAMESPACE $NAME --with-source"
# Reconcile selected ImageRepository
reconcile-image-repository:
shortCut: Shift-R
confirm: false
description: Flux reconcile ImageRepository
scopes:
- imagerepositories
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile image repository -n $NAMESPACE $NAME"
Insight: For Flux image automation, this plugin forces an immediate scan of an ImageRepository, which is useful when you’ve just pushed a new image and want Flux to detect it without waiting for the normal scan interval.
# Reconcile selected ImageUpdateAutomation
reconcile-image-update-automation:
shortCut: Shift-R
confirm: false
description: Flux reconcile ImageUpdateAutomation
scopes:
- imageupdateautomation
command: bash
background: true
args:
- -c
- "flux --context $CONTEXT reconcile image update -n $NAMESPACE $NAME"
Insight: This plugin triggers the image update automation process, which checks for new images and updates the manifests in Git. It’s useful when you want to immediately apply image updates without waiting for the automation interval.
Pro Tips
Sorting and Filtering
K9s offers powerful sorting and filtering capabilities:
- SHIFT-c - Sort by CPU usage
- CTRL-q - Sort by memory usage as a percentage of limits
- CTRL-z - Show only resources with errors (CrashLoopBackOff, Pending, etc.)
Custom Views
You can customize the columns displayed for different resources by editing the ~/.k9s/views.yaml
file. This is especially useful for custom resources where you want to highlight specific fields.
Conclusion
K9s transforms the Kubernetes command-line experience into something much more interactive and efficient. By customizing it with aliases, hotkeys, and plugins, you can create a workflow that perfectly matches your needs.
The best part? All these customizations are stored in simple YAML files that you can version control and share with your team.