On this page
Picture an office building shared by several companies. Each company has its own floor, its own reception desk and its own staff, yet they all share the same lifts, power and street address. Namespaces give a Kubernetes cluster the same kind of floors.
A namespace is a virtual partition inside one cluster. Pods, Deployments, Services and ConfigMaps all live in a namespace, and their names only have to be unique inside it. That is why you can run a Deployment called web-api in both a development and a production namespace without a clash.
Namespaces are also the boundary where you attach access rules (RBAC), resource quotas and network policies. They are the main tool for separating teams and environments on a shared cluster.
What you will learn
- Why namespaces exist and what the four built-in namespaces are for
- Which resources live inside a namespace and which belong to the whole cluster
- How to create namespaces and deploy workloads into them
- How Services in different namespaces find each other through DNS
- How to give a namespace a budget with a ResourceQuota
Why use namespaces?
For a hobby project with one developer and one environment, a single namespace is fine. Real teams usually need to:
- Separate environments (development, staging, production) on the same cluster
- Give each team its own isolated workspace
- Limit how much CPU, memory and storage a team can consume
- Apply different security policies per environment
- Organise hundreds of microservices so their names do not collide
Namespaces cover all of these without running a separate cluster for each team or environment.
The built-in namespaces
Every cluster starts with four namespaces. Know what each one is for before you create your own.
| Namespace | Purpose | Deploy your workloads here? |
|---|---|---|
default | Where resources go when you do not name a namespace | Only for quick demos, never in production |
kube-system | Components Kubernetes runs for itself, such as CoreDNS, kube-proxy and, on many clusters, the scheduler and controller manager | No, Kubernetes manages it |
kube-public | Data readable by everyone, even without authentication, such as the cluster-info ConfigMap | No |
kube-node-lease | Lease objects that act as node heartbeats, so the control plane notices failed nodes quickly | No |
List them on your own cluster:
Expected output (your ages will differ):
default for real workloads. Everything you create without naming a namespace lands there, so it quickly turns into a mix of unrelated things. Give each app or environment its own namespace, and leave kube-system to Kubernetes.Namespace-scoped and cluster-scoped resources
Not every resource lives in a namespace. Each kind is either namespace-scoped or cluster-scoped.
| Scope | Examples | Visible from |
|---|---|---|
| Namespace-scoped | Pods, Deployments, ReplicaSets, Services, ConfigMaps, Secrets, Jobs, CronJobs | Only the namespace it belongs to |
| Cluster-scoped | Nodes, PersistentVolumes, ClusterRoles, ClusterRoleBindings, and Namespaces themselves | The whole cluster, from every namespace |
Not sure about a kind? Ask the API server:
Creating a namespace
For a quick experiment, one command is enough:
In real projects, prefer a manifest that you keep in Git. Labels make the namespace easy to filter and to target with policies later. Save this as ecommerce-dev-namespace.yaml:
Save the production version as ecommerce-prod-namespace.yaml:
You will apply both in the hands-on section. Namespace names must be valid DNS labels: lowercase letters, digits and -, starting and ending with a letter or digit, at most 63 characters.
Putting workloads into a namespace
There are two ways to choose the namespace of a resource:
- Set
metadata.namespacein the manifest and runkubectl apply. The namespace is part of the definition and always explicit, so this is the recommended way for real workflows. - Pass
-n <namespace>(long form--namespace) tokubectl apply. This sets the namespace for manifests that do not declare one.
If you do neither, the resource goes to the default namespace of your current context, which is usually default.
namespace: ecommerce-dev and you run kubectl apply -n ecommerce-prod, kubectl refuses with an error saying the namespaces do not match. Use one or the other, not both with different values.The Deployment below runs two replicas of an ASP.NET Core API in the ecommerce-dev namespace. It uses Microsoft's ready-made sample image, which listens on port 8080, so you can test it without building your own. Save it as catalog-api-deployment.yaml:
Next, a ClusterIP Service exposes those Pods inside the cluster, in the same namespace. Save it as catalog-api-service.yaml:
Talking across namespaces with DNS
Inside one namespace, a Service is reachable by its short name, for example http://catalog-api. From a different namespace, you add the namespace to the name.
| Calling from | Name to use |
|---|---|
| The same namespace | catalog-api |
| Another namespace | catalog-api.ecommerce-dev |
| Anywhere (fully qualified) | catalog-api.ecommerce-dev.svc.cluster.local |
The general form is <service-name>.<namespace>.svc.cluster.local. For example, the order-api Service in the production namespace is reachable at http://order-api.production.svc.cluster.local from any other namespace.
Giving a namespace a budget
Once each team has its own namespace, you can cap what it may use. A ResourceQuota limits the total CPU, memory and number of objects in a namespace. A LimitRange sets default, minimum and maximum requests and limits for each container, so one runaway container cannot starve the others. The next lesson covers both in depth. Here is a first quota.
Save it as ecommerce-dev-quota.yaml:
All Pods in ecommerce-dev together may request at most 2 CPU cores and 2Gi of memory, and set limits up to 4 cores and 4Gi. The namespace may hold at most 20 Pods and 10 Services.
Because this quota covers CPU and memory, every new Pod in the namespace must declare those requests and limits, or it is rejected. The catalog-api Deployment already does.
Everyday namespace commands
| I want to… | Command |
|---|---|
| List all namespaces | kubectl get namespaces (short: kubectl get ns) |
| Create a namespace | kubectl create namespace <name> |
| See a namespace with its quotas and limit ranges | kubectl describe namespace <name> |
| List resources in one namespace | kubectl get pods -n <name> |
| List resources in every namespace | kubectl get pods -A |
| Change the default namespace of my context | kubectl config set-context --current --namespace=<name> |
| Check how much of a quota is used | kubectl describe resourcequota <quota> -n <name> |
| Delete a namespace and everything in it | kubectl delete namespace <name> |
Work in one namespace or in all of them
Add -n to scope any kubectl get command to one namespace, or -A (short for --all-namespaces) to see every namespace at once:
Stop typing -n on every command
Typing -n ecommerce-dev again and again gets old fast. Make it the default for your current context instead:
Every following kubectl command now targets ecommerce-dev until you change it. To check which namespace your context uses (empty output means default):
Inspect a namespace and its quota
Delete a namespace
Deleting a namespace deletes all resources inside it:
kubectl config current-context and kubectl get all -n <name> first, so you know exactly what you are deleting and on which cluster.Hands-on: development and production on one cluster
Your team runs a small e-commerce platform. You want the same application in a development environment, where developers experiment freely, and a production environment, where real customers shop. Both run on one cluster, kept apart by namespaces.
You need the five files from the sections above: the two namespace manifests, the Deployment, the Service and the quota.
Step 1 — Create the two namespaces
Verify that they exist:
Expected output (abbreviated):
Step 2 — Deploy the catalog API into development
Check that the Pods run in the right namespace:
Expected output (the name suffixes will differ):
Now confirm that the Pods are not visible from the production namespace:
Expected output:
Step 3 — Attach the quota to development
See the budget and how much of it is already used:
Expected output. The Used column already counts the two catalog-api Pods and their Service:
Step 4 — Make development your default namespace
You can now leave out -n ecommerce-dev. This lists the catalog-api Pods without any flag:
Step 5 — Call the API from another namespace
Start a short-lived busybox Pod in ecommerce-prod and fetch the catalog-api Service that lives in ecommerce-dev, using its full DNS name:
Read what it downloaded:
You should see the HTML of the sample app's home page. The full DNS name works from any namespace, while the short name catalog-api resolves only inside ecommerce-dev.
Step 6 — Clean up
Delete the debug Pod:
Point your context back at the default namespace:
When you are finished with the exercise, delete both namespaces. The Deployment, Service and quota go with them:
catalog-api Deployment to ecommerce-prod without renaming anything. The namespace keeps the two copies apart, and each one can get its own quota and access rules.Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
No resources found, but you know the Pod exists | You are looking in the wrong namespace | Add -n <namespace>, or use -A to find it |
kubectl apply -n fails with a namespace mismatch | The manifest's metadata.namespace differs from the flag | Remove the flag or fix the manifest |
| A Service cannot be reached from another namespace | You used the short name | Use <service>.<namespace> or the full .svc.cluster.local name |
| New Pods are rejected after you add a quota | The quota covers CPU and memory, but the Pod declares no requests or limits | Add requests and limits, or add a LimitRange with defaults (next lesson) |
Summary
Namespaces are virtual partitions inside a Kubernetes cluster that keep resource names apart. They are the foundation for multi-tenancy, environment separation and access control.
- Every cluster has four built-in namespaces:
default,kube-system,kube-publicandkube-node-lease. - Some resources are namespace-scoped (Pods, Services, ConfigMaps) and some are cluster-scoped (Nodes, PersistentVolumes, Namespaces).
- Declare the namespace in your manifests with
metadata.namespacefor predictable deployments. - Use
kubectl get <resource> -n <namespace>for one namespace, or-Afor all of them. - Set a default namespace per context with
kubectl config set-context --current --namespace=<ns>. - Reach Services in other namespaces with
<service>.<namespace>.svc.cluster.local. Namespaces do not block network traffic on their own. - Attach a
ResourceQuotato cap CPU, memory and object counts per namespace. - Deleting a namespace removes everything inside it, so double-check before you do it.
Next, you will give each namespace a proper budget with ResourceQuota and LimitRange.