Sign in
← Kubernetes: basics
7 min · easy · Lesson 9 of 11

Namespace: resource isolation

How a cluster is split into areas, which resources fall outside them, and the rules kubectl uses to pick a namespace.

How a cluster is split into areas, which resources fall outside them, and what rules kubectl follows to pick a namespace. The lesson on your first Pod helps here.

Why you need a namespace

A namespace is an area inside a cluster that isolates resources from each other. Inside one namespace, names of resources of the same type are unique.

Different teams, environments, and projects share one cluster. Without namespaces their names would collide fast. Team A has its own Service api, team B also has api: without a boundary that's a conflict. A Service is an object that gives a permanent address to a group of Pods. A namespace is the boundary inside which team A's api doesn't get in the way of team B's api.

Other settings attach to a namespace too. RBAC sets who can do what inside it. You can cap a team's total CPU and memory (ResourceQuota) and the traffic allowed between Pods (NetworkPolicy); separate lessons cover those.

In production, a namespace is a unit of administration: its own team, its own permissions, its own limits.

What lives in a namespace, and what doesn't

Not every resource lives inside a namespace.

Inside a namespace (namespaced): Pod, Deployment, Service, ConfigMap, Secret, Role, Job.

Outside a namespace, at the whole-cluster level (cluster-scoped): Node, Namespace, PersistentVolume, ClusterRole, StorageClass.

NamespacedCluster-scoped
Pod, Deployment, ServiceNode, Namespace
ConfigMap, SecretPersistentVolume, StorageClass
Role, JobClusterRole

You can check which group a resource belongs to:

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

A Node is a cluster machine; it belongs to the whole cluster, so it sits outside any namespace. A Pod runs on a node, but it's tied to a namespace.

Standard namespaces

A fresh cluster already ships with a few namespaces.

Local-cluster tools add their own. kind, for example, also adds local-path-storage:

kubectl get ns
NAME                 STATUS   AGE
default              Active   97s
kube-node-lease      Active   94s
kube-public          Active   99s
kube-system          Active   100s
local-path-storage   Active   46s

How to create a namespace

Imperatively, with one command:

kubectl create ns team-a

ns is short for namespace.

Declaratively, with a manifest:

apiVersion: v1
kind: Namespace
metadata:
  name: team-a

You can also name the namespace right in a resource's manifest:

apiVersion: v1
kind: Pod
metadata:
  name: pinger
  namespace: team-a
spec:
  containers:
    - name: pinger
      image: busybox:1.36.1
      command: ["sleep", "3600"]

If the namespace doesn't exist yet, apply fails:

Error from server (NotFound): error when creating "pod.yaml": namespaces "team-a" not found

That's why you create the namespace first, then put resources into it.

The -n flag

By default kubectl works in the namespace from the current context (usually default). To reach a different namespace, add the -n flag:

kubectl get pod -n team-a
kubectl apply -f pod.yaml -n team-a
kubectl logs pinger -n team-a

The -A flag (or --all-namespaces) shows resources from every namespace at once:

kubectl get pod -A

To change the default namespace for the current context:

kubectl config set-context --current --namespace=team-a

After that, kubectl get pod with no flags looks inside team-a. The command only changes the kubeconfig file; the cluster knows nothing about it. To see which namespace is selected right now:

kubectl config view --minify -o jsonpath='{..namespace}'

Empty output means default.

Reaching across namespaces

namespace team-a namespace team-b Pod client in team-b api Service api team B api.team-a.svc.cluster.local Service api team A
The name api is taken in both namespaces; only the full address saves you from outside.

Every Service gets a DNS name of this shape:

<service>.<namespace>.svc.cluster.local

From a Pod in your own namespace, you can reach a Service by its short name: api. From another namespace you need the address with the namespace: api.team-a.svc.cluster.local or shorter, api.team-a.

You can see why in any Pod's /etc/resolv.conf. Here's a Pod from team-b:

kubectl exec -n team-b deploy/api -- cat /etc/resolv.conf
search team-b.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

The search line lists the domains the DNS client appends to a short name. Your own namespace's domain comes first. That's why api from team-b turns into api.team-b.svc.cluster.local, while api.team-a turns into api.team-a.svc.cluster.local.

For example, a Pod in team-b calls team A's Service api:

curl http://api.team-a.svc.cluster.local:8080/health

The busybox image has no curl; there, the same thing is wget -qO- http://api.team-a.svc.cluster.local:8080.

Which namespace kubectl picks

When kubectl creates or looks up a resource, it picks a namespace this way.

  1. If the manifest has metadata.namespace, it uses that.
  2. Otherwise, if the -n flag is set, it uses that.
  3. Otherwise it uses the namespace from the current context.
  4. Otherwise default.

A conflict is a separate case. If the manifest has namespace: team-a written in it, but the command runs as kubectl apply -f pod.yaml -n team-b, kubectl doesn't silently pick one of the two. It returns an error and creates nothing:

error: the namespace from the provided object "team-a" does not match the namespace "team-b". You must pass '--namespace=team-a' to perform this operation.

If -n matches the manifest, there's no error. The rule is simple: set the namespace either in the manifest or with the flag, never different ones in both places. One manifest without metadata.namespace can be applied into several namespaces with the -n flag.

Deleting a namespace

kubectl delete ns team-a deletes everything inside it. That's handy for cleaning up a learning cluster and dangerous in production. The deletion is asynchronous: the namespace moves into the Terminating phase and waits for all its resources to free up.

NAME     STATUS        AGE
team-a   Terminating   9s

If it gets stuck, the usual cause is a finalizer on some resource. A finalizer is a marker on an object that blocks deletion until cleanup finishes.

Common mistakes

What you'll need for the tasks

The tasks live in the labs/ folder: each lab brings up its own kind cluster on your machine, with instructions in its README.md.

Homework

Practice the theory on your own cluster: 2 steps with a check. Set up the cluster with the Kubernetes locally track, the tasks live in the k8s-practice repository.

./run.sh start k8s-namespace     # set up the starting state
./run.sh verify k8s-namespace    # check the current step

In short

Done reading?

Mark the lesson as read to move your track progress forward.

Go through it with an AI agent

The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.

Get access for $49

Tell the agent: use MCP izi, give me lesson k8s-basics/namespace