Multi-Tenancy în Kubernetes: spațiu de nume, cotă de resurse și HNC
Gestionarea unui singur cluster Kubernetes pentru o singură echipă este relativ simplă. Adevărata provocare începe atunci când trebuie să împărțiți același grup între 10, 20, 50 de echipe diferite, fiecare cu propriile cerințe de resurse, securitate și izolare. Sau atunci când oferiți Kubernetes-as-a-service clienților dvs. și trebuie să vă asigurați că A nu pot vedea sau interfera cu sarcinile de lucru ale echipei B, nu mai pot consuma resursele bugetului său și nu poate ocoli politicile companiei.
Kubernetes oferă spatiu de nume ca unitate de izolație de bază, dar singur nu este suficient pentru multi-chiriere reală. În acest articol vom vedea Cum să construiți un sistem complet de locații multiple: Cota de resurse pentru a limita resursele pe spațiu de nume, LimitRange a seta valorile implicite și maxime pe container, NetworkPolicy pentru a izola traficul, e Controler ierarhic al spațiului de nume (HNC) pentru a gestiona instalațiile sisteme organizaționale complexe cu moștenire de politici.
Ce vei învăța
- Modele de închiriere multiplă: spațiu de nume per locatar vs cluster per locatar
- ResourceQuota: Limite ale procesorului, memoriei, stocării și numărului de obiecte per spațiu de nume
- LimitRange: valori implicite și maxime pentru containere, prevenirea Podurilor fără limite
- NetworkPolicy pentru izolarea între spațiile de nume
- RBAC pentru chiriași: fiecare echipă vede doar propriul spațiu de nume
- HNC (Controler de spațiu de nume ierarhic): moștenirea politicii, a cotei și a RBAC
- Vcluster: clustere virtuale complete pentru o izolare puternică
- Model pentru integrarea automată a chiriașilor
Modele cu mai multe locații
Înainte de implementare, trebuie să alegeți modelul potrivit în funcție de nivelul dvs izolație necesară:
| Model | Izolare | Regimul Operațional | Cost | Caz de utilizare |
|---|---|---|---|---|
| Spațiu de nume pentru echipă | logic (RBAC, partajare) | Bas | Minim | Echipe interne cu încredere reciprocă |
| Spațiu de nume pentru fiecare client (închiriere multiplă soft) | Logic + Rețea | Mediu | Bas | SaaS cu izolare de bază |
| Cluster virtual (vcluster) | Puternic (API de server separat) | Ridicat | Mediu | Clienți întreprinderi, izolare CI/CD |
| Grup separat pentru fiecare chiriaș | Complet | Foarte Înalt | Ridicat | Reglementare, date sensibile |
ResourceQuota: Limite pentru spațiile de nume
ResourceQuota definește limitele agregate pentru toate resursele dintr-un spațiu de nume. Când un spațiu de nume are o cotă, vine fiecare cerere de creare a resurselor verificate în raport cu cota disponibilă.
Cota completă de resurse pentru o echipă
# 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
Cota de resurse pe clasă de serviciu
# 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: Valori implicite și maxime pentru containere
ResourceQuota operează la nivel de spațiu de nume, dar dacă un Pod nu specifică resources.requests, cota nu poate calcula utilizarea. LimitRange rezolvă acest lucru: stabilește cererea și limita implicit pentru fiecare container și definește valorile minime și maxime permise.
# 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 pentru Multi-Tenancy
Fiecare chiriaș trebuie doar să vadă și să-și schimbe propriul spațiu de nume. Să creăm un model RBAC reproductibil care poate fi automatizat pentru fiecare echipă nouă:
# 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
NetworkPolicy pentru izolarea între spații de nume
# 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
Controler ierarhic al spațiului de nume (HNC)
HNC vă permite să creați ierarhiile spațiilor de nume cu moştenire de resurse. Și ideal pentru structuri organizaționale complexe: un spațiu de nume „echipă-alfa”. cu sub-spații de nume „team-alpha-dev”, „team-alpha-staging”, „team-alpha-prod” care ei moștenesc automat RBAC, NetworkPolicy, ResourceQuota și LimitRange de la părinte.
Instalare HNC
# 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
Ierarhia spațiilor de nume pentru o echipă
# 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)
Propagarea automată a resurselor
# 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
Cluster virtual cu vcluster
Pentru o izolare mai puternică, vcluster creează clustere Kubernetes complete (cu propriile sale Server API, planificator și manager de controler) care rulează într-un spațiu de nume a clusterului gazdă. Chiriașul are acces complet la vcluster-ul său, dar nu vede cluster-ul gazdă.
# 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
Automatizare de integrare a chiriașilor
În grupurile cu multe echipe, integrarea manuală nu se extinde. Un model și o utilizare obișnuită
un Operator dedicat (sau un simplu script/GitOps) care creează automat toate
resursele necesare unui nou chiriaș pornind de la un 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
Monitorizarea cotelor
# 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"
Cele mai bune practici pentru multi-chiriere
Lista de verificare pentru multi-chiriere de producție
- Un spațiu de nume pentru fiecare mediu de echipă: team-alpha-dev, team-alpha-staging, team-alpha-prod; evitați amestecarea mediilor în același spațiu de nume
- Cota de resurse este întotdeauna definită: fără cotă, o echipă poate consuma toate resursele clusterului și poate afecta alți chiriași
- LimitRange pentru valori implicite: împiedică podurile fără solicitări de resurse să facă inutile ResourceQuotas și programarea clusterului
- NetworkPolicy default-deny: fiecare spațiu de nume trebuie să aibă o politică care blochează tot traficul neautorizat între spații de nume
- Standarde de securitate pentru pod restricționate: aplică nivelul restricționat tuturor spațiilor de nume ale chiriașilor (vezi articolul 6)
- privilegiu minim RBAC: dezvoltatorii folosesc ClusterRole
edit, Nuadminocluster-admin - Audit acces: activați jurnalul de audit pentru a urmări cine accesează ce în fiecare spațiu de nume
- Automatizați integrarea: utilizați Capsule, un operator personalizat sau un manifest GitOps pentru a crea toate obiectele chiriași în mod consecvent
Capcanele Kubernetes-ului cu locații multiple
- Spațiul de nume nu este o izolare completă: unele obiecte din domeniul clusterului (ClusterRole, PersistentVolume, Node) sunt vizibile pentru toți chiriașii; utilizați vcluster dacă aveți nevoie de o izolare completă
- Vulnerabilitati ale nucleului partajat: toți chiriașii au același nucleu Linux; un container care exploatează o vulnerabilitate a nucleului poate afecta alți chiriași; Evaluați nodurile dedicate pentru chiriașii cu date sensibile
- Scurgere de DNS: În mod implicit, podurile pot rezolva numele de servicii în alte spații de nume (
service.namespace.svc.cluster.local); utilizați NetworkPolicy pentru a bloca, de asemenea, traficul DNS între spații de nume, dacă este necesar - Cotă de resurse fără LimitRange: dacă nu există LimitRange, podurile fără solicitări de resurse ignoră ResourceQuota și cota nu este scalată corect
Concluzii și pașii următori
Multi-tenancy în Kubernetes este un continuum între simplitatea operațională și izolare puternic. Pentru majoritatea cazurilor de afaceri cu echipe interne, spații de nume cu ResourceQuota, LimitRange, NetworkPolicy și RBAC adecvate asigură o izolare suficientă cheltuieli operaționale minime. Pentru clienți întreprinderi sau scenarii cu cerințe de conformitate strict, vcluster oferă un nivel mult mai puternic de izolare, menținând în același timp beneficiile a unui cluster partajat în ceea ce privește eficiența resurselor.
HNC transformă gestionarea ierarhiilor spațiilor de nume în ceva scalabil: în loc de nevoia de a replica manual RBAC și NetworkPolicy în fiecare sub-namespace, sunt definite politicile o dată în spațiul de nume părinte și se propagă automat. Pentru platforme cu zeci de echipe, acest lucru face diferența între un sistem care poate fi întreținut și unul care necesită o echipă dedicată doar pentru a gestiona configurația spațiului de nume.
Articole viitoare din seria Kubernetes la scară
- Sarcini de lucru AI și GPU pe Kubernetes: Plugin de dispozitiv și joburi de instruire
- FinOps pentru Kubernetes: dimensionare drepturi, instanțe spot și reducere a costurilor
- GitOps cu ArgoCD: implementare declarativă și lansări progresive
- Observabilitatea clusterului: Prometheus, Grafana și OpenTelemetry
Articole anterioare
Serii înrudite
- Securitate Kubernetes — Standardele de securitate RBAC și Pod, condiții prealabile pentru închiriere multiplă
- Ingineria platformei — multi-tenancy ca fundament al platformelor interne pentru dezvoltatori
- FinOps pentru Kubernetes — managementul costurilor pentru spații de nume și chiriași







