Namespaces & Resource Isolation
A Kubernetes cluster is a single shared environment, but teams, projects, and environments need logical separation. Namespaces divide a cluster into virtual sub-clusters, giving each workload its own naming scope, resource budget, and access controls — all within the same physical infrastructure.
Based on kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/.
What Are Namespaces?
Namespaces are a mechanism for logically isolating groups of resources within a single cluster. They provide:
-
Name scoping — two teams can each deploy a service
named
apiwithout conflict, as long as they live in different namespaces. -
Access control boundaries — RBAC roles can be
scoped to a namespace, giving Team A full control of
team-awhile Team B cannot touch it. - Resource budgets — ResourceQuotas cap the total CPU, memory, and object count a namespace can consume.
Without Network Policies, pods in different namespaces can freely communicate. Without PodSecurity admission, a privileged pod in any namespace can escape to the host. Namespaces are an organisational tool; hard multi-tenancy requires additional controls.
Default Namespaces
A fresh cluster ships with four namespaces:
| Namespace | Purpose |
|---|---|
default |
Where resources land when you don't specify a namespace. Fine for exploration; avoid it for production workloads. |
kube-system |
Kubernetes control plane components: the API server, scheduler, controller manager, CoreDNS, kube-proxy, and cloud-controller. |
kube-public |
Readable by all users, including unauthenticated ones. Used for cluster-info and bootstrap tokens. |
kube-node-lease |
Stores Lease objects that the kubelet updates as heartbeats; allows the control plane to detect node failure efficiently. |
kube-system
Cluster add-ons (Ingress controllers, cert-manager, monitoring
agents) sometimes install into kube-system. Prefer
dedicated namespaces like ingress-nginx or
cert-manager so their resources are clearly separated
from core cluster components.
Scoped vs. Cluster-wide Resources
Not every Kubernetes resource lives inside a namespace. Resources fall into two categories:
| Namespace-scoped | Cluster-scoped |
|---|---|
| Pods, Deployments, Services | Nodes |
| ConfigMaps, Secrets | PersistentVolumes |
| ServiceAccounts, Roles, RoleBindings | ClusterRoles, ClusterRoleBindings |
| Ingresses, NetworkPolicies | StorageClasses, IngressClasses |
| ResourceQuotas, LimitRanges | CustomResourceDefinitions (CRDs) |
Check whether a resource is namespace-scoped with:
kubectl api-resources --namespaced=true # namespace-scoped resources
kubectl api-resources --namespaced=false # cluster-scoped resources
Working with Namespaces
Creating a namespace
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
env: production
Or imperatively:
kubectl create namespace team-alpha
Using a namespace in manifests
Set the namespace in the resource's metadata:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
namespace: team-alpha # explicit namespace
spec:
containers:
- name: app
image: nginx:1.27
Setting a default namespace for your kubectl session
Typing -n team-alpha on every command is tedious. Set a
permanent default for the current context:
# set default namespace for the current context
kubectl config set-context --current --namespace=team-alpha
# verify
kubectl config view --minify | grep namespace
DNS within and across namespaces
A Service named api in namespace
team-alpha is reachable:
| From | Address |
|---|---|
| Same namespace | api or api.team-alpha |
| Different namespace | api.team-alpha.svc.cluster.local |
Resource Quotas
A ResourceQuota caps the total resources (CPU, memory,
object counts) a namespace may consume. This prevents one team from
starving the rest of the cluster.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
services: "10"
Check quota usage:
kubectl describe resourcequota team-alpha-quota -n team-alpha
A companion object, LimitRange, sets default and maximum
CPU/memory per container in a namespace — useful when
developers forget to set resource requests:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-alpha
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "2"
memory: "2Gi"
When to Use Multiple Namespaces
A single default namespace is fine for a solo developer
experimenting on a laptop cluster. For anything else, plan namespace
boundaries around one or more of these axes:
| Strategy | Example namespaces | Best for |
|---|---|---|
| By environment |
dev, staging, prod
|
Separate environments in one cluster |
| By team |
team-frontend, team-backend,
team-data
|
Org-level isolation and chargeback |
| By application |
payments, auth,
notifications
|
Microservices with distinct lifecycle and ownership |
| By component tier |
monitoring, ingress-nginx,
cert-manager
|
Infrastructure add-ons separated from app workloads |
Deleting a namespace cascades to every resource inside it
— pods, services, secrets, configmaps, and more. There is no
recycle bin. Always double-check before running
kubectl delete namespace <name>.