Skip to content
somaz94Public

About

Single-binary kubectx/kubens replacement with per-terminal context isolation, production guards, a built-in fuzzy picker (no fzf), and a cluster health check

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

kube-ctx

CI E2E License: Apache 2.0 Latest Tag Top Language

kctx — a single-binary replacement for kubectx and kubens that fixes the three things which make them risky once you have more than a couple of clusters: a current-context every terminal shares, no guard rail in front of production, and an external fzf dependency for the picker.

kctx opens its built-in picker, narrows it to the production contexts, and makes you retype prod-eks before it switches

For detailed documentation, see the docs/ folder:

Usage | Configuration | Examples | Use Cases | Deployment | Development


Why kube-ctx?

kubectx + kubens kctx
Scope of a switch Global — every terminal follows Per-terminal via the shell hook or kctx shell, global otherwise
Production guard None Contexts — and the namespaces inside them — classified by name, exact list, prefix or suffix; colored everywhere, and confirm gates ctx, ns, shell, exec and export alike
Context per project — kctx bind: cd into a repo, this terminal follows
Interactive picker Needs fzf on $PATH Built in — no external dependency (not on Windows yet, where kctx prints the list)
Run against another cluster Switch, run, switch back kctx exec prod -- kubectl get pods
The same question, every cluster A for loop that switches and hopes kctx exec --all -- kubectl get nodes, in parallel
Namespace list offline Fails when the API server is unreachable Falls back to a cache and says so
Cluster health — kctx doctor: reachability, version, expired certs and tokens
Certificates about to expire — kctx expiry: every cluster's TLS secrets and cert-manager Certificates in one table
Adding someone's kubeconfig Hand-merge, or --flatten and hope the names do not clash kctx import: colliding stanzas are disambiguated, never overwritten
Handing one context over Edit a copy by hand kctx export prod --flatten -f prod.yaml
Backups — Automatic before every destructive kubeconfig edit
Binaries Two One

The problem it solves

A kubeconfig has exactly one current-context. Switch it in one tab and every other tab follows — including the one where you are halfway through a production incident. kctx gives each terminal its own copy of the kubeconfig and points $KUBECONFIG at it:

# terminal A                     # terminal B
$ kctx ctx prod-eks              $ kubectl config current-context
Switched to context prod-eks.    dev-cluster        # unchanged

That behavior needs a shell hook, because a child process cannot change its parent's environment. One line in your rc file installs it:

eval "$(kctx init zsh)"     # or bash; fish: kctx init fish | source

Without the hook, kctx edits the global kubeconfig exactly the way kubectx does — nothing breaks, you just do not get the isolation.


Quick Start


Install

# Homebrew (macOS / Linux)
brew install somaz94/tap/kube-ctx

# Scoop (Windows)
scoop bucket add somaz94 https://github.com/somaz94/scoop-bucket
scoop install kube-ctx

# krew (kubectl plugin)
kubectl krew index add somaz94 https://github.com/somaz94/krew-index
kubectl krew install somaz94/ctx2

# Install script
curl -fsSL https://raw.githubusercontent.com/somaz94/kube-ctx/main/scripts/install.sh | bash

# From source
git clone https://github.com/somaz94/kube-ctx.git
cd kube-ctx && make build && make install       # → /usr/local/bin/kctx

Prebuilt archives without the install script: Deployment → Binary.

Then, for per-terminal isolation, one line in your rc file:

eval "$(kctx init zsh)"     # bash: kctx init bash;  fish: kctx init fish | source

On the krew install, the binary is named kubectl-ctx2, and switching through kubectl ctx2 ctx ... is always global — kubectl runs a plugin as a subprocess, which cannot change the shell that called it. Install the hook against kubectl-ctx2 and call it directly for shell-local switching. See Deployment.


Use

kctx                             # (via ctx) interactive picker
kctx prod-eks                    # switch, the way kubectx takes it
kctx ctx prod-eks                # the same thing, spelled out
kctx -                           # back to the previous context
kctx ns kube-system              # namespace of the current context
kctx list --wide                 # everything at a glance
kctx doctor                      # what still works?
kctx expiry                      # what runs out in the next 30 days?
kctx exec prod-eks -- kubectl get nodes    # one command, no switch
kctx exec --all -- kubectl get nodes       # every cluster, in parallel
kctx bind dev                    # cd here later, and this terminal follows
kctx shell prod-eks              # a subshell pinned to prod

Commands

Command What it does
kctx [name|-|-N] Switch context. No argument opens the picker; - goes back
kctx ctx [name|-|-N] The same, spelled out — and the way to reach a context named like a subcommand
kctx ns [name|-|-N] Switch the namespace of the current context
kctx current [-n] Print the current context (or namespace) and exit — for prompts
kctx list [--wide] Table of every context, with guard badges
kctx rename <old> <new> Rename a context (. = current)
kctx delete|rm|del <name>... [--prune] Delete contexts, optionally their orphaned cluster/user entries
kctx import <file>... [--prune] Merge contexts from another kubeconfig, without colliding
kctx export [name]... [-f file] Write contexts out as a standalone kubeconfig
kctx alias <name> <context> Short names usable anywhere a context is
kctx bind [context] Bind a directory to a context; cd there switches
kctx guard add|list|remove Classify a context — or a namespace inside it — as production, without writing a regex
kctx doctor [context...] Parallel health check; non-zero exit if anything is broken
kctx expiry|expire|certs [context...] What TLS certificates expire soon, across every cluster; exit 2 inside the window, or when a cluster could not be read
kctx shell [context] Subshell pinned to a context
kctx sessions [--clean] List the per-terminal kubeconfig copies, and tidy them
kctx exec <context> -- <cmd> Run one command against a context
kctx exec --all|-c a,b -- <cmd> Run it against many contexts at once
kctx init bash|zsh|fish Shell hook + completions
kctx version Build information

Global flags: --kubeconfig, -o color|plain|json, --no-color, -y/--yes. An unknown -o value is an error rather than a silent fallback, so a script asking for -o jsno never gets a human table to parse.

Exit status is scriptable: 1 is kube-ctx failing, 2 is doctor finding a sick cluster, or expiry finding a certificate inside the window or failing to read a cluster at all, 130 is you declining a prompt — so kctx ctx prod && ./deploy.sh does not deploy when you back out. See Usage.


Production guards

Contexts are classified by name. Out of the box prod, prd and production are marked DANGER, staging/uat WARN — labels only, nothing blocks. Turn a rule into a real gate in ~/.config/kube-ctx/config.yaml:

guards:
  - match: '(^|[-_.])(prod|production)([-_.]|$)'
    level: danger
    confirm: true          # retype the context name to switch to it

aliases:
  p: prod-eks-apne2
$ kctx ctx prod-eks-apne2
! prod-eks-apne2 is classified danger by the guard rule (^|[-_.])(prod|production)([-_.]|$).
Type "prod-eks-apne2" to continue:

The gate covers kctx shell and kctx exec too, not just switching — otherwise kctx exec prod -- kubectl delete deploy/api would walk straight past it. Declining exits 130, so kctx ctx prod && ./deploy.sh does not deploy.

Names lie, though — the cluster that would hurt most to break is often the one called cluster-7. Name it directly, no regex and no editing:

kctx guard add cluster-7 --confirm --label PROD
kctx guard add --suffix -live --level danger
kctx guard list

A rule can also list namespaces:, which moves it onto the other axis: it then guards those namespaces inside the contexts it matches, rather than the contexts themselves. That is the guard for someone who lives in a production cluster all day, where the risk is not arriving but what gets deleted in kube-system — and it covers kctx ctx, kctx ns, kctx exec -n and kctx shell -n alike:

kctx guard add --prefix prod- -n kube-system --confirm

See Configuration for every field.


What expires next

Certificates run out on a schedule nobody is watching. kctx expiry reads every kubernetes.io/tls secret in every context, in parallel, and reports what falls inside the next 30 days:

$ kctx expiry --days 30
CONTEXT   NAMESPACE  KIND         NAME          IN
prod-eks  istio      Certificate  gateway-cert  8d (auto)
prod-eks  default    Secret/tls   legacy-api    19d
staging   ingress    Secret/tls   wildcard      27d

The certificate is the unit, not whatever manages it — a secret pasted in by hand two years ago shows up next to a cert-manager Certificate. Where cert-manager is present its Certificates are folded in, which is what separates the rows that renew themselves ((auto), dimmed) from the ones somebody has to act on. This is deliberately not doctor: nothing here is broken yet, which is the point of being told. Exit 2 inside the window makes it a cron gate — kctx expiry --days 30 || notify-oncall. See Usage.


Taking on another kubeconfig

Someone sends you a kubeconfig. The usual answer is KUBECONFIG=a:b kubectl config view --flatten > merged, and it has a trap: every kubeadm cluster calls its cluster kubernetes and its user kubernetes-admin, so the merge resolves the collision by first-writer-wins and the contexts from the file listed second quietly land on the first file's API server. You find out later, from the wrong cluster.

$ kctx import ~/Downloads/kubeconfig.yaml
CONTEXT                      ACTION  CLUSTER       USER                SOURCE
kubernetes-admin@kubernetes  added   kubernetes-2  kubernetes-admin-2
Imported 1 context(s). Switch to one with kctx ctx <name>.

A stanza whose contents differ is never replaced — the incoming one lands under a name of its own and only the imported context points at it. A stanza identical to one already there is reused rather than duplicated, so re-running an import is a no-op instead of a pile of copies. Colliding context names are refused outright until you say what to do about them (--prefix, --as, --overwrite), and --dry-run shows the whole plan first.

The other direction hands one context to someone else, or takes a backup:

kctx export prod --flatten -f prod.yaml   # certificates inlined, so it works elsewhere
kctx export --all -f backup.yaml          # everything

Exports are written 0600, never overwrite a file without --force, and a confirm guard applies — handing over a kubeconfig is handing over a route to the cluster. See Usage.


Where things are stored

Path Contents
$XDG_CONFIG_HOME/kube-ctx/config.yaml aliases, guard rules
$XDG_STATE_HOME/kube-ctx/history* context and namespace history
$XDG_STATE_HOME/kube-ctx/backups/ kubeconfig snapshots, 10 generations
$XDG_STATE_HOME/kube-ctx/shells/ per-terminal kubeconfig copies (kctx sessions)
$XDG_CACHE_HOME/kube-ctx/namespaces/ namespace list cache

Everything is created 0600/0700 — the copies hold credentials. Nothing is written to ~/.kube/ except the kubeconfig edit you asked for, and destructive edits are backed up first.


Related projects

  • kube-diff: Diff local manifests (plain YAML, Helm, Kustomize) against the live cluster.
  • kube-events: View and summarize Kubernetes events, grouped by resource with warnings first.

License

Apache 2.0 — see LICENSE.

About

Single-binary kubectx/kubens replacement with per-terminal context isolation, production guards, a built-in fuzzy picker (no fzf), and a cluster health check

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages