Kubernetes의 멀티 테넌시: 네임스페이스, 리소스 할당량 및 HNC
단일 팀의 단일 Kubernetes 클러스터를 관리하는 것은 비교적 간단합니다. 진정한 도전은 10, 20, 50개 팀이 동일한 클러스터를 공유해야 할 때 시작됩니다. 각각 고유한 리소스, 보안 및 격리 요구 사항이 있습니다. 아니면 고객에게 서비스형 Kubernetes를 제공하고 다음을 보장해야 할 때 팀 B의 워크로드를 보거나 방해할 수 없으며 더 이상 소비할 수 없습니다. 예산 자원을 확보할 수 없으며 회사 정책을 우회할 수 없습니다.
Kubernetes는 다음을 제공합니다. 네임스페이스 기본적인 단열 단위로서, 그러나 그것만으로는 실제 멀티 테넌시에는 충분하지 않습니다. 이 기사에서 우리는 볼 것입니다 완전한 다중 테넌시 시스템을 구축하는 방법: 리소스할당량 네임스페이스당 리소스를 제한하기 위해 제한 범위 설정하다 컨테이너당 기본값 및 최대값, 네트워크 정책 트래픽을 격리하고, 전자 계층적 네임스페이스 컨트롤러(HNC) 시설을 관리하기 위해 정책 상속이 포함된 복잡한 조직 시스템.
무엇을 배울 것인가
- 다중 테넌트 모델: 테넌트당 네임스페이스와 테넌트당 클러스터
- ResourceQuota: CPU, 메모리, 스토리지 및 네임스페이스당 개체 수에 대한 제한
- LimitRange: 컨테이너의 기본값 및 최대값, 제한 없는 Pod 방지
- 네임스페이스 간 격리를 위한 NetworkPolicy
- 테넌트용 RBAC: 각 팀은 자체 네임스페이스만 볼 수 있습니다.
- HNC(Hierarchical Namespace Controller): 정책, 할당량 및 RBAC 상속
- Vcluster: 강력한 격리를 위한 완벽한 가상 클러스터
- 자동화된 테넌트 온보딩 패턴
다중 테넌시 모델
구현하기 전에 레벨에 따라 올바른 모델을 선택해야 합니다. 필요한 단열재:
| 모델 | 격리 | 운영 오버헤드 | 비용 | 사용 사례 |
|---|---|---|---|---|
| 팀용 네임스페이스 | 논리적(RBAC, 공유) | 베이스 | 최저한의 | 상호 신뢰를 갖고 있는 내부 팀 |
| 고객당 네임스페이스(소프트 멀티 테넌시) | 논리 + 네트워크 | 중간 | 베이스 | 기본 격리를 갖춘 SaaS |
| 가상 클러스터(vcluster) | 강력함(별도의 서버 API) | 높은 | 중간 | 기업 고객, CI/CD 격리 |
| 테넌트당 별도의 클러스터 | 완벽한 | 매우 키가 크다 | 높은 | 규제, 민감한 데이터 |
ResourceQuota: 네임스페이스 제한
ResourceQuota는 네임스페이스의 모든 리소스에 대한 집계 제한을 정의합니다. 네임스페이스에 할당량이 있으면 모든 리소스 생성 요청이 옵니다. 사용 가능한 할당량과 비교하여 확인되었습니다.
팀의 전체 ResourceQuota
# 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
# 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: 컨테이너의 기본값 및 최대값
ResourceQuota는 네임스페이스 수준에서 작동하지만 포드가 resources.requests를 지정하지 않으면 할당량으로 사용량을 계산할 수 없습니다. LimitRange는 이 문제를 해결합니다. 요청과 제한을 설정합니다. 각 컨테이너의 기본값이며 허용되는 최소값과 최대값을 정의합니다.
# 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
각 테넌트는 자신의 네임스페이스만 보고 변경하면 됩니다. 패턴을 만들어보자 새로운 팀마다 자동화할 수 있는 재현 가능한 RBAC:
# 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
# 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
계층적 네임스페이스 컨트롤러(HNC)
HNC를 사용하면 다음을 만들 수 있습니다. 네임스페이스 계층 상속으로 자원. 복잡한 조직 구조에 이상적: "team-alpha" 네임스페이스 하위 네임스페이스 "team-alpha-dev", "team-alpha-staging", "team-alpha-prod" 포함 상위 항목으로부터 RBAC, NetworkPolicy, ResourceQuota 및 LimitRange를 자동으로 상속합니다.
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
팀의 네임스페이스 계층 구조
# 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)
자동 리소스 전파
# 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
vcluster가 있는 가상 클러스터
더 강력한 격리를 위해 vcluster는 전체 Kubernetes 클러스터를 생성합니다(자체 네임스페이스 내에서 실행되는 API 서버, 스케줄러 및 컨트롤러 관리자 호스트 클러스터의 테넌트는 Vcluster에 대한 전체 액세스 권한을 가지고 있지만 볼 수는 없습니다. 호스트 클러스터.
# 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
테넌트 온보딩 자동화
팀이 많은 클러스터에서는 수동 온보딩이 확장되지 않습니다. 일반적인 패턴 및 사용
모든 것을 자동으로 생성하는 전용 Operator(또는 간단한 스크립트/GitOps)
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
확률 모니터링
# 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"
다중 테넌시 모범 사례
프로덕션 멀티 테넌시 체크리스트
- 팀 환경당 하나의 네임스페이스: 팀-알파-개발, 팀-알파-스테이징, 팀-알파-프로덕션; 동일한 네임스페이스에서 환경을 혼합하지 마십시오.
- ResourceQuota는 항상 정의됩니다. 할당량이 없으면 팀이 모든 클러스터 리소스를 소비하고 다른 테넌트에 영향을 미칠 수 있습니다.
- 기본값의 LimitRange: 리소스 요청이 없는 포드가 ResourceQuota 및 클러스터 예약을 쓸모없게 만드는 것을 방지합니다.
- NetworkPolicy 기본 거부: 각 네임스페이스에는 승인되지 않은 모든 네임스페이스 간 트래픽을 차단하는 정책이 있어야 합니다.
- 포드 보안 표준이 제한됨: 모든 테넌트 네임스페이스에 제한된 수준을 적용합니다(문서 6 참조).
- RBAC 최소 권한: 개발자는 ClusterRole을 사용합니다.
edit, 아니다adminocluster-admin - 액세스 감사: 감사 로그를 활성화하여 누가 각 네임스페이스의 무엇에 액세스하는지 추적
- 온보딩 자동화: Capsule, 사용자 지정 Operator 또는 GitOps 매니페스트를 사용하여 모든 테넌트 개체를 일관되게 생성합니다.
멀티 테넌시 Kubernetes의 함정
- 네임스페이스가 완전히 격리되지 않았습니다. 일부 클러스터 범위 객체(ClusterRole, PertantVolume, Node)는 모든 테넌트에 표시됩니다. 완전한 격리가 필요한 경우 vcluster를 사용하세요.
- 공유 커널 취약점: 모든 테넌트는 동일한 Linux 커널을 공유합니다. 커널 취약성을 악용하는 컨테이너는 다른 테넌트에 영향을 미칠 수 있습니다. 민감한 데이터가 있는 테넌트의 전용 노드를 평가합니다.
- DNS 유출: 기본적으로 Pod는 서비스 이름을 다른 네임스페이스(
service.namespace.svc.cluster.local); 필요한 경우 NetworkPolicy를 사용하여 네임스페이스 간 DNS 트래픽도 차단합니다. - LimitRange가 없는 ResourceQuota: LimitRange가 없으면 리소스 요청이 없는 포드는 ResourceQuota를 무시하고 할당량은 올바르게 조정되지 않습니다.
결론 및 다음 단계
Kubernetes의 멀티 테넌시는 운영 단순성과 격리 사이의 연속체입니다. 강하다. 내부 팀이 있는 대부분의 비즈니스 사례에서는 ResourceQuota가 있는 네임스페이스, 적절한 LimitRange, NetworkPolicy 및 RBAC는 다음을 통해 충분한 격리를 제공합니다. 최소한의 운영 오버헤드. 규정 준수 요구 사항이 있는 기업 고객 또는 시나리오의 경우 엄격하게 관리되는 vcluster는 이점을 유지하면서 훨씬 더 강력한 격리 수준을 제공합니다. 자원 효율성 측면에서 공유 클러스터의
HNC는 네임스페이스 계층 관리를 확장 가능한 방식으로 전환합니다. 각 하위 네임스페이스에서 RBAC 및 NetworkPolicy를 수동으로 복제해야 함 정책은 상위 네임스페이스에 한 번만 적용되고 자동으로 전파됩니다. 플랫폼의 경우 수십 개의 팀이 있기 때문에 유지 관리가 가능한 시스템과 필요한 시스템의 차이가 발생합니다. 네임스페이스 구성을 관리하는 전담 팀.
Kubernetes at Scale 시리즈의 향후 기사
이전 기사
관련 시리즈
- 쿠버네티스 보안 — RBAC 및 포드 보안 표준, 멀티 테넌시를 위한 전제 조건
- 플랫폼 엔지니어링 — 내부 개발자 플랫폼의 기반인 멀티 테넌시
- Kubernetes를 위한 FinOps — 네임스페이스 및 테넌트에 대한 비용 관리







