Let's think about it this way for a second
On a big cluster running lots of teams and lots of apps, resource names can collide (say both teams name their deployment 'database'). A Namespace is basically like a virtual cluster — resource names just need to be unique within each namespace (they can repeat across namespaces). By default, resources get created in the `default` namespace — `kube-system` is where Kubernetes's own internal components run.
Let's connect this to a real scenario
To split things up by team, you might create three namespaces — `dev`, `staging`, `production` — and deploy each environment's Deployment/Service into its own namespace, like `kubectl apply -f app.yaml -n staging`. You can also set resource quotas (CPU/memory limits) per namespace — so one team burning through all the resources doesn't end up hurting another team.
Let's look at it together
# Create a namespace
kubectl create namespace staging
# Deploy into a specific namespace
kubectl apply -f app.yaml -n staging
# List resources in a namespace
kubectl get pods -n staging
# See all namespaces
kubectl get namespacesNAME STATUS AGE
default Active 10d
kube-system Active 10d
staging Active 5s5-Minute Try-It
Create a `staging` namespace and deploy web-deployment into it (remember to add `-n staging`) — you'll see it's kept separate from the pods in the `default` namespace.
A Quick Word of Caution
Namespaces don't provide network isolation by default — pods in different namespaces can still talk to each other by default (a NetworkPolicy is what's needed to block that).