Multi-tenancy in Kubernetes: naamruimte, resourcequota en HNC
Het beheren van één Kubernetes-cluster voor één team is relatief eenvoudig. De echte uitdaging begint wanneer je hetzelfde cluster moet delen met 10, 20, 50 teams verschillend, elk met zijn eigen vereisten voor hulpbronnen, beveiliging en isolatie. Of wanneer u Kubernetes-as-a-service aanbiedt aan uw klanten en u ervoor moet zorgen dat de A kan de werklast van team B niet zien of zich ermee bemoeien, kan niet meer consumeren middelen van zijn begroting, en kan het bedrijfsbeleid niet omzeilen.
Kubernetes biedt de naamruimte als basisisolatie-eenheid, maar dit alleen is niet voldoende voor echte multi-tenancy. In dit artikel zullen we zien Zo bouwt u een compleet multi-tenancy-systeem: Bronquota om bronnen per naamruimte te beperken, Limietbereik instellen standaardwaarden en maxima per container, Netwerkbeleid het verkeer te isoleren, e Hiërarchische naamruimtecontroller (HNC) faciliteiten beheren complexe organisatiesystemen met beleidsovererving.
Wat je gaat leren
- Multi-tenancy-modellen: naamruimte per tenant versus cluster per tenant
- ResourceQuota: limieten voor CPU, geheugen, opslag en aantal objecten per naamruimte
- LimitRange: standaardwaarden en maxima voor containers, preventie van Pods zonder limieten
- NetworkPolicy voor isolatie tussen naamruimten
- RBAC voor tenants: elk team ziet alleen zijn eigen naamruimte
- HNC (Hierarchical Namespace Controller): overname van beleid, quota en RBAC
- Vcluster: complete virtuele clusters voor sterke isolatie
- Patroon voor automatische onboarding van huurders
Multi-tenancy-modellen
Voordat u het implementeert, moet u het juiste model kiezen op basis van uw niveau isolatie vereist:
| Model | Isolatie | Operationele overhead | Kosten | Gebruikscasus |
|---|---|---|---|---|
| Naamruimte-voor-team | Logisch (RBAC, delen) | Bas | Minimum | Interne teams met wederzijds vertrouwen |
| Naamruimte per klant (zachte multi-tenancy) | Logisch + Netwerk | Medium | Bas | SaaS met basisisolatie |
| Virtueel cluster (vcluster) | Sterk (afzonderlijke server-API) | Hoog | Medium | Enterprise-klanten, CI/CD-isolatie |
| Apart cluster per tenant | Compleet | Zeer lang | Hoog | Regelgeving, gevoelige gegevens |
ResourceQuota: limieten voor naamruimten
De ResourceQuota definieert de totale limieten voor alle resources in een naamruimte. Wanneer een naamruimte een quotum heeft, komt elk verzoek voor het maken van bronnen geverifieerd aan de hand van het beschikbare quotum.
Volledige ResourceQuota voor een team
# resource-quota-team-alpha.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
# Risorse compute
requests.cpu: "20" # max 20 vCPU richieste nel namespace
limits.cpu: "40" # max 40 vCPU limits
requests.memory: "40Gi" # max 40 GB RAM richiesta
limits.memory: "80Gi" # max 80 GB RAM limits
# Storage
requests.storage: "500Gi" # max 500 GB storage totale
persistentvolumeclaims: "20" # max 20 PVC
# Per StorageClass specifica
standard.storageclass.storage.k8s.io/requests.storage: "200Gi"
ssd.storageclass.storage.k8s.io/requests.storage: "100Gi"
# Oggetti Kubernetes
pods: "100" # max 100 Pod
services: "20"
secrets: "50"
configmaps: "50"
replicationcontrollers: "20"
services.nodeports: "0" # nessun NodePort (usiamo Ingress)
services.loadbalancers: "2" # max 2 LoadBalancer
# GPU (se applicabile)
requests.nvidia.com/gpu: "4" # max 4 GPU
# Verifica utilizzo quota
kubectl describe resourcequota team-alpha-quota -n team-alpha
# Output:
# Name: team-alpha-quota
# Resource Used Hard
# -------- --- ---
# limits.cpu 8500m 40
# limits.memory 12Gi 80Gi
# pods 35 100
# requests.cpu 4200m 20
Resourcequota per serviceklasse
# resource-quota-by-priority.yaml
# Separa le quote per classe di priorita
# Usa PriorityClass per fare QoS
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000
globalDefault: false
description: "Workload critici, non soggetti a eviction"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority
value: 100
globalDefault: true
description: "Workload batch, possono essere evicted"
---
# Quota separata per workload ad alta priorita
apiVersion: v1
kind: ResourceQuota
metadata:
name: high-priority-quota
namespace: team-alpha
spec:
hard:
pods: "10"
requests.cpu: "8"
requests.memory: "16Gi"
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values: ["high-priority"]
LimitRange: standaardwaarden en maxima voor containers
ResourceQuota werkt op naamruimteniveau, maar als een pod resources.requests niet specificeert, quota kan het gebruik niet berekenen. De LimitRange lost dit op: het stelt verzoek en limiet in standaard voor elke container en definieert de toegestane minimum- en maximumwaarden.
# limitrange-team-alpha.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: team-alpha-limits
namespace: team-alpha
spec:
limits:
# Valori di default per container (applicati se non specificati)
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
# Massimi e minimi consentiti
max:
cpu: "4"
memory: "8Gi"
min:
cpu: "10m"
memory: "32Mi"
# Ratio max/request per prevenire burst eccessivi
maxLimitRequestRatio:
cpu: "10" # limit max 10x il request
memory: "4" # limit max 4x il request
# Per i Pod (somma di tutti i container)
- type: Pod
max:
cpu: "8"
memory: "16Gi"
# Per i PVC
- type: PersistentVolumeClaim
max:
storage: "50Gi"
min:
storage: "1Gi"
RBAC voor multi-tenancy
Elke tenant hoeft alleen zijn eigen naamruimte te zien en te wijzigen. Laten we een patroon maken reproduceerbare RBAC die voor elk nieuw team kan worden geautomatiseerd:
# onboarding-team-alpha.yaml
# Script di onboarding: crea namespace + quota + limitrange + RBAC
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
env: production
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
---
# Gruppo di utenti: tutti i developer del team alpha
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-developers
namespace: team-alpha
subjects:
- kind: Group
name: "team-alpha"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit # ClusterRole built-in: edit permette tutto tranne RBAC e quota
apiGroup: rbac.authorization.k8s.io
---
# Tech Lead: puo anche gestire i quota (ma non cluster-admin)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-lead
namespace: team-alpha
subjects:
- kind: User
name: "alice@company.com"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin # ClusterRole built-in: admin = edit + gestione RBAC nel namespace
apiGroup: rbac.authorization.k8s.io
# Verifica che il team non possa accedere ad altri namespace
kubectl auth can-i get pods --as-group=team-alpha --as=developer -n team-beta
# No
kubectl auth can-i get pods --as-group=team-alpha --as=developer -n team-alpha
# Yes
Netwerkbeleid voor isolatie van meerdere naamruimten
# networkpolicy-tenant-isolation.yaml
# Isola completamente il namespace del tenant
# Permette solo traffico interno al namespace + DNS + monitoring
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-isolation
namespace: team-alpha
spec:
podSelector: {} # tutti i Pod nel namespace
policyTypes:
- Ingress
- Egress
ingress:
# Traffico solo da Pod nello stesso namespace
- from:
- podSelector: {}
# Permetti dall'ingress controller (namespace ingress-nginx)
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
egress:
# Traffico solo verso Pod nello stesso namespace
- to:
- podSelector: {}
# DNS
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# Monitoring: permetti scrape da namespace monitoring
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
# Accesso a servizi comuni (es. database condiviso, internal APIs)
- to:
- namespaceSelector:
matchLabels:
shared-service: "true"
ports:
- protocol: TCP
port: 5432 # PostgreSQL condiviso
- protocol: TCP
port: 6379 # Redis condiviso
Hiërarchische naamruimtecontroller (HNC)
Met HNC kunt u creëren naamruimtehiërarchieën met erfenis van hulpbronnen. En ideaal voor complexe organisatiestructuren: een ‘team-alpha’ naamruimte met subnaamruimten "team-alpha-dev", "team-alpha-staging", "team-alpha-prod" die ze nemen automatisch RBAC, NetworkPolicy, ResourceQuota en LimitRange over van het bovenliggende item.
HNC-installatie
# Installa HNC con kubectl
kubectl apply -f https://github.com/kubernetes-sigs/hierarchical-namespaces/releases/download/v1.1.0/default.yaml
# Oppure con Helm
helm repo add hnc https://kubernetes-sigs.github.io/hierarchical-namespaces/
helm install hnc hnc/hnc \
--namespace hnc-system \
--create-namespace \
--version 1.1.0
# Installa il plugin kubectl per HNC
curl -L https://github.com/kubernetes-sigs/hierarchical-namespaces/releases/download/v1.1.0/kubectl-hns_linux_amd64 \
-o /usr/local/bin/kubectl-hns
chmod +x /usr/local/bin/kubectl-hns
# Verifica
kubectl hns version
Naamruimtehiërarchie voor een team
# Crea la gerarchia: team-alpha e il namespace root
# team-alpha-dev e team-alpha-prod sono subnamespace
# Crea il namespace root
kubectl create namespace team-alpha
# Crea i subnamespace (HNC li gestisce)
kubectl hns create team-alpha-dev -n team-alpha
kubectl hns create team-alpha-staging -n team-alpha
kubectl hns create team-alpha-prod -n team-alpha
# Visualizza la gerarchia
kubectl hns tree team-alpha
# Output:
# team-alpha
# ├── team-alpha-dev
# ├── team-alpha-staging
# └── team-alpha-prod
# Configura cosa viene propagato dai parent ai children
kubectl hns config set-resource networkpolicies --mode Propagate
kubectl hns config set-resource rolebindings --mode Propagate
kubectl hns config set-resource limitranges --mode Propagate
# ResourceQuota NON viene propagata (ogni sub-namespace ha la sua)
Automatische bronverspreiding
# Nel namespace parent team-alpha:
# Un RoleBinding qui viene propagato automaticamente a tutti i subnamespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-developers
namespace: team-alpha # propagato automaticamente a tutti i children
annotations:
propagate.hnc.x-k8s.io/select: "true"
subjects:
- kind: Group
name: "team-alpha-devs"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # view in tutti i subnamespace
apiGroup: rbac.authorization.k8s.io
# RoleBinding specifico per prod: solo il tech lead
# Non si propaga ai children perche e in team-alpha-prod
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: prod-admin
namespace: team-alpha-prod
subjects:
- kind: User
name: "alice@company.com"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
# Verifica propagazione
kubectl get rolebindings -n team-alpha-dev | grep team-alpha-developers
# Il RoleBinding e apparso nel subnamespace per propagazione
Virtueel cluster met vcluster
Voor een sterkere isolatie creëert vcluster volledige Kubernetes-clusters (met zijn eigen API-server, planner en controllermanager) die binnen een naamruimte draaien van het gastcluster. De huurder heeft volledige toegang tot zijn vcluster, maar ziet deze niet het gastcluster.
# Installa vcluster CLI
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin
# Crea un virtual cluster per il team-beta
vcluster create team-beta-cluster \
--namespace vcluster-team-beta \
--connect=false \
--helm-values vcluster-values.yaml
# vcluster-values.yaml
# vcluster:
# image: ghcr.io/loft-sh/vcluster-k8s:1.30
# sync:
# nodes:
# enabled: true
# syncAllNodes: false # sync solo i nodi dove girano i Pod del vcluster
# resources:
# limits:
# cpu: "2"
# memory: "2Gi"
# Connettiti al vcluster
vcluster connect team-beta-cluster --namespace vcluster-team-beta -- kubectl get nodes
Automatisering van de onboarding van huurders
In clusters met veel teams schaalt handmatige onboarding niet. Een gemeenschappelijk patroon en gebruik
een speciale Operator (of een eenvoudig script/GitOps) die automatisch alle
middelen die nodig zijn voor een nieuwe huurder, uitgaande van een CRD Tenant:
# tenant-crd.yaml - esempio con Capsule (operator per multi-tenancy)
# Capsule e un operator CNCF che automatizza la creazione di tenant
helm repo add clastix https://clastix.github.io/charts
helm install capsule clastix/capsule \
--namespace capsule-system \
--create-namespace
---
# tenant.yaml - definisci un tenant con Capsule
apiVersion: capsule.clastix.io/v1beta2
kind: Tenant
metadata:
name: team-alpha
spec:
owners:
- name: alice@company.com
kind: User
- name: team-alpha-admins
kind: Group
namespaceOptions:
quota: 10 # max 10 namespace per questo tenant
forbiddenLabels:
denied: ["environment=production"] # il tenant non puo creare ns con certi label
resourceQuotas:
scope: Tenant # quota aggregata su tutti i namespace del tenant
items:
- hard:
requests.cpu: "50"
requests.memory: "100Gi"
requests.storage: "1Ti"
limitRanges:
items:
- limits:
- type: Container
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
networkPolicies:
items:
- podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector: {}
nodeSelector:
kubernetes.io/os: linux
# Possibile restringere il tenant a nodi specifici:
# tenant: team-alpha
Kansbewaking
# Vedi utilizzo quota di tutti i namespace
kubectl get resourcequota -A -o custom-columns=\
"NAMESPACE:.metadata.namespace,NAME:.metadata.name,\
CPU-REQ:.status.used.requests\.cpu,CPU-LIM:.status.used.limits\.cpu,\
MEM-REQ:.status.used.requests\.memory"
# Alert Prometheus per quota vicina al limite
# Aggiungi questa regola PrometheusRule:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: namespace-quota-alerts
namespace: monitoring
spec:
groups:
- name: quota
rules:
- alert: NamespaceCPUQuotaExceeding80Percent
expr: |
kube_resourcequota{resource="requests.cpu",type="used"} /
kube_resourcequota{resource="requests.cpu",type="hard"} > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "Namespace {{ $labels.namespace }} al {{ $value | humanizePercentage }} della quota CPU"
- alert: NamespaceMemoryQuotaExceeding90Percent
expr: |
kube_resourcequota{resource="requests.memory",type="used"} /
kube_resourcequota{resource="requests.memory",type="hard"} > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "Namespace {{ $labels.namespace }} al 90% della quota memoria"
Best practices voor multi-tenancy
Controlelijst voor productiemultitenancy
- Eén naamruimte per teamomgeving: team-alpha-ontwikkelaar, team-alpha-staging, team-alpha-prod; vermijd het mixen van omgevingen in dezelfde naamruimte
- ResourceQuota altijd gedefinieerd: zonder quota kan een team alle clusterbronnen verbruiken en andere tenants beïnvloeden
- LimitRange voor standaardwaarden: voorkomt dat Pods zonder bronverzoeken ResourceQuota's en clusterplanning onbruikbaar maken
- Netwerkbeleid standaard weigeren: elke naamruimte moet een beleid hebben dat al het ongeautoriseerde verkeer tussen de naamruimten blokkeert
- Pod-beveiligingsnormen beperkt: past het beperkte niveau toe op alle tenant-naamruimten (zie artikel 6)
- RBAC minste privilege: ontwikkelaars gebruiken ClusterRole
edit, Nietadminocluster-admin - Toegangsaudit: schakel het auditlogboek in om bij te houden wie toegang heeft tot wat in elke naamruimte
- Automatiseer onboarding: gebruik Capsule, een aangepaste Operator of een GitOps-manifest om alle tenantobjecten consistent te maken
Valkuilen van Multi-Tenancy Kubernetes
- Naamruimte is geen volledige isolatie: sommige clustergerichte objecten (ClusterRole, PersistentVolume, Node) zijn zichtbaar voor alle tenants; gebruik vcluster als je volledige isolatie nodig hebt
- Gedeelde kernel-kwetsbaarheden: alle tenants delen dezelfde Linux-kernel; een container die misbruik maakt van een kernelkwetsbaarheid kan gevolgen hebben voor andere tenants; Evalueer speciale knooppunten voor tenants met gevoelige gegevens
- DNS-lekkage: Standaard kunnen Pods servicenamen omzetten in andere naamruimten (
service.namespace.svc.cluster.local); gebruik NetworkPolicy om indien nodig ook DNS-verkeer tussen naamruimten te blokkeren - ResourceQuota zonder LimitRange: als er geen LimitRange is, negeren Pods zonder resourceaanvragen de ResourceQuota en wordt het quotum niet correct geschaald
Conclusies en volgende stappen
Multi-tenancy in Kubernetes is een continuüm tussen operationele eenvoud en isolatie sterk. Voor de meeste businesscases met interne teams, naamruimten met ResourceQuota, Passende LimitRange, NetworkPolicy en RBAC zorgen voor voldoende isolatie minimale operationele overhead. Voor zakelijke klanten of scenario's met compliancevereisten strenger, vcluster biedt een veel sterker niveau van isolatie met behoud van de voordelen van een gedeeld cluster in termen van hulpbronnenefficiëntie.
HNC verandert het beheer van naamruimtehiërarchieën in iets schaalbaars: in plaats van het handmatig repliceren van RBAC en NetworkPolicy in elke subnaamruimte is gedefinieerd beleid eenmaal in de bovenliggende naamruimte en wordt automatisch doorgegeven. Voor platforms met tientallen teams maakt dit het verschil tussen een onderhoudbaar systeem en een systeem dat dit vereist een speciaal team dat alleen de naamruimteconfiguratie beheert.
Aankomende artikelen in de Kubernetes at Scale-serie
Vorige artikelen
Gerelateerde serie
- Kubernetes-beveiliging — RBAC- en Pod-beveiligingsnormen, vereisten voor multi-tenancy
- Platformtechniek — multi-tenancy als basis voor interne ontwikkelaarsplatforms
- FinOps voor Kubernetes — kostenbeheer voor naamruimten en tenants







