kubectl contexts and namespaces
Work safely across multiple clusters. How kubeconfig is structured, switching contexts and namespaces, and avoiding the wrong-cluster mistake.
Almost everyone ends up with several clusters, local, dev, staging, production, reachable from the same terminal, with no visual difference between them.
Running a destructive command against the wrong one is the most common serious mistake people make with Kubernetes. Nothing in kubectl's output warns you, so the safeguards have to be set up deliberately.
How kubeconfig is structured
~/.kube/config holds three lists and a pointer:
apiVersion: v1
kind: Config
current-context: dev
clusters:
- name: prod-cluster
cluster:
server: https://prod.k8s.example.com
certificate-authority-data: LS0tLS1...
users:
- name: prod-admin
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args: [eks, get-token, --cluster-name, production]
contexts:
- name: prod
context:
cluster: prod-cluster
user: prod-admin
namespace: payments
A context binds a cluster, a user and a default namespace. Switching context switches all three at once.
The exec block is how cloud clusters authenticate, kubectl shells out to aws, gcloud or az to mint a short-lived token each time. That is why an expired cloud login produces a kubectl auth error rather than a cloud CLI one.
Everyday commands
kubectl config get-contexts
CURRENT NAME CLUSTER NAMESPACE
dev dev-cluster default
* staging stage-cluster payments
prod prod-cluster payments
kubectl config current-context # where am I?
kubectl config use-context prod # switch
kubectl config set-context --current --namespace=payments # default namespace
kubectl config delete-context old-cluster # tidy up
kubectl config current-context before anything destructive is a cheap habit that prevents an expensive mistake.
Namespaces
kubectl get pods -n payments
kubectl get pods -A # every namespace
kubectl config set-context --current --namespace=payments
Forgetting the namespace is the most common reason for "No resources found" when you know something is running. kubectl get pods -A settles it immediately.
The namespace is part of the context, so setting it while on staging does not affect prod. That is usually what you want.
Several kubeconfig files
The KUBECONFIG variable takes a list, and kubectl merges them in order:
export KUBECONFIG=~/.kube/config:~/.kube/prod-config:~/.kube/client-a.yaml
kubectl config get-contexts
Merging is useful when clusters come from different sources: a cloud CLI, a client, a local kind cluster. Keeping production in its own file that you source only when needed is itself a safeguard.
To write a genuine merged file:
KUBECONFIG=~/.kube/config:~/.kube/new-cluster.yaml \
kubectl config view --flatten > ~/.kube/merged && mv ~/.kube/merged ~/.kube/config
--flatten inlines the certificate data, which a plain config view leaves as file references that then break.
Cloud CLIs add contexts for you:
aws eks update-kubeconfig --region us-east-1 --name production
gcloud container clusters get-credentials production --region us-central1
az aks get-credentials --resource-group rg --name production
These generate long context names like arn:aws:eks:us-east-1:111122223333:cluster/production. Rename them:
kubectl config rename-context arn:aws:eks:us-east-1:111122223333:cluster/production prod
Not losing track of where you are
Put the context in your shell prompt. This is the single most effective safeguard. kube-ps1 does it, and most prompt frameworks, starship, powerlevel10k, oh-my-zsh, have a Kubernetes segment built in:
[prod:payments] ~/work/infra $
Use kubectx and kubens. Interactive switching with fuzzy matching, far less typing than the kubectl config commands, and kubectx - jumps back to the previous context:
brew install kubectx
kubectx prod
kubens payments
Scope a single command instead of switching. If you only need one command elsewhere, do not change the global context at all:
kubectl --context=prod get pods -n payments
This is much safer in scripts, and it is what CI should do, never rely on ambient context in automation.
Keep a read-only context for production. A second user entry bound to a read-only ClusterRole, used by default, with the admin context reserved for when you genuinely intend to change something. RBAC refusing a destructive command is a far better guard than remembering not to type it.
Contexts in CI
Never depend on current-context in automation. Pass an explicit kubeconfig and context:
export KUBECONFIG=/tmp/kubeconfig
aws eks update-kubeconfig --region us-east-1 --name production --kubeconfig $KUBECONFIG
kubectl --context=arn:aws:eks:... apply -f ./manifests/
A pipeline that inherits whatever context happened to be set is one refactor away from deploying to the wrong cluster.
Checking what you can actually do
kubectl auth can-i delete pods -n payments
kubectl auth can-i '*' '*' # am I cluster admin here?
kubectl auth can-i list secrets --as=system:serviceaccount:payments:api
kubectl auth can-i is worth knowing for two reasons: it tells you whether a permission error is RBAC or something else, and --as lets you check a service account's permissions without impersonating it in anger.
Quick reference
| Task | Command |
|---|---|
| Where am I | kubectl config current-context |
| List contexts | kubectl config get-contexts |
| Switch | kubectl config use-context <name> |
| Set default namespace | kubectl config set-context --current --namespace=<ns> |
| Rename | kubectl config rename-context <old> <new> |
| Remove | kubectl config delete-context <name> |
| One-off elsewhere | kubectl --context=<ctx> get pods |
| Merge configs | KUBECONFIG=a:b kubectl config view --flatten |
| Check permissions | kubectl auth can-i <verb> <resource> |
| Full config | kubectl config view |
Key takeaways
- A context binds a cluster, a user and a default namespace. Switching changes all three.
- Check
current-contextbefore anything destructive: nothing else will warn you. - Put the context in your shell prompt. It is the highest-value safeguard available.
kubectl get pods -Aresolves most "No resources found" confusion instantly.--context=scopes one command without changing global state; use it in scripts.KUBECONFIGmerges files with:, andconfig view --flattenwrites a real merged file.- Never rely on ambient context in CI. Pass the kubeconfig and context explicitly.
- A read-only production context stops mistakes at the RBAC layer rather than relying on care.
Check your understanding
Nothing found
kubectl get pods returns "No resources found in default namespace" on a cluster where you know workloads are running. What are the two things to check?
A pipeline that deployed to the wrong cluster
A CI job runs kubectl apply with no --context and no explicit KUBECONFIG, relying on whatever context the runner has set. What is the problem?
Frequently Asked Questions
What is a kubectl context?
A named combination of a cluster, a user credential and a default namespace, stored in your kubeconfig. Switching context with kubectl config use-context <name> changes all three at once, which is how you move between clusters without editing configuration. kubectl config get-contexts lists them with the current one marked, and kubectl config current-context prints just the active name.
How do I switch between Kubernetes clusters?
kubectl config use-context <name> changes the active context. For a single command elsewhere, kubectl --context=prod get pods avoids changing global state at all, which is safer and is what scripts should do. kubectx makes interactive switching much quicker, with fuzzy matching and kubectx - to jump back to the previous context.
How do I change the default namespace?
kubectl config set-context --current --namespace=payments sets it for the current context, so you stop passing -n on every command. Because the namespace is part of the context, changing it on staging leaves prod untouched. kubens does the same thing interactively if you have kubectx installed.
How do I use multiple kubeconfig files?
Set KUBECONFIG to a colon-separated list, export KUBECONFIG=~/.kube/config:~/.kube/client-a.yaml, and kubectl merges them, exposing every context. To produce a single merged file, run KUBECONFIG=a:b kubectl config view --flatten > merged; the --flatten flag inlines certificate data, which a plain config view leaves as file paths that then break when the file moves. Keeping production credentials in a separate file you source deliberately is itself a useful safeguard.
How do I avoid running commands against the wrong cluster?
Show the current context in your shell prompt, kube-ps1, or the Kubernetes segment in starship, powerlevel10k or oh-my-zsh, so it is always visible. Prefer kubectl --context=<name> for one-off commands rather than switching globally. Most importantly, make production read-only by default with a separate admin context used only when you intend to change something, so RBAC refuses destructive commands rather than relying on you remembering which cluster you are on.
Why does kubectl ask me to log in again on a cloud cluster?
Cloud kubeconfigs use an exec credential plugin that shells out to aws, gcloud or az to obtain a short-lived token on each call. When that CLI's own session expires, kubectl surfaces it as an authentication failure even though the kubeconfig itself is fine. Re-authenticating with the cloud CLI, aws sso login, gcloud auth login, restores access without touching your Kubernetes configuration.