Blog · June 24, 2025 · Updated on September 7, 2026 · 11 min read

Kubernetes Namespaces Done Right

Overhead view of a warehouse, two workers organizing boxes between tall rows of shelving
Photo: Tiger Lily / Pexels

A Kubernetes namespace is a logically separated area inside a cluster. Names have to be unique within a namespace but not across namespaces, and permissions, resource quotas and network rules attach to the namespace. That makes namespaces the tool for splitting one cluster between applications and teams without running a separate cluster for each of them.

What a namespace is not: a security boundary on its own. Without RBAC, network policies and quotas, a namespace is just a folder with a name. Those three building blocks turn the folder into a protected area, and that is what this post is about.

I run Kubernetes clusters in production and wrote the Kubernetes Practical Guide for Rheinwerk (2024). The namespace rules here are the ones I apply in my own clusters, including the failure modes I have come across in my own operations and in client projects. All my Kubernetes posts are collected on the Kubernetes page.

What a Kubernetes namespace separates, and what it doesn't

Picture the cluster as a large warehouse. The namespace is a fenced-off shelving zone: each team has its own, with its own key, its own allotted space and its own rules. Still, all zones stand in the same hall, on the same floor, with the same forklift lanes. Translated to Kubernetes: Pods from different namespaces run on the same nodes, share the same kernel and the same cluster network.

Out of the box a namespace does three things. It scopes names, so two teams can both run a Deployment called api without getting in each other's way. It is the unit you grant permissions at, because a Role and a RoleBinding always apply to exactly one namespace. And it is the unit Kubernetes counts and caps resources at, through ResourceQuota and LimitRange.

What it doesn't do: a namespace isolates neither network nor compute. A Pod in the shop namespace can reach every Pod in billing by default, and a Pod without limits can starve the node for every other namespace. You have to shut both down explicitly; more on that below.

It also matters that not every object lives in a namespace. Pods, Deployments, Services, ConfigMaps, Secrets, Ingresses and PersistentVolumeClaims are namespaced. Nodes, PersistentVolumes, StorageClasses, ClusterRoles and the namespaces themselves are cluster-wide. kubectl tells you which is which:

kubectl api-resources --namespaced=true
kubectl api-resources --namespaced=false

That distinction explains a trap newcomers run into regularly: a PersistentVolume belongs to no namespace; only the PersistentVolumeClaim binds it to one. If you go looking for volumes "in the namespace", you are looking in the wrong place.

The four namespaces every cluster ships with

A freshly installed cluster starts with four namespaces you don't have to create and shouldn't delete.

Namespace Purpose Should you use it?
default landing zone for everything created without a namespace only for quick tests
kube-system components Kubernetes runs itself (DNS, proxy, controllers) no, read only
kube-public readable by all clients, holds cluster information such as the cluster-info ConfigMap no
kube-node-lease Lease objects the kubelet uses for its heartbeats no

The kube- prefix is reserved for system namespaces, so your own namespaces never start with it. And the default namespace is trap number one: every command without -n lands there. In shared clusters it fills up over a few months with test Deployments from five people, none of whom remember starting them. In my production clusters default stays empty; if you want to enforce that, an admission rule such as a Gatekeeper constraint does the job.

Slicing namespaces: by application, team or environment?

The most common question in my projects is not "what is a namespace" but "how many do we need and what do we slice them by". There are three common patterns, and each of them is right in some situations.

Pattern Example Fits when Weakness
per application or component shop, shop-search, billing several applications share one cluster many small namespaces with microservices
per team team-payments, team-frontend teams operate their own services permissions and quotas get coarse
per environment dev, staging, prod one small cluster for everything production shares nodes with experiments

My rule of thumb for the cut comes from the book and hasn't changed since. I ask three questions: do the applications belong to one larger, coherent component? Do they need each other to work? Are they rolled out and rolled back together? Three times yes means one shared namespace. A single no is enough to separate them.

In my clusters it looks like this: every business application gets its own namespace, and platform tools such as ArgoCD, cert-manager, Prometheus and Falco each get one as well. Environments, on the other hand, I separate by cluster, not by namespace. A staging cluster that mirrors production is worth more to me than a staging namespace that shares nodes, ingress controller and kernel with production. For a one-person cluster or a pure test system that is overkill; there, dev and prod as namespaces are perfectly fine.

What I no longer do: namespaces for slightly different variants of the same application, such as shop-v1 and shop-v2. That is what labels are for. Namespaces are meant for things that need separate permissions, separate quotas or separate network rules. Everything else is a label case.

Creating a namespace and working with it in kubectl

A namespace is a simple object, and like everything in Kubernetes you should keep it as YAML in Git rather than creating it by hand with kubectl create namespace. The reason: the namespace is where quotas, roles and network rules will hang later, and you want those versioned together with it. In my setup ArgoCD creates the namespaces; the manifest sits next to the quota and the RoleBinding in the same folder.

apiVersion: v1
kind: Namespace
metadata:
  name: shop
  labels:
    team: commerce
    environment: production

The labels on the namespace are more than decoration. Network policies and admission rules select namespaces by label, and Kubernetes automatically sets the label kubernetes.io/metadata.name to the namespace's name, so you can select a specific namespace even without labels of your own.

Day to day you work with three options. -n shop addresses one namespace, -A shows a resource across all namespaces, and kubectl config set-context --current --namespace=shop makes a namespace the default for every following command:

kubectl get pods -n shop
kubectl get pods -A
kubectl config set-context --current --namespace=shop

Switching via set-context gets tedious fast when you move between several namespaces and clusters every day; kubens and kubectx take that off your hands. The rest of the everyday commands are collected in kubectl Commands: The Essentials.

One point that is easy to miss is DNS. A Service api in the shop namespace is simply reachable as api from inside shop. From another namespace you need the long name api.shop.svc.cluster.local, or at least api.shop. So when an application can no longer find its database after moving into its own namespace, that is almost always the reason.

Limiting resources per namespace: ResourceQuota and LimitRange

A shared cluster without quotas works right up until someone rolls out a Deployment with twenty replicas and no limits. Kubernetes ships two objects for this, both of which act per namespace. A ResourceQuota caps the total a namespace may request. A LimitRange sets bounds and defaults for individual containers.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: shop-quota
  namespace: shop
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "50"
    persistentvolumeclaims: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: shop-defaults
  namespace: shop
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      default:
        cpu: 500m
        memory: 512Mi
      max:
        cpu: "2"
        memory: 4Gi

The quota says: all Pods in shop together may request at most 4 CPU and 8 GiB, set at most 8 CPU and 16 GiB as limits, and there may be no more than 50 Pods and 10 volume claims. The LimitRange makes sure a container without its own values starts with a request of 100 millicores and 128 MiB and is capped at 500 millicores and 512 MiB; nobody may ask for more than 2 CPU or 4 GiB for a single container.

The two belong together, and this is where it most often goes wrong in practice. As soon as a ResourceQuota constrains requests.cpu or requests.memory, the API server rejects every Pod that doesn't set those values. Without a LimitRange, every Helm chart that ships without requests then fails, and the error must specify requests.cpu only shows up in the ReplicaSet's events, not on the Deployment. The That the LimitRange fills in the missing values before the quota check runs is not a coincidence but the order of the admission pass: Kubernetes runs the mutating plugins first and only then the validating ones, which include ResourceQuota (admission controller reference). Together they produce a namespace that doesn't starve the others. Which values make sense for requests and limits is covered in Kubernetes Requests and Limits Explained.

kubectl describe quota -n shop shows you at any time how much of the budget is used. That doubles as an early warning: a namespace that sits at 90 percent of its quota permanently needs either a bigger budget or a cleanup.

Isolation between namespaces: permissions and network

The term namespace isolation misleads you if you take it literally. A namespace only isolates once you add two things: permissions and network rules.

Permissions run through RBAC. A Role describes what is allowed inside a namespace, and a RoleBinding hands that Role to a user, a group or a ServiceAccount. A development team gets edit in its namespace and nothing else, and an application's ServiceAccount may only read the Secrets it needs. ClusterRoleBindings, by contrast, you hand out only to administrators and platform components, because those apply across all namespaces. How roles, verbs and bindings fit together is explained in Kubernetes RBAC: Roles and Permissions.

Network runs through NetworkPolicies. By default every Pod may talk to every other Pod, namespace or not. My pattern for every application namespace is a default-deny policy for incoming traffic plus targeted allowances: from the ingress controller to the frontend, from the frontend to the API, from the API to the database. The namespace selector in a NetworkPolicy uses exactly the labels you set on the namespace above. The details with examples are in Kubernetes Network Policy Explained.

What neither of them isolates: the kernel. Pods from different namespaces run on the same nodes, and whoever breaks out of a container lands on the node, not in the namespace. If two tenants genuinely must not trust each other, separate node pools with taints, or separate clusters altogether, are the honest answer. For teams within one company, in my experience the combination of RBAC, NetworkPolicy, quota and pod security rules is almost always enough.

Frequently asked questions

How many namespaces should a cluster have?

As many as there are units with their own permissions, quotas or network rules, and no more. For a cluster with three applications and four platform tools, seven namespaces is normal. Hundreds of namespaces are technically no problem, but each one needs a quota, a RoleBinding and a network policy, otherwise it is just a name. If you don't have a template for that in Git, create fewer namespaces.

Can a Service be reached across namespaces?

Yes, via the full DNS name service.namespace.svc.cluster.local; often service.namespace is enough. Whether the connection then actually succeeds is decided by the NetworkPolicies in the target namespace. Without policies everything goes through; with default-deny only what you allowed.

What happens when I delete a namespace?

Kubernetes deletes everything inside it: Pods, Deployments, Services, Secrets, PersistentVolumeClaims. The namespace sits in the Terminating state for a while until all finalizers have run. If it gets stuck there, a custom resource whose controller is no longer running is usually the blocker. Before deleting a namespace, check the volumes: with Delete as the reclaim policy, the data is gone afterwards.

Are Kubernetes namespaces a security feature?

Only together with RBAC, NetworkPolicies and pod security rules. On its own a namespace separates names and nothing else. As tenant separation for customers who don't trust each other, the concept is not enough; that calls for separate nodes or clusters.

Can a Pod belong to several namespaces?

No. Every namespaced object belongs to exactly one namespace, and that cannot be changed after creation. If you want to move a Deployment to another namespace, you create it there and delete it in the old one.

Where to go from here

If you have an existing cluster, start with an inventory: kubectl get all -n default shows you what doesn't belong there. Then create a namespace with quota and LimitRange in Git for every application, give teams their permissions through RoleBindings and set a default-deny policy. In that order: structure first, then permissions, then network.

The three building blocks have their own posts: Kubernetes RBAC: Roles and Permissions for the access side, Kubernetes Requests and Limits Explained for the values in quota and LimitRange, and Kubernetes Network Policy Explained for the network side.

All of this, with every example, is in chapter 2 of my Kubernetes Practical Guide (Rheinwerk Computing), with permissions in chapter 7 and resource control in chapter 8.

Kevin Welter

Kevin Welter

Developer, IT architect, author of technical books (Kubernetes, cloud infrastructures) and speaker. Runs his business with an AI workforce of eight AI employees and shows solo business owners in his community how to hire their first AI employee.

More about AI employees

Kubernetes from the basics to a production-ready cluster

Get the book