当集群从"几个团队共用"变成"几十个团队、几百个命名空间共存",资源就开始打架:一个团队狂拉资源把别人挤爆、错误的 requests 让调度器预判失准、节点利用率忽高忽低。多租户与资源治理的目标是:让每个团队在"自己的配额盒子里"自由运行,同时整个集群的资源被调度器高效、公平地使用。
目录
- 1. 租户边界的建立:Namespace 与资源对象
- 2. ResourceQuota:给租户划定资源上限
- 3. LimitRange:给单个 Pod/容器定范围
- 4. requests 与 limits:资源预留的双层语义
- 5. QoS 等级:Guaranteed / Burstable / BestEffort
- 6. 多租户隔离:网络、安全与命名空间治理
- 7. 层级租户:Hierarchical Namespaces 与配额罐
- 8. 资源饱和度与 descheduler 调度
- 9. 生产最佳实践与避坑
1. 租户边界的建立:Namespace 与资源
1.1 Namespace 是逻辑租户
Namespace 提供的隔离维度:
- 资源名隔离:同名 Deployment 可在不同 ns 共存
- 资源配额:ResourceQuota 按 ns 限制总量
- 权限隔离:RBAC 按 ns 授权(Role / RoleBinding)
- 网络隔离:NetworkPolicy 按 ns 生效
- 成本归属:按 ns 打标签 + 成本分析
一个生产集群的常见 ns 划分:
- platform(平台/基础设施)
- shop,payment,inventory(业务团队)
- dev / staging / prod(不同环境,若混合部署)
- 注意:把"环境"和"团队"混在一个维度会导致权限与配额纠缠
ℹ️ 原则:ns 粒度要配合"团队/产品的运维边界"。太多 ns 增加管理成本,太少无法隔离。
1.2 用标签体系支撑治理
# 为每个 ns 打标准标签,作为配额/成本/权限的统一维度
metadata:
name: payment
labels:
team: "payments-core"
env: "prod"
cost-center: "billing"
criticality: "high"
2. ResourceQuota:给租户划定资源上限
2.1 配额 CPU/内存/对象数量
apiVersion: v1
kind: ResourceQuota
metadata:
name: payment-quota
namespace: payment
spec:
hard:
requests.cpu: "8"
requests.memory: 16Gi
limits.cpu: "16"
limits.memory: 32Gi
count/pods: "100"
count/services: "20"
count/persistentvolumeclaims: "30"
ResourceQuota 会拒绝"超过配额的创建":
创建 Pod 时 requests.cpu 超了 → API 拒绝(403)
这保证了 ns 内总资源不超过配额
scopeSelector 细粒度配额:按 QoS / 阶段 / 状态:
spec.scopes及匹配 label 可以按 Pod 类型(qos 等级)单独配额
典型治理:
requests 和 limits 分开配额
→ 防止"requests 很低但 limits 拉很高"的投机
2.2 配额检查命令
kubectl get resourcequota -n payment
kubectl describe resourcequota payment-quota -n payment
# 看到已用 vs 配额,快速判断一个 ns 是否吃紧
3. LimitRange:给单个 Pod 定资源范围
3.1 为什么还要 LimitRange
ResourceQuota 管"ns 总量",LimitRange 管"单个 Pod 的边界":
- 防止某个 Pod 把配额/Slot 全占
- 没写 requests/limits 的 Pod 自动给默认值
- 约束 ratio:limit 不能是 request 的任意倍(防请求/Giant)
组合:Quota 划"总量" + LimitRange 划"单件" + QoS 定义优先级
3.2 LimitRange 配置
apiVersion: v1
kind: LimitRange
metadata:
name: payment-lr
namespace: payment
spec:
limits:
- max: # 单个 Pod 上限
cpu: "4"
memory: 8Gi
default: # 未声明时的默认 limit
cpu: "500m"
memory: 512Mi
defaultRequest: # 未声明时的默认 requests
cpu: "100m"
memory: 128Mi
type: Container
LimitRange 作用时机:Pod 创建时(Admission 阶段)
- 违反 max/min → 拒绝创建
- 未声明 requests/limits → 注入默认
→ 防止"裸奔"的 Pod 抢占,也防止限制过于宽松
4. requests 与 limits:资源预留的调度语义
4.1 requests = 调度依据,limits = 运行上限
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
requests(请求/保留):
- 调度器据此决定"放在哪个节点"(节点剩余 >= 所有 Pod requests)
- 实际运行中 requests 是被"保证"的最低值
- 例子:requests.cpu=500m 保证能拿到约半个核
limits(上限):
- 超过上限会被限制/被杀
- CPU limit:CPU 限制(不硬 kill)
- 内存 limit:超过即 OOM(内核 kill,QoS 决定谁先死)
常见认知误区:
- 只有 limits 没 requests → 调度不保护,且对钱包不利
- requests 设太高 → 节点利用率虚胖,调度挤爆
- limits 设太低 → 高峰 OOM
4.2 推荐设置策略
理想:requests 反映"稳态基准使用",limits 反映"可容忍的峰值"
- 先用 VPA 或 观察 看真实用量(prometheus 分位数)
- requests ≈ P50~P75 峰值用量(安全冗余)
- limits ≈ 1.5x ~ 2x requests(给峰值弹性)
- 保留多容器/僵尸团队的限值审评
注意:requests 太保守 → 节点利用率虚低 → Cluster Autoscaler 误判需要扩容,过早加节点。
requests 太高 → 调度器按 requests 预留,节点实际跑不满却"看起来满",利用率虚高。
5. QoS 等级:Guaranteed / Burstable / BestEffort
5.1 三个等级的判定
QoS 由 requests 与 limits 是否一致决定:
Guaranteed:
requests == limits(cpu 与 memory 都不缺)
例:requests.cpu=500m limits.cpu=500m
Burstable:
有 requests,且至少一个维度 requests != limits
BestEffort:
完全不设 requests / limits
内存不足时内核先杀谁:
BestEffort > Burstable(超配较多) > Burstable(超配较少) > Guaranteed
→ QoS 等级 = Pod 在资源紧张时的"生存优先级"
5.2 建议把关键服务设为 Guaranteed
# 关键服务:requests == limits,最稳也最贵
resources:
requests: { cpu: "1", memory: 2Gi }
limits: { cpu: "1", memory: 2Gi }
为什么关键服务用 Guaranteed:
- 内存上限确定 → 不会因兄弟 Pod 抢占被 OOM
- 调度与运行行为可预测
- 监控/排障清晰(不会因为 OOM 而"错杀")
Burstable 适合弹性批处理:可以用较高 limits、较低 requests
BestEffort 基本别用:随时可能被 OOM,且不能预测
6. 多租户隔离:网络、安全与命名空间治理
6.1 网络隔离 NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: payment-deny-all
namespace: payment
spec:
podSelector: {} # 该 ns 所有 Pod
policyTypes: [Ingress, Egress]
ingress: []
egress: []
---
# 允许来自 shop 的 80 端口入站
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: payment-allow-shop
namespace: payment
spec:
podSelector:
matchLabels: { app: api }
ingress:
- from:
- namespaceSelector:
matchLabels: { name: shop }
ports: [ { protocol: TCP, port: 8080 } ]
租户间网络隔离的原则:
- 默认拒绝(deny-all),显式放行
- 只开业务必需通道
- 依赖 CNI 支持(Calico/Cilium 都支持 NetworkPolicy)
注意:NetworkPolicy 只是"网络侧"隔离,
资源的 RuntimeClass(如 gVisor / kata-container)可做更强的运行时隔离。
6.2 权限与 RBAC 视角
租户 = 一组 namespace + 一组 RBAC 权限 + 一组配额 +
网络策略 + 成本归属标签
推荐用"租户/项目 CRD"(如 HNC,见第 7 节)统一管理这五者,
避免手写散件的 namespace/role/quota/networkpolicy。
- Role / RoleBinding 限 namespace 内权限
- 集群管理员避免 Team 随便建 Global 特权
7. 层级命名空间(HNC)与 Quota 罐
7.1 层级命名空间 Hierarchical Namespaces
apiVersion: hnc.x-k8s.io/v1alpha2
kind: SubnamespaceAnchor
metadata:
name: payments-core
namespace: org-root
spec:
hierarchicalQuota: true # 继承父级配额
HNC(sig-arch)的作用:
- 父 ns 与子 ns 建立层级(组织树)
- 配额、RBAC、策略可"继承"到子 ns
- 子 ns 创建的 quota 会汇总到父级(配额罐 Quota Pool)
- 适合"部门 → 团队 → 项目"的组织结构映射
配额罐(Quota Pool):
- 整个组织一个总池,子团队在此池内分配
- 比每个团队独立配额更易治理、防闲置
7.2 硬件隔离与软治理权衡
软隔离(默认,推荐起步):
Namespace + quota + RBAC + NetworkPolicy
→ 共享底层,成本低,管理简单
硬隔离(高安全要求):
独立集群 / 独立节点池 / RuntimeClass 沙箱 / 专用存储
→ 成本高、管理复杂,留给合规/强安全租户
决策:先软隔离,的确有安全/合规要求叠加硬隔离
8. 资源饱和度与 descheduler 调度
8.1 资源饱和与"热点节点"
调度只看 requests(创建时刻),会随时间漂移:
- 起初均衡的节点,慢慢一个被掏空、一个闲置
- 新增 Pod 又继续往空闲节点堆 → 惰性不均匀
descheduler 的作用:
- 识别"过度饱和/空转"的节点
- 触发受影响 Pod 重调度(逐驱逐到更均衡的节点)
- 需配合集群容忍短暂资源变动(除 pod PDB)
8.2 descheduler 配置
apiVersion: v1
kind: ConfigMap
metadata:
name: descheduler-policy
namespace: kube-system
data:
policy.yaml: |
apiVersion: descheduler/v1alpha2
kind: DeschedulerPolicy
strategies:
- name: "LowNodeUtilization"
params:
nodeResourceUtilizationThresholds:
thresholds:
cpu: 20
memory: 20
targetThresholds:
cpu: 60
memory: 60
# 节点 cpu<20% 视为 low,>60% 视为 high;均衡覆盖
nodeResourceUtilizationThresholds:
...
descheduler 是"被动纠偏"(不保证实时),
适合:节点负载长期失衡 / 多可用区流量不均
不适合:想即时再平衡(要等规则触发)
注意:descheduler 会驱逐 Pod → 必须配合 PDB 与 controller
9. 生产最佳实践与避坑
9.1 Checklist
□ 用 Namespace 划分租户 + 标准标签(team/env/cost)
□ 每个租户:ResourceQuota(总量)+ LimitRange(单件边界)
□ 关键服务设 Guaranteed QoS(requests==limits)
□ requests 基于真实用量度量(VPA/监控),limits 留峰值弹性
□ 默认拒绝网络 + 显式放行(NetworkPolicy)
□ RBAC 最小权限、按 ns 授权
□ 组织结构复杂 → 用 HNC 层级 + 配额罐
□ 长期负载失衡 → descheduler 自动疏通
□ 监控:quota 使用率、QoS 分布、节点饱和度、OOM 次数
9.2 常见坑
| 坑 | 现象 | 对策 |
|---|---|---|
| 只设 limits 无 requests | 调度挤爆/利用率低 | requests 设基准用量 |
| requests 虚高 | 节点放几个就满 | 用真实度量校准 |
| 无 ResourceQuota | 团队无限拉配额 | 每租户设 Quota |
| 无 LimitRange | 单 Pod 独占资源 | 设定单个 Pod 边界 |
| 关键服务 BestEffort | 高峰被 OOM | 设 Guaranteed |
| 无 NetworkPolicy | 租户相互可达 | 默认拒绝 |
| 无 descheduler | 节点长期失衡 | 引入 rebalance |
9.3 一句话原则
Quota 圈住总量,LimitRange 圈住单件,
Guaranteed 保住关键,descheduler 疏解失衡。
小结
多租户与资源治理 = 给每个团队一个"有边界、可计量、能隔离"的盒子:Namespace 划边界、ResourceQuota 圈总量、LimitRange 定单件、QoS 分优先、NetworkPolicy 隔离网络、descheduler 调平衡。落地记住五件事:Namespace 定租户 + 打标准标签、Quota+LimitRange 圈住总量与单件、requests 用真实用量校准 + 关键服务 Guaranteed、网络默认拒绝、长期失衡交给 descheduler。当每个团队都在自己清晰的配额盒子里运行,集群资源的分配才从"争抢的混沌"变成"有秩序的经济学"。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。