CoursesKubernetes fundamentalsNamespaces: tidy rooms

Namespaces: tidy rooms

Dividing one cluster into spaces.

Beginner8 min · lesson 22 of 24
In plain terms
A namespace is an apartment inside a shared building: your “kitchen” and your neighbor’s don’t clash, and each apartment has its own rules and space.

A block of flats keeps a dozen families under one roof. One set of outside walls, one set of pipes, one front door onto the street. Inside, each family has its own flat, its own lock, and its own kitchen that nobody else has to scrub. One building, many separate homes.

A Kubernetes cluster is that building. A cluster means the pool of machines that Kubernetes runs your apps on, wired together and managed as one system. A namespace is one flat inside it: a named slice of the cluster that holds a group of objects and keeps them out of everyone else's way.

Why carve up one cluster

Nearly everything you have built so far already sits in a namespace, whether you chose one or not. A Pod lives in one, and a Pod is the smallest thing Kubernetes runs: one or more containers (apps packed up with everything they need to run) sharing a single network address. A Deployment lives in one too, the recipe that keeps a set of identical Pods alive. So does a Service, the steady address that forwards traffic to those Pods. ConfigMaps and Secrets, which hold settings and passwords, sit in a namespace as well. Skip the choice and Kubernetes makes it for you: everything lands in the namespace that ships with every cluster, called default.

The most obvious win is names. A name has to be unique inside a namespace and nowhere else. Team A can run a Deployment called web. Team B can run a web of their own. Neither one trips over the other, because the namespace is stitched into every object's full identity. That is what lets you cut one cluster into a dev section for half-finished work and a staging section for the dress rehearsal before real users show up, or hand each team a room of its own, without inventing a fresh name for every single thing.

There is a second reason teams reach for them. A room is a natural place to hang rules on. You can cap how much CPU and memory a team gets, so one hungry team cannot starve everybody else on the cluster. You can spell out who is allowed to do what inside that room, so the payments team never wipes the search team's work by accident. Draw those lines once, and every object created in that namespace picks them up automatically.

Making a room and living in it

kubectl is the command-line tool you talk to a cluster with. Creating a namespace is one line.

Terminal
kubectl create namespace team-a
Output
namespace/team-a created

You could staple -n team-a onto every command you type, where -n is short for namespace, and that gets tiring by about the fifth command. Set it as your default instead, and kubectl will assume it from here on.

Terminal
kubectl config set-context --current --namespace=team-a
Output
Context "kind-dev" modified.

Now a bare get pods reads from team-a and you never have to say the word.

Terminal
kubectl get pods
Output
NAME READY STATUS RESTARTS AGE
web-6f8c9d4b7f-2xkzr 1/1 Running 0 45s
web-6f8c9d4b7f-lm9qp 1/1 Running 0 45s

When you want to look somewhere else, -n <name> peeks into one other room and -A shows every room at once. That second flag saves you from the trap that catches nearly everybody. It goes like this. Your web Pods are running in team-a, but the context you are on still points at default. Maybe you logged into the cluster fresh, maybe you are on a teammate's machine, maybe nobody had set a default yet. You go looking for your Pods and find nothing.

Terminal
kubectl get pods
Output
No resources found in default namespace.

Your gut says the Pods crashed or never started. They are fine. They are sitting in team-a while this shell reads default, an empty room. -A settles the argument by listing every namespace side by side.

Terminal
kubectl get pods -A
Output
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-76f75df574-abcde 1/1 Running 0 2d
kube-system kube-proxy-9xk2l 1/1 Running 0 2d
team-a web-6f8c9d4b7f-2xkzr 1/1 Running 0 2m
team-b api-7d9f6c5b8d-qw4rt 1/1 Running 0 3m

There they are, over in team-a. Two ways out. Add -n team-a for a one-off command, or point your default context at team-a so plain commands read from it with no flag at all.

One-line commands are fine for a room you plan to throw away. Real setups live in files you can keep in git (the tool that records every change to your files), have reviewed by teammates, and run again next month. Here is the same namespace written as YAML, a plain-text format for spelling out what you want, this time carrying a quota that caps how much the room may take.

team-a.yaml
apiVersion: v1
kind: Namespace
metadata:
name: team-a
labels:
team: team-a
environment: dev
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
Terminal
kubectl apply -f team-a.yaml
Output
namespace/team-a configured
resourcequota/team-a-quota created

apply is not bothered that the namespace already exists. It compares the file against what is running, creates whatever is missing, and leaves the rest alone. So you can run the same file over and over and nothing bad happens, which is what you want when a whole team shares one pile of config files.

That quota is doing real work now. If the team already has 20 Pods running and asks for a 21st, Kubernetes says no. Same answer if a new Pod would push their memory total past 8Gi. The room has a meter on the wall, and once the meter reads full, nothing new comes in until something old goes out.

You can read that meter yourself instead of taking it on faith. kubectl describe prints what the room has used next to what it is allowed.

Terminal
kubectl describe quota team-a-quota -n team-a
Output
Name: team-a-quota
Namespace: team-a
Resource Used Hard
-------- ---- ----
limits.cpu 2 8
limits.memory 4Gi 16Gi
pods 2 20
requests.cpu 500m 4
requests.memory 1Gi 8Gi

What a namespace will not do for you

Here is where beginners get burned. A namespace tidies and it scopes, and on its own it isolates nothing at all. Two Pods in different namespaces can chat over the network all day, no questions asked. Kubernetes even hands out a friendly address to make it easier: a Service called db over in team-b answers to db.team-b from anywhere in the cluster. Nothing stands in the way of that traffic until you write a rule that blocks it.

Namespaces do not split the hardware either. A Pod from team-a and a Pod from team-b will happily share one physical machine, which Kubernetes calls a node. Real separation gets layered on top of the room. A NetworkPolicy (a firewall rule for Pod-to-Pod traffic) decides who may reach whom. Access rules decide who may act inside the namespace. Quotas decide how much anyone may take. The namespace is the room. You fit the locks and the meters yourself.

One cluster, four namespaces
default
web
Deployment
web-xxxx
Pod
team-a
web
Deployment
db
Service
team-b
web
Deployment
db
Service
kube-system
coredns
cluster DNS
kube-proxy
networking

Read that picture room by room. default is still holding a stray web that somebody created without thinking about where it would land. team-a and team-b each run their own web and their own db, identical names, zero collisions. kube-system is the cluster's own flat, where CoreDNS and kube-proxy quietly keep the lights on. Give teams and environments rooms of their own rather than piling everything into default.

Inside one room a short name is enough. A Pod in team-a asks for db and gets the team-a database. Call across rooms and you need the longer form, db.team-b, or the fully spelled out db.team-b.svc.cluster.local, which is what people mean by an FQDN (fully qualified domain name, a name with every level written out so nothing is left to guesswork). NetworkPolicies and quotas live inside a namespace too. None of this adds up to security on its own; it gives you organization plus the hooks that policy attaches to.

During an incident, type the -n every time. The classic 3 a.m. outage is somebody editing exactly the right object name in exactly the wrong namespace, then staring at a graph that refuses to move. Pick your namespace on purpose instead of letting default pick it for you.

Try this

Make a namespace, put a Deployment inside it, watch default come up empty without -n, then throw the room away.

terminal
$ kubectl create namespace team-a
namespace/team-a created
$ kubectl -n team-a create deployment web --image=nginx:1.27 --replicas=1
deployment.apps/web created
$ kubectl get pods
No resources found in default namespace.
$ kubectl -n team-a get pods
NAME READY STATUS RESTARTS AGE
web-… 1/1 Running 0 6s
$ kubectl get deploy -A | Select-String 'team-a|NAMESPACE'
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
team-a web 1/1 1 1 10s
$ kubectl delete namespace team-a
namespace "team-a" deleted

Takeaway

A namespace buys you a name scope, a place to hang quotas, and a place to hang access rules. It buys you no network wall and no split in the hardware. Type the -n (or set your context deliberately), and reach for the cross-namespace name when a Service in one room has to call a Service in another.

When something 'vanishes', suspect the namespace before the app
Nine times out of ten a missing Pod has not crashed. It is sitting in a room you walked out of and forgot about. Reach for -A (the long form is --all-namespaces) to find it, then choose: -n <name> for a quick look, or switch your default context if you will be working in that room for a while. Check the room before you go debugging the app.
Quick check
01You drop a frontend into namespace team-a and a database into team-b, and you configure nothing else. Can the frontend talk to the database over the network?
Correct — Nothing stands in the way until you write a NetworkPolicy, and the database answers to db.team-b from anywhere in the cluster.
Incorrect — This is the myth that catches people. A namespace scopes names and admin rules, not packets. Cross-namespace traffic flows on day one.
Incorrect — Where the Pods land makes no difference. Pods reach each other by Service name across nodes and across namespaces alike.
02Team A already runs a Deployment named web in namespace team-a. Team B wants a Deployment named web of their own, in namespace team-b. What happens?
Incorrect — Names only need to be unique inside one namespace, so two Deployments called web in two namespaces sit side by side quite happily.
Correct — Per-namespace naming is exactly what lets teams keep short, obvious names without stepping on each other.
Incorrect — Nothing gets replaced. The two are separate objects living in separate namespaces.
Incorrect — Backwards. Putting both in one namespace is the one arrangement that would make the names collide.
03team-a.yaml carries a ResourceQuota with pods: "20". The team is already running 20 Pods and applies a 21st. What does Kubernetes do?
Correct — Once the meter reads full, nothing new is let in until something old leaves.
Incorrect — A quota turns away new objects over the cap. It never kills running Pods to squeeze another one in.
Incorrect — The check happens as the object is admitted, so the over-limit Pod is genuinely turned away, not merely flagged.
Incorrect — Going over a quota refuses the new request. It never tears the namespace down.

Related