Stage 5 · Platform
Platform Engineering & Multi-Tenancy
Multi-Tenancy
Namespaces, hierarchy, virtual clusters (vcluster), and cost allocation.
Tenancy Models
Multi-tenancy in Kubernetes ranges from soft isolation (shared cluster, separate namespaces) to hard isolation (separate clusters). The right model depends on your security, compliance, and operational requirements.
| Model | Isolation | Complexity | Cost |
|---|---|---|---|
| Shared namespace | None | Low | Low |
| Namespace per team | Soft | Medium | Low |
| Virtual cluster per team | Medium | Medium | Medium |
| Cluster per team | Hard | High | High |
Namespace Isolation
Namespaces provide the basic isolation boundary for multi-tenancy. Each tenant gets their own namespace with separate RBAC, NetworkPolicies, and ResourceQuotas. NetworkPolicies prevent cross-tenant traffic. RBAC restricts who can manage resources.
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
tenant: alpha
pod-security.kubernetes.io/enforce: baseline
annotations:
cost-center: "engineering-123"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-cross-tenant
namespace: team-alpha
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant: alpha
egress:
- to:
- namespaceSelector:
matchLabels:
tenant: alpha
- to: # Allow DNS
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53This namespace blocks all cross-tenant traffic. Tenants can only communicate within their namespace. DNS egress is allowed for service discovery. The pod-security label enforces the baseline security profile.
Resource Quotas per Tenant
Resource quotas prevent any tenant from consuming more than their share. Set quotas on CPU, memory, storage, and object counts. Use limit ranges to set default requests/limits so users don't have to specify them.
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "20"
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
persistentvolumeclaims: "10"
pods: "50"
services.loadbalancers: "2"
services.nodeports: "0"
configmaps: "100"
secrets: "100"
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values: ["production"]
---
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-alpha
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "4"
memory: "8Gi"The quota limits total resources in the namespace. The limit range sets defaults for containers that don't specify resources. scopeSelector applies quotas to pods with specific priority classes.
When a namespace hits its quota, new pods are rejected with 403 Forbidden. Monitor quota usage with kubectl describe resourcequota -n team-alpha. Set up alerts when usage exceeds 80%.
RBAC for Tenants
RBAC restricts what tenants can do in their namespaces. Give tenants admin access to their namespace but no access to others. Use ClusterRoles for cluster-wide permissions (reading nodes, storage classes) and Roles for namespace-specific permissions.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tenant-admin
namespace: team-alpha
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-admins
namespace: team-alpha
subjects:
- kind: Group
name: team-alpha-admins
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: tenant-admin
apiGroup: rbac.authorization.k8s.ioTenant admins can manage all resources in their namespace. The Group subject maps to your identity provider groups. This ensures only team-alpha admins can manage resources in team-alpha.
Virtual Clusters (vcluster)
Virtual clusters (vcluster) provide stronger isolation than namespaces. Each tenant gets a virtual API server that runs in a pod. The virtual cluster has its own namespaces, RBAC, and CRDs, but shares the underlying node resources. This is a middle ground between namespace and full cluster isolation.
apiVersion: apps/v1
kind: Deployment
metadata:
name: vcluster-alpha
namespace: vclusters
spec:
replicas: 1
selector:
matchLabels:
app: vcluster-alpha
template:
metadata:
labels:
app: vcluster-alpha
spec:
containers:
- name: vcluster
image: loftsh/vcluster:0.19.0
args:
- --service-cidr=10.96.0.0/16
- --dns-domain=cluster.local
env:
- name: VCLUSTER_SERVICE_TYPE
value: LoadBalancervcluster runs a lightweight Kubernetes API server in a pod. Tenants get their own cluster context but share physical resources. The vcluster syncs resources to the host cluster for scheduling.
Cost Allocation
Cost allocation tracks resource consumption per tenant for billing and optimization. Kubecost, OpenCost, and cloud provider tools provide namespace-level cost breakdowns. Labels on namespaces and pods enable cost attribution.
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
cost-center: engineering
environment: production
---
# OpenCost allocation query
# kubectl port-forward -n kubecost svc/kubecost-cost-analyzer 9090
# http://localhost:9090/model/allocation?window=7d&aggregate=namespaceOpenCost tracks CPU, memory, storage, and network costs per namespace. Labels enable filtering and grouping. Export cost data to Prometheus for custom dashboards and alerting.
Kubecost provides real-time cost visibility per namespace, deployment, and label. It shows idle resources, right-sizing recommendations, and allocation reports. Install via Helm: helm install kubecost kubecost/cost-analyzer.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.