Namespaces: tidy rooms
Dividing one cluster into spaces.
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.
kubectl create namespace team-a
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.
kubectl config set-context --current --namespace=team-a
Context "kind-dev" modified.
Now a bare get pods reads from team-a and you never have to say the word.
kubectl get pods
NAME READY STATUS RESTARTS AGEweb-6f8c9d4b7f-2xkzr 1/1 Running 0 45sweb-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.
kubectl get pods
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.
kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGEkube-system coredns-76f75df574-abcde 1/1 Running 0 2dkube-system kube-proxy-9xk2l 1/1 Running 0 2dteam-a web-6f8c9d4b7f-2xkzr 1/1 Running 0 2mteam-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.
apiVersion: v1kind: Namespacemetadata:name: team-alabels:team: team-aenvironment: dev---apiVersion: v1kind: ResourceQuotametadata:name: team-a-quotanamespace: team-aspec:hard:requests.cpu: "4"requests.memory: 8Gilimits.cpu: "8"limits.memory: 16Gipods: "20"
kubectl apply -f team-a.yaml
namespace/team-a configuredresourcequota/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.
kubectl describe quota team-a-quota -n team-a
Name: team-a-quotaNamespace: team-aResource Used Hard-------- ---- ----limits.cpu 2 8limits.memory 4Gi 16Gipods 2 20requests.cpu 500m 4requests.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.
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.
$ kubectl create namespace team-anamespace/team-a created$ kubectl -n team-a create deployment web --image=nginx:1.27 --replicas=1deployment.apps/web created$ kubectl get podsNo resources found in default namespace.$ kubectl -n team-a get podsNAME READY STATUS RESTARTS AGEweb-… 1/1 Running 0 6s$ kubectl get deploy -A | Select-String 'team-a|NAMESPACE'NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGEteam-a web 1/1 1 1 10s$ kubectl delete namespace team-anamespace "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.
-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.team-a and a database into team-b, and you configure nothing else. Can the frontend talk to the database over the network?