CloudOpsGuide
kubernetes

Kubernetes Namespace Best Practices

Beginner
9 minutes
October 2026
CloudOpsGuide Team

Kubernetes Namespace Best Practices

Learn how to effectively organize and manage Kubernetes namespaces for multi-tenant environments, resource isolation, and security.

Table of Contents

What Are Namespaces

Namespaces provide logical separation within a single cluster. They're not hard isolation — they're organizational boundaries with optional resource and access controls.

# List all namespaces
kubectl get namespaces

# Built-in namespaces
NAME              STATUS   AGE
default           Active   30d     # default for everything without -n
kube-system       Active   30d     # cluster components (DNS, proxy)
kube-public       Active   30d     # publicly readable data
kube-node-lease   Active   30d     # node heartbeats

When to Use Namespaces

Good reasons:

  • Separate environments (dev / staging / prod)
  • Separate teams on a shared cluster
  • Separate applications with different resource needs
  • Apply different RBAC policies per boundary

Bad reasons:

  • One namespace per microservice in a small team — over-engineering
  • Namespaces as a security boundary alone — they need RBAC + NetworkPolicies + ResourceQuotas to mean anything

Namespace Organization Strategies

Strategy 1: By Environment (most common)

kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace production

Pros: simple, matches CI/CD pipelines, clear blast radius.

Strategy 2: By Team

kubectl create namespace team-payments
kubectl create namespace team-frontend

Pros: teams own their namespaces, quotas per team.

Strategy 3: By Environment + Team (larger orgs)

payments-dev, payments-prod
frontend-dev, frontend-prod

Resource Quotas

Prevent one team/environment from consuming the whole cluster:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"
    persistentvolumeclaims: "10"
    services.loadbalancers: "2"
kubectl apply -f quota.yaml
kubectl describe quota -n dev

LimitRange — Default Per-Container Limits

Without defaults, a single container can request everything:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
  - type: Container
    default:              # limit if unspecified
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:       # request if unspecified
      cpu: "100m"
      memory: "128Mi"
    max:
      cpu: "2"
      memory: "2Gi"
    min:
      cpu: "50m"
      memory: "64Mi"

Network Policies

Namespaces alone do NOT isolate network traffic. Add NetworkPolicies:

# Deny all cross-namespace traffic by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-namespace
  namespace: production
spec:
  podSelector: {}          # applies to all pods in production
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector: {}  # only pods in the same namespace
# Allow monitoring namespace to scrape metrics
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: monitoring
      ports:
        - port: 9090

RBAC per Namespace

Give teams access only to their namespaces:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: payments-dev
  name: developer
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "deployments", "jobs", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developers
  namespace: payments-dev
subjects:
- kind: Group
  name: payments-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

Common Mistakes

1. Everything in default

Deploying everything to default means no quotas, no RBAC isolation, and messy resource management. Create real namespaces from day one.

2. Assuming namespaces = security

Namespaces are organizational, not a security boundary. Combine with RBAC + NetworkPolicy + PodSecurityStandards:

# Enforce restricted pod security per namespace
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted

3. Forgetting resource defaults

Pods without requests/limits can starve a namespace. Always pair namespaces with LimitRange.

4. Namespace sprawl

Dozens of near-empty namespaces are harder to manage. Keep the scheme simple and documented.

Useful Commands

# Create with labels (useful for NetworkPolicy selectors)
kubectl create namespace monitoring
kubectl label namespace monitoring environment=observability

# Set default namespace for your context
kubectl config set-context --current --namespace=dev

# See everything in a namespace
kubectl get all -n production

# Delete a namespace (deletes EVERYTHING inside)
kubectl delete namespace old-env

Related Articles


Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Beginner
Estimated Reading Time: 9 minutes