4.1 What Namespaces Are and What They Are Not
Right, let’s talk about namespaces. If you’re coming from the world of virtual machines, your first instinct is to think of a namespace as a “mini-server” or a “virtual cluster.” I need you to unlearn that. It’s the wrong mental model, and it will lead to confusion and spectacularly broken deployments. A namespace is not a separate cluster; it’s a filter you apply to your existing cluster. It’s a way to say, “For this particular group of users or applications, only show them the objects that belong to them.”
Think of it like this: your entire cluster is a massive, shared apartment building. A namespace is just the number you paint on a single apartment door. Everyone shares the same building infrastructure: the foundation, the roof, the plumbing mains, the electrical grid. But what’s inside Apartment 4B is completely separate from what’s in 5C. The tenant in 4B can’t just walk into 5C and start rummaging through their fridge. That’s isolation. But if the main water line in the basement bursts, everyone in the building is affected. That’s the cluster-level shared fate.
The Crucial Boundary of a Namespace
This apartment building analogy explains what namespaces can and cannot do. They provide isolation for most Kubernetes objects—Pods, Services, Deployments, ConfigMaps, you name it. An object in the finance namespace is, by default, completely invisible to a Pod in the marketing namespace. This is brilliant for multi-tenancy. You can have a dev, staging, and prod namespace on the same cluster, and your developers can kubectl get pods --namespace=dev without seeing the carefully curated, sacred pods of production.
But—and this is a massive, glaring “but” that the designers absolutely should have found a better solution for—namespaces do not provide isolation for cluster-scoped resources. This is the rough edge you will cut yourself on.
Node resources, PersistentVolume objects, and most critically, ClusterRoles and ClusterRoleBindings, exist outside of any namespace. They are part of the building’s foundation. A poorly configured ClusterRoleBinding in the dev namespace can grant a service account permissions to delete every Pod in the entire cluster, including production. It’s like giving a tenant a master key that works on every single apartment door. It’s a phenomenally bad default, and you must be paranoid about it.
What’s In a Name (space)?
Let’s get practical. Creating a namespace is laughably simple. You can do it imperatively, which is fine for a quick test:
kubectl create namespace testing
But you and I both know that anything that matters belongs in a version-controlled manifest. So here’s the declarative way, in a file called my-namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: testing
labels:
environment: dev
team: frontend
Apply it with kubectl apply -f my-namespace.yaml. See? No magic. It’s just another Kubernetes object, like a Pod or a Service. This is a key insight: everything in Kubernetes is an object in the API, namespaces included.
Now, to see the magic of the filter in action, try these two commands back-to-back:
kubectl get pods -n testing
kubectl get pods -n kube-system
The first will probably return No resources found in testing namespace. The second will show you the all-important system-level pods that make your cluster actually function. You’ve just used the namespace filter to view two completely different slices of the same cluster.
The Default Dilemma and Contexts
Ah, the default namespace. Kubernetes, in its infinite wisdom, creates this one for you. It’s a trap. Using it for anything beyond five-minute experiments is a classic pitfall. It teaches bad habits, and because everyone can see it, it becomes a dumping ground for random, forgotten objects. Do yourself a favor and treat the default namespace like a public bathroom stall: use it in an emergency, but avoid it if you have any other option.
To avoid constantly typing -n namespace-name, you can change your current context. This is your kubectl configuration saying, “Until I say otherwise, assume I’m talking to this specific cluster, as this specific user, and looking in this specific namespace.”
# See your current context
kubectl config current-context
# Create a new context that points to your new namespace
kubectl config set-context my-test-context --cluster=your-cluster-name --user=your-user-name --namespace=testing
# Switch to using that new context
kubectl config use-context my-test-context
# Now all your commands are scoped to the 'testing' namespace!
kubectl get pods # This checks 'testing', not 'default'
This is incredibly useful, but also dangerously stateful. You forget you’ve switched contexts, run a destructive command, and accidentally wipe out your staging database instead of your local minikube one. I’ve done it. You’ll do it. The best practice is to always be explicit in scripts and automation. Never rely on a context. Use the -n flag every single time. Save the context switching for your interactive shell sessions, and always double-check your context with kubectl config current-context before running anything scary.
So, to recap: namespaces are your primary tool for soft, multi-tenant isolation within a single cluster. They’re a filter, not a fence. Use them relentlessly, label them meaningfully, but never, ever forget that their isolation is easily breached by cluster-scoped objects. Now let’s talk about how to actually enforce that isolation properly.