Kubernetes 多租户设计:Namespace 隔离、ResourceQuota、LimitRange 实战
系统讲解 Kubernetes 多租户架构设计:Namespace 资源隔离边界、ResourceQuota 配额控制防止资源抢占、LimitRange 设置默认资源限制、网络策略隔离租户流量,结合 RBAC 构建企业级多团队 K8s 平台的完整方案。
企业内多个团队共享同一 Kubernetes 集群时,“多租户”问题随之而来:如何防止某个团队把集群资源耗尽?如何保证各团队互不干扰?本文讲解用 Namespace + ResourceQuota + LimitRange + NetworkPolicy + RBAC 构建企业级多租户平台的完整方案。
多租户隔离模型
强隔离(多集群)
每个租户一个集群 → 完全隔离,成本最高,运维复杂
中等隔离(Namespace 隔离)
每个租户一个 Namespace → 软隔离,共享节点,本文重点
轻隔离(标签隔离)
同一 Namespace,用标签区分 → 最弱,不推荐
生产主流方案是 Namespace 级别隔离:通过 ResourceQuota 限制资源用量、NetworkPolicy 隔离网络、RBAC 控制权限。
一、Namespace 规划与命名规范
# 建议的命名规范:<环境>-<团队/业务>
# 生产环境
kubectl create namespace prod-frontend
kubectl create namespace prod-backend
kubectl create namespace prod-data
kubectl create namespace prod-infra # 共享基础设施(Prometheus、EFK 等)
# 开发/测试环境
kubectl create namespace dev-frontend
kubectl create namespace dev-backend
kubectl create namespace staging-frontend
# 平台组件(cluster-wide)
kubectl create namespace monitoring
kubectl create namespace logging
kubectl create namespace cert-manager
# 给 Namespace 打标签(用于 NetworkPolicy 选择)
kubectl label namespace prod-frontend \
env=production \
team=frontend \
tier=web
kubectl label namespace prod-backend \
env=production \
team=backend \
tier=api
二、ResourceQuota:硬性资源配额
ResourceQuota 防止单个租户消耗过多集群资源。
# prod-backend 团队的资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: backend-quota
namespace: prod-backend
spec:
hard:
# ====== 计算资源 ======
# Pod 实际 request 总量(所有 Pod 的 requests 之和上限)
requests.cpu: "20" # 最多申请 20 核
requests.memory: 40Gi # 最多申请 40GB 内存
# Pod 实际 limit 总量
limits.cpu: "40" # 最多限制 40 核
limits.memory: 80Gi # 最多限制 80GB 内存
# ====== 对象数量 ======
pods: "100" # 最多 100 个 Pod
services: "20" # 最多 20 个 Service
secrets: "50" # 最多 50 个 Secret
configmaps: "50" # 最多 50 个 ConfigMap
persistentvolumeclaims: "20" # 最多 20 个 PVC
# ====== 存储 ======
requests.storage: 500Gi # 所有 PVC 申请总量上限
# 指定 StorageClass 的配额
alicloud-disk-ssd.storageclass.storage.k8s.io/requests.storage: 200Gi
# ====== 服务类型限制 ======
services.loadbalancers: "3" # 最多 3 个 LoadBalancer Service(费钱)
services.nodeports: "0" # 禁止 NodePort(安全要求)
# 查看配额使用情况
kubectl describe resourcequota backend-quota -n prod-backend
# Name: backend-quota
# Namespace: prod-backend
# Resource Used Hard
# -------- ---- ----
# limits.cpu 8 40
# limits.memory 16Gi 80Gi
# pods 23 100
# requests.cpu 4 20
# requests.memory 8Gi 40Gi
# 超出配额时会报错
# Error from server (Forbidden): pods "myapp" is forbidden:
# exceeded quota: backend-quota, requested: requests.cpu=4,
# used: requests.cpu=18, limited: requests.cpu=20
多级配额(QoS 类别限制)
# 限制各 QoS 类别的 Pod 数量
apiVersion: v1
kind: ResourceQuota
metadata:
name: pod-qos-quota
namespace: prod-backend
spec:
hard:
# BestEffort 类 Pod(没有设置 requests/limits 的 Pod)禁止运行
# 生产环境必须设置资源限制
count/pods.bestEffort: "0"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["low-priority"] # 只限制低优先级 Pod
三、LimitRange:自动注入默认资源限制
ResourceQuota 要求 Pod 必须有 requests/limits,但开发者可能忘记写。LimitRange 设置默认值和最大/最小值。
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: prod-backend
spec:
limits:
# ====== Container 级别限制 ======
- type: Container
# 默认值(用户没写 requests/limits 时自动注入)
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
# 最大值(用户设置超过此值则拒绝)
max:
cpu: "8"
memory: 16Gi
# 最小值(用户设置低于此值则拒绝)
min:
cpu: 10m
memory: 32Mi
# 最大/最小比(防止 limits 远大于 requests,造成资源浪费)
maxLimitRequestRatio:
cpu: "10" # limits.cpu 不能超过 requests.cpu 的 10 倍
memory: "4" # limits.memory 不能超过 requests.memory 的 4 倍
# ====== Pod 级别限制 ======
- type: Pod
max:
cpu: "16" # 单个 Pod 最多使用 16 核
memory: 32Gi
# ====== PVC 存储限制 ======
- type: PersistentVolumeClaim
max:
storage: 100Gi # 单个 PVC 最大 100GB
min:
storage: 1Gi
# 验证 LimitRange 生效
# 创建一个没有设置 resources 的 Pod
kubectl run test --image=nginx -n prod-backend
kubectl get pod test -n prod-backend -o jsonpath='{.spec.containers[0].resources}'
# {"limits":{"cpu":"500m","memory":"512Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}
# 自动注入了默认值
四、NetworkPolicy:租户网络隔离
默认情况下,K8s 所有 Pod 可以互相通信。NetworkPolicy 实现网络层隔离(需要支持 NetworkPolicy 的 CNI,如 Cilium、Calico)。
# 默认拒绝所有入流量(白名单模式)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: prod-backend
spec:
podSelector: {} # 匹配所有 Pod
policyTypes:
- Ingress # 只影响入流量
---
# 只允许来自 frontend 命名空间的流量(以及 monitoring 的采集)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-and-monitoring
namespace: prod-backend
spec:
podSelector:
matchLabels:
app: api-server # 只影响 api-server Pod
policyTypes:
- Ingress
ingress:
# 允许 prod-frontend 命名空间的流量
- from:
- namespaceSelector:
matchLabels:
team: frontend
env: production
ports:
- protocol: TCP
port: 8080
# 允许 monitoring 采集 metrics
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090 # Prometheus metrics 端口
# 禁止 Pod 访问集群外部(出口白名单)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-egress
namespace: prod-backend
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# 允许访问 DNS(K8s 内部通信必需)
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
# 允许访问数据库命名空间
- to:
- namespaceSelector:
matchLabels:
team: data
# 允许访问特定外部 IP(如外部数据库、第三方 API)
- to:
- ipBlock:
cidr: 10.0.0.0/8 # 内网
- ipBlock:
cidr: 203.0.113.5/32 # 特定外部 IP
五、完整多租户模板(一键初始化)
#!/bin/bash
# 初始化新租户命名空间的脚本
# 用法:./init-tenant.sh <team-name> <environment> <cpu-limit> <memory-limit>
TEAM=$1 # e.g. backend
ENV=$2 # e.g. prod
CPU_LIMIT=$3 # e.g. 20
MEM_LIMIT=$4 # e.g. 40Gi
NAMESPACE="${ENV}-${TEAM}"
echo "Creating tenant namespace: $NAMESPACE"
# 1. 创建 Namespace
kubectl create namespace $NAMESPACE
kubectl label namespace $NAMESPACE env=$ENV team=$TEAM
# 2. 创建 ResourceQuota
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: ${TEAM}-quota
namespace: $NAMESPACE
spec:
hard:
requests.cpu: "$((CPU_LIMIT/2))"
requests.memory: "$(echo $MEM_LIMIT | sed 's/Gi//')/2Gi"
limits.cpu: "$CPU_LIMIT"
limits.memory: "$MEM_LIMIT"
pods: "100"
services: "20"
persistentvolumeclaims: "20"
requests.storage: 500Gi
services.loadbalancers: "2"
services.nodeports: "0"
EOF
# 3. 创建 LimitRange
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: $NAMESPACE
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "4"
memory: 8Gi
min:
cpu: 10m
memory: 32Mi
EOF
# 4. 创建 ServiceAccount + RBAC(开发者权限)
kubectl create serviceaccount ${TEAM}-developer -n $NAMESPACE
kubectl create rolebinding ${TEAM}-developer-binding \
--clusterrole=namespace-admin \
--serviceaccount=${NAMESPACE}:${TEAM}-developer \
--namespace=$NAMESPACE
# 5. 创建默认 NetworkPolicy(隔离)
cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: $NAMESPACE
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
EOF
echo "Tenant $NAMESPACE initialized successfully!"
六、配额监控与告警
# 查看所有命名空间的配额使用率
kubectl get resourcequota -A -o custom-columns=\
"NAMESPACE:.metadata.namespace,\
QUOTA:.metadata.name,\
CPU_USED:.status.used['requests\.cpu'],\
CPU_HARD:.status.hard['requests\.cpu'],\
MEM_USED:.status.used['requests\.memory'],\
MEM_HARD:.status.hard['requests\.memory']"
# Prometheus 采集配额指标(metrics-server + kube-state-metrics)
# 关键指标:
# kube_resourcequota{resource="requests.cpu",type="used"} /
# kube_resourcequota{resource="requests.cpu",type="hard"} > 0.85
# 当配额使用率超过 85% 时告警
# Grafana Dashboard 推荐:
# - Namespace 资源使用总览
# - 配额使用率趋势(接近 100% 提前预警)
# - 被配额拒绝的请求数量(events 中 FailedScheduling)
多租户设计要点
配额设置: ResourceQuota 的 requests 设置为预期平均用量的 2 倍,limits 设置为峰值用量的 1.5 倍,留有余量但防止无限增长。
LimitRange 是 ResourceQuota 的前提: 如果没有 LimitRange 设置默认值,Pod 没有设置 requests/limits 时,ResourceQuota 中的 requests.cpu 等配额会因为 Pod 没有 requests 而无法统计,导致实际资源无限制。
NetworkPolicy 建议白名单模式: 先 default-deny-all,再逐条开放需要的通信路径。这虽然初期配置工作量大,但安全性远高于黑名单模式。
告警阈值: 配额使用率 80% 发 Warning,90% 发 Critical,给团队留出时间申请扩容或优化资源用量。
