Kubernetes Namespaces: Create, Switch, and Manage with kubectl

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.

text
development
└── deployment/web

testing
└── deployment/web

Although 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:

bash
kubectl get namespaces

Sample output:

output
NAME              STATUS   AGE
default           Active   163m
kube-node-lease   Active   163m
kube-public       Active   163m
kube-system       Active   163m

Brief roles:

  • default — used for namespaced objects when no other namespace is selected
  • kube-system — contains Kubernetes system objects and many cluster add-ons, commonly including CoreDNS
  • kube-public — intended for publicly readable cluster information; it is normally readable by all clients, including unauthenticated clients when cluster authorization permits the standard behavior
  • kube-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:

bash
kubectl api-resources --namespaced=true

Sample output (trimmed):

output
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         Deployment

List cluster-scoped resources:

bash
kubectl api-resources --namespaced=false

Sample output (trimmed):

output
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        ClusterRole

Common 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:

bash
kubectl create namespace development
bash
kubectl create namespace testing

Sample output:

output
namespace/development created
output
namespace/testing created

An invalid name fails validation:

bash
kubectl create namespace Team_Development

Sample output (trimmed):

output
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:

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: staging

Apply and verify:

bash
kubectl apply -f namespace-staging.yaml

Sample output:

output
namespace/staging created
bash
kubectl get namespaces

Sample output (trimmed):

output
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   0s

For 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:

yaml
metadata:
  name: web
  namespace: development

Create and View Resources in a Namespace

Create a Deployment in development:

bash
kubectl create deployment web --image=nginx --namespace=development

Sample output:

output
deployment.apps/web created

Create the same Deployment name in testing:

bash
kubectl create deployment web --image=nginx --namespace=testing

Sample output:

output
deployment.apps/web created

List namespaced resources in one namespace:

bash
kubectl get pods -n development
bash
kubectl get all -n development

Sample output from kubectl get all -n development (trimmed):

output
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       18s

No 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:

bash
kubectl get pods --all-namespaces

The short form -A is equivalent:

bash
kubectl get pods -A

Sample output (trimmed):

output
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          1m

The 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:

bash
kubectl config current-context

Sample output:

output
kubernetes-admin@kubernetes

Inspect contexts and namespace defaults:

bash
kubectl config get-contexts

Sample output (trimmed):

output
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin

The 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:

bash
kubectl config set-context --current --namespace=development

Sample output:

output
Context "kubernetes-admin@kubernetes" modified.

The context name differs between clusters. The change updates your local kubeconfig only.

Verify:

bash
kubectl config view --minify -o jsonpath='{.contexts[0].context.namespace}{"\n"}'

Sample output:

output
development

A blank result means the context does not store a namespace, so kubectl uses default when you omit -n.

Now list Pods without -n:

bash
kubectl get pods

Sample output (trimmed):

output
NAME                   READY   STATUS    RESTARTS   AGE
web-65d846d465-dmm47   1/1     Running   0          4m

Return to the default namespace:

bash
kubectl config set-context --current --namespace=default

This 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:

bash
ORIGINAL_CONTEXT=$(kubectl config current-context)
bash
DEV_CONTEXT="${ORIGINAL_CONTEXT}-development"
bash
TEST_CONTEXT="${ORIGINAL_CONTEXT}-testing"

Capture the cluster and user from your current context:

bash
CLUSTER_NAME=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.cluster}')
bash
USER_NAME=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.user}')

Verify the values before creating contexts:

bash
printf 'Cluster: %s\nUser: %s\n' "$CLUSTER_NAME" "$USER_NAME"

Sample output:

output
Cluster: kubernetes
User: kubernetes-admin

On Minikube, kind, EKS, AKS, GKE, or OpenShift clusters these values differ.

Create a context for development:

bash
kubectl config set-context "$DEV_CONTEXT" --cluster="$CLUSTER_NAME" --user="$USER_NAME" --namespace=development

Sample output:

output
Context "kubernetes-admin@kubernetes-development" created.

Create one for testing:

bash
kubectl config set-context "$TEST_CONTEXT" --cluster="$CLUSTER_NAME" --user="$USER_NAME" --namespace=testing

Sample output:

output
Context "kubernetes-admin@kubernetes-testing" created.

Switch contexts:

bash
kubectl config use-context "$DEV_CONTEXT"

Sample output:

output
Switched to context "kubernetes-admin@kubernetes-development".
bash
kubectl get pods

Sample output (trimmed):

output
NAME                   READY   STATUS    RESTARTS   AGE
web-65d846d465-dmm47   1/1     Running   0          6m
bash
kubectl config use-context "$TEST_CONTEXT"

Sample output:

output
Switched to context "kubernetes-admin@kubernetes-testing".
bash
kubectl get pods

Sample output (trimmed):

output
NAME                   READY   STATUS    RESTARTS   AGE
web-65d846d465-ftxhw   1/1     Running   0          3m

The 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:

text
<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:

bash
kubectl expose deployment web --port=80 --namespace=testing

Sample output:

output
service/web exposed

Run a temporary curl Pod in development. Cross-namespace Service checks use the curl command against the fully qualified Service DNS name:

bash
kubectl run curl-dev --image=curlimages/curl --restart=Never --namespace=development --command -- sleep 3600

Sample output:

output
pod/curl-dev created

Wait until the curl Pod is ready:

bash
kubectl wait --for=condition=Ready pod/curl-dev -n development --timeout=60s

Sample output:

output
pod/curl-dev condition met

Query the Service in testing by short DNS name:

bash
kubectl exec -n development curl-dev -- curl -s -o /dev/null -w '%{http_code}\n' http://web.testing

When 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:

bash
kubectl config use-context "$ORIGINAL_CONTEXT"

Sample output:

output
Switched to context "kubernetes-admin@kubernetes".
bash
kubectl config delete-context "$DEV_CONTEXT"
bash
kubectl config delete-context "$TEST_CONTEXT"

Sample output:

output
deleted context kubernetes-admin@kubernetes-development from /root/.kube/config
deleted context kubernetes-admin@kubernetes-testing from /root/.kube/config

The path in the output varies by user and KUBECONFIG setting.

Delete a single namespaced object:

bash
kubectl delete deployment web -n development

Delete resources included in kubectl's all category while keeping the namespace:

bash
kubectl delete all --all -n testing
NOTE
The all 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:

bash
kubectl delete namespace staging

Sample output:

output
namespace "staging" deleted

Deleting 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:

  1. Create development and testing namespaces.

  2. Deploy web with image nginx in both namespaces.

  3. List the Deployments, ReplicaSets, and Pods in each namespace and confirm that Kubernetes created independent objects in both namespaces:

    bash
    kubectl get deployments,replicasets,pods -n development
    kubectl get deployments,replicasets,pods -n testing
  4. Set development as the default namespace on your current context and run kubectl get pods without -n.

  5. 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.

  6. Expose web in testing and curl http://web.testing from a Pod in development.

  7. 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 development and testing.


References


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.

Frequently Asked Questions

1. What is the difference between a kubectl context and a namespace?

A context selects cluster, user credentials, and an optional default namespace. A namespace is a Kubernetes API object that scopes namespaced resources inside one cluster. Changing context can change cluster and user; setting --namespace on a context only changes the default namespace kubectl uses when you omit -n.

2. Why does kubectl say a Pod was not found when I know it exists?

kubectl queries the namespace from your current context default or from -n. A Pod in development is invisible to kubectl get pods without -n development when your context still points at default. Use kubectl get pods -A or set the context default namespace.

3. Does a namespace provide network or security isolation by itself?

No. Namespaces organize objects and DNS names, but they do not automatically block network traffic or restrict API access. NetworkPolicy controls traffic, RBAC controls API permissions, ResourceQuota limits resource consumption, and admission policies enforce rules when objects are created or updated.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)