| Tested on | Rocky Linux 10.2 (Red Quartz) workstation |
|---|---|
| Package | kubectl 1.36.3 |
| Applies to | Any host with kubectl configured; any Kubernetes cluster |
| Cert prep | CKAD · CKA · CKS |
| Lab environment | Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm |
| Privilege | Normal user (no sudo required on the workstation) |
| Scope | Namespace concepts, namespaced vs cluster-scoped resources, kubectl -n and --all-namespaces, and setting a default namespace on the current context. Does not cover multi-cluster kubeconfig, merging kubeconfig files, ResourceQuota, namespace RBAC, or NetworkPolicy. |
| Related guides | Kubernetes pods Kubernetes Services Kubernetes RBAC Kubernetes architecture |
Kubernetes namespaces group namespaced resources into separate named scopes within the same cluster. They cannot be nested, and each namespaced object belongs to exactly one namespace. Nodes, Namespaces, PersistentVolumes, and other cluster-scoped objects are not divided by namespaces. A kubectl context can also store a default namespace so you do not need -n on every command.
In this walkthrough you create development and testing namespaces, deploy the same Deployment name in both, switch kubectl between them, set a default namespace on your context, and reach a Service across namespace boundaries. For clusters, users, multiple kubeconfig files, and remote API access, see Install kubectl and configure kubeconfig.
What Is a Kubernetes Namespace?
A namespace provides a scope for names within a given API resource type. Names must be unique for the same kind inside a namespace, but the same string can exist in another namespace on the same cluster. For example, a Deployment and a Service may both be named web in development, while two Deployments both named web in the same namespace cannot coexist.
Namespaces cannot be nested. A namespace is not a separate cluster, and namespace boundaries do not by themselves provide workload, network, or security isolation.
development
└── deployment/web
testing
└── deployment/webAlthough both Deployments are named web, their complete identities include their namespaces. Changes made to development/web do not modify testing/web.
Default Kubernetes Namespaces
List namespaces on a new cluster:
kubectl get namespacesSample output:
NAME STATUS AGE
default Active 163m
kube-node-lease Active 163m
kube-public Active 163m
kube-system Active 163mBrief roles:
default— used for namespaced objects when no other namespace is selectedkube-system— contains Kubernetes system objects and many cluster add-ons, commonly including CoreDNSkube-public— intended for publicly readable cluster information; it is normally readable by all clients, including unauthenticated clients when cluster authorization permits the standard behaviorkube-node-lease— contains Lease objects used for node heartbeats and node availability tracking
Do not create custom namespaces whose names start with kube-. Kubernetes reserves that prefix for system namespaces.
Namespaced and Cluster-Scoped Resources
List API resources that live inside a namespace:
kubectl api-resources --namespaced=trueSample output (trimmed):
NAME SHORTNAMES APIVERSION NAMESPACED KIND
configmaps cm v1 true ConfigMap
pods po v1 true Pod
secrets v1 true Secret
services svc v1 true Service
deployments deploy apps/v1 true DeploymentList cluster-scoped resources:
kubectl api-resources --namespaced=falseSample output (trimmed):
NAME SHORTNAMES APIVERSION NAMESPACED KIND
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumes pv v1 false PersistentVolume
clusterroles rbac.authorization.k8s.io/v1 false ClusterRoleCommon examples:
| Scope | Examples |
|---|---|
| Namespaced | Pods, Deployments, Services, ConfigMaps, Secrets |
| Cluster-scoped | Nodes, Namespaces, PersistentVolumes, ClusterRoles |
kubectl get nodes -n development does not make Nodes namespaced. kubectl ignores -n for cluster-scoped kinds because those objects are not stored inside a namespace.
Create Kubernetes Namespaces
Namespace names must be valid DNS labels: lowercase letters, numbers, and hyphens, starting and ending with an alphanumeric character, at most 63 characters long.
Create namespaces imperatively:
kubectl create namespace developmentkubectl create namespace testingSample output:
namespace/development creatednamespace/testing createdAn invalid name fails validation:
kubectl create namespace Team_DevelopmentSample output (trimmed):
The Namespace "Team_Development" is invalid: metadata.name: Invalid value: "Team_Development": a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-'Create one declaratively. Save this as namespace-staging.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: stagingApply and verify:
kubectl apply -f namespace-staging.yamlSample output:
namespace/staging createdkubectl get namespacesSample output (trimmed):
NAME STATUS AGE
default Active 163m
development Active 1s
kube-node-lease Active 163m
kube-public Active 163m
kube-system Active 163m
staging Active 0s
testing Active 0sFor namespaced manifests, metadata.namespace stores the destination in the YAML. The -n option selects a namespace for commands where the manifest does not already declare one. Avoid supplying conflicting namespaces in the manifest and on the command line.
Example manifest fragment:
metadata:
name: web
namespace: developmentCreate and View Resources in a Namespace
Create a Deployment in development:
kubectl create deployment web --image=nginx --namespace=developmentSample output:
deployment.apps/web createdCreate the same Deployment name in testing:
kubectl create deployment web --image=nginx --namespace=testingSample output:
deployment.apps/web createdList namespaced resources in one namespace:
kubectl get pods -n developmentkubectl get all -n developmentSample output from kubectl get all -n development (trimmed):
NAME READY STATUS RESTARTS AGE
pod/web-65d846d465-dmm47 1/1 Running 0 18s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 1/1 1 1 18s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-65d846d465 1 1 1 18sNo Service appears yet because kubectl create deployment creates the Deployment object. The Deployment controller then creates a ReplicaSet, which creates the Pod. A Service is not created automatically. You create the Service later in the cross-namespace DNS example.
List Pods across every namespace:
kubectl get pods --all-namespacesThe short form -A is equivalent:
kubectl get pods -ASample output (trimmed):
NAMESPACE NAME READY STATUS RESTARTS AGE
development web-65d846d465-dmm47 1/1 Running 0 2m
kube-system coredns-668d6bf9bc-bwcg7 1/1 Running 0 163m
testing web-65d846d465-ftxhw 1/1 Running 0 1mThe NAMESPACE column confirms which scope each Pod belongs to even when the workload name is identical.
If kubectl get pods returns No resources found while kubectl get pods -A shows your workload, kubectl is probably querying a different namespace from the one containing the workload.
Set the Default Namespace for kubectl
Check the active context:
kubectl config current-contextSample output:
kubernetes-admin@kubernetesInspect contexts and namespace defaults:
kubectl config get-contextsSample output (trimmed):
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-adminThe empty NAMESPACE column means the context does not store a namespace, so kubectl uses default when you omit -n.
Set the default namespace on the current context:
kubectl config set-context --current --namespace=developmentSample output:
Context "kubernetes-admin@kubernetes" modified.The context name differs between clusters. The change updates your local kubeconfig only.
Verify:
kubectl config view --minify -o jsonpath='{.contexts[0].context.namespace}{"\n"}'Sample output:
developmentA blank result means the context does not store a namespace, so kubectl uses default when you omit -n.
Now list Pods without -n:
kubectl get podsSample output (trimmed):
NAME READY STATUS RESTARTS AGE
web-65d846d465-dmm47 1/1 Running 0 4mReturn to the default namespace:
kubectl config set-context --current --namespace=defaultThis explicitly sets default as the namespace for the current context. It is sufficient when you want commands without -n to query the default namespace again.
For renaming contexts, switching clusters, and managing multiple kubeconfig files, use Install kubectl and configure kubeconfig.
Create Namespace-Specific kubectl Contexts
You can define separate contexts that point at the same cluster and user but different default namespaces. That lets you kubectl config use-context instead of passing -n repeatedly.
Capture the original context and build descriptive names for the namespace-specific contexts:
ORIGINAL_CONTEXT=$(kubectl config current-context)DEV_CONTEXT="${ORIGINAL_CONTEXT}-development"TEST_CONTEXT="${ORIGINAL_CONTEXT}-testing"Capture the cluster and user from your current context:
CLUSTER_NAME=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.cluster}')USER_NAME=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.user}')Verify the values before creating contexts:
printf 'Cluster: %s\nUser: %s\n' "$CLUSTER_NAME" "$USER_NAME"Sample output:
Cluster: kubernetes
User: kubernetes-adminOn Minikube, kind, EKS, AKS, GKE, or OpenShift clusters these values differ.
Create a context for development:
kubectl config set-context "$DEV_CONTEXT" --cluster="$CLUSTER_NAME" --user="$USER_NAME" --namespace=developmentSample output:
Context "kubernetes-admin@kubernetes-development" created.Create one for testing:
kubectl config set-context "$TEST_CONTEXT" --cluster="$CLUSTER_NAME" --user="$USER_NAME" --namespace=testingSample output:
Context "kubernetes-admin@kubernetes-testing" created.Switch contexts:
kubectl config use-context "$DEV_CONTEXT"Sample output:
Switched to context "kubernetes-admin@kubernetes-development".kubectl get podsSample output (trimmed):
NAME READY STATUS RESTARTS AGE
web-65d846d465-dmm47 1/1 Running 0 6mkubectl config use-context "$TEST_CONTEXT"Sample output:
Switched to context "kubernetes-admin@kubernetes-testing".kubectl get podsSample output (trimmed):
NAME READY STATUS RESTARTS AGE
web-65d846d465-ftxhw 1/1 Running 0 3mThe command omitted -n, but kubectl queried testing because that namespace is stored in the active context. These contexts reuse the same cluster and credentials while changing only the default namespace.
Access Services Across Namespaces
In a cluster with working Kubernetes DNS, a Pod can address a Service in another namespace with:
<service-name>.<namespace-name>
<service-name>.<namespace-name>.svc.<cluster-domain>Most clusters use cluster.local as the cluster domain, producing a full name such as web.testing.svc.cluster.local. Cluster administrators can configure a different domain, so the short web.testing form is usually better for this example.
Expose the existing web Deployment in testing:
kubectl expose deployment web --port=80 --namespace=testingSample output:
service/web exposedRun a temporary curl Pod in development. Cross-namespace Service checks use the curl command against the fully qualified Service DNS name:
kubectl run curl-dev --image=curlimages/curl --restart=Never --namespace=development --command -- sleep 3600Sample output:
pod/curl-dev createdWait until the curl Pod is ready:
kubectl wait --for=condition=Ready pod/curl-dev -n development --timeout=60sSample output:
pod/curl-dev condition metQuery the Service in testing by short DNS name:
kubectl exec -n development curl-dev -- curl -s -o /dev/null -w '%{http_code}\n' http://web.testingWhen DNS and the backend Pod are healthy, the command prints 200. That confirms cross-namespace service discovery from development to testing. Namespace boundaries do not automatically block that traffic. Restricting east-west traffic requires NetworkPolicy or other controls outside this article.
Delete Resources and Namespaces
Before you delete the practice namespaces, restore your original context and remove the temporary contexts from the demonstration:
kubectl config use-context "$ORIGINAL_CONTEXT"Sample output:
Switched to context "kubernetes-admin@kubernetes".kubectl config delete-context "$DEV_CONTEXT"kubectl config delete-context "$TEST_CONTEXT"Sample output:
deleted context kubernetes-admin@kubernetes-development from /root/.kube/config
deleted context kubernetes-admin@kubernetes-testing from /root/.kube/configThe path in the output varies by user and KUBECONFIG setting.
Delete a single namespaced object:
kubectl delete deployment web -n developmentDelete resources included in kubectl's all category while keeping the namespace:
kubectl delete all --all -n testingall category does not mean every namespaced resource. It commonly covers workload controllers, Pods, and Services, but it does not include resources such as Secrets, ConfigMaps, PVCs, ServiceAccounts, Ingresses, or custom resources. Run kubectl api-resources --namespaced=true when you need to inspect the types that may exist.
Delete an entire namespace:
kubectl delete namespace stagingSample output:
namespace "staging" deletedDeleting a namespace removes namespaced resources inside it. The API server rejects new objects in that namespace while termination runs.
If a namespace stays in Terminating for a long time, finalizers or unavailable API resources are usually involved. Use a separate namespace-termination troubleshooting workflow before editing finalizers manually.
Common Namespace and Context Mistakes
| Symptom | Likely cause | Fix |
|---|---|---|
Error from server (NotFound): pods "app" not found |
kubectl is querying the wrong namespace | kubectl get pods -A, or set -n, or fix the context default |
kubectl get pods shows nothing after a colleague created workloads |
Context default still default |
kubectl config set-context --current --namespace=<ns> |
Commands hit the wrong cluster after use-context |
Context selects cluster and user, not only namespace | Confirm with kubectl config current-context and cluster-info |
sudo kubectl behaves differently from your user |
root has a separate $HOME/.kube/config |
Run kubectl as the user that owns the kubeconfig |
kubectl get nodes -n app seems to filter nodes |
Nodes are cluster-scoped | Drop -n for node operations |
Pods in team-a reach Pods in team-b unexpectedly |
Namespaces are not network firewalls | Plan NetworkPolicy or service mesh rules separately |
| Resources reappear after deletion | An operator, GitOps controller, Helm release, or another reconciler recreates them | Pause or update the managing source before deleting the generated resources |
Attempt to change metadata.namespace is rejected |
An existing object's namespace is immutable | Export or recreate the object in the destination namespace, then delete the original |
Namespace stuck in Terminating |
Finalizers or API discovery issues | Use a dedicated troubleshooting workflow; avoid blind finalizer edits |
Practice Exercise
Try this sequence on a lab cluster:
-
Create
developmentandtestingnamespaces. -
Deploy
webwith imagenginxin both namespaces. -
List the Deployments, ReplicaSets, and Pods in each namespace and confirm that Kubernetes created independent objects in both namespaces:
bashkubectl get deployments,replicasets,pods -n development kubectl get deployments,replicasets,pods -n testing -
Set
developmentas the default namespace on your current context and runkubectl get podswithout-n. -
Create suffixed contexts from your original context name that share your cluster and user but set different namespace defaults; switch with
kubectl config use-context. -
Expose
webintestingand curlhttp://web.testingfrom a Pod indevelopment. -
Switch back to the original context, remove the two practice contexts, delete the temporary curl Pod if you created one, delete practice Deployments, and then delete
developmentandtesting.
References
- Namespaces — Kubernetes documentation
- Organizing Cluster Access Using kubeconfig Files — contexts and default namespaces
- DNS for Services and Pods — cross-namespace service names
Summary
Kubernetes namespaces group namespaced objects inside one cluster. Use kubectl create namespace, YAML, -n, and -A to work with them, and set a default namespace on your kubectl context when you run many commands in the same scope. Contexts can remember that default without replacing full kubeconfig management. Namespaces organize resources, but they do not automatically control network traffic, API permissions, or resource consumption. Use NetworkPolicy, RBAC, and ResourceQuota for those separate purposes.

