ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

【Kubernetes从入门到精通】第32篇:ResourceQuota——多团队共享集群的“公平秤“

【Kubernetes从入门到精通】第32篇:ResourceQuota——多团队共享集群的“公平秤“ 上一篇【第31篇】LimitRange——给你的Namespace画个“圈“下一篇【第33篇】Pod生命周期全解——从Pending到Terminating的每一步摘要上篇LimitRange解决了单个Pod不能太离谱的问题但新问题来了就算每个Pod都规规矩矩地配了500m CPU和512Mi内存一个团队可以创建100个这样的Pod啊团队A不小心创建了200个Pod团队B的Pod就调度不下了——这就是公地悲剧。ResourceQuota就是来管这事的。它作用在Namespace级别给整个Namespace设资源上限——你们团队总共只能用20核CPU、40Gi内存、最多50个Pod。超过配额拒绝创建。而且它不光管计算资源requests/limits的CPU和内存还能管对象数量——这个Namespace最多创建10个Service、5个Ingress、3个PVC。本文把ResourceQuota的两种配额掰碎讲清楚带你看Scope作用域的精妙之处最后用工ResourceQuotaLimitRange的组合拳实现按团队划分资源池——团队A分12核24Gi团队B分8核16Gi各玩各的互不抢。一、ResourceQuota vs LimitRange——“总面积vs房间标准”1.1 两者的作用域对比【ResourceQuota vs LimitRange——一个管总量一个管个体】 公寓楼比喻 ┌─────────────────────────────────────────────────────────┐ │ │ │ LimitRange 房间装修标准 │ │ ┌────────────────────────────────────────────┐ │ │ │ 每间房的面积必须在 20-50 平米之间 │ │ │ │ 每间房的层高不能超过 3 米 │ │ │ │ 如果没标注面积默认30平米 │ │ │ └────────────────────────────────────────────┘ │ │ │ │ ResourceQuota 整层楼的总面积上限 │ │ ┌────────────────────────────────────────────┐ │ │ │ 这层楼的总面积不能超过 500 平米 │ │ │ │ 这层楼最多住 20 个租户 │ │ │ │ 这层楼最多 5 个独立卫生间 │ │ │ └────────────────────────────────────────────┘ │ │ │ │ 两者配合 │ │ ┌────────────────────────────────────────────┐ │ │ │ LimitRange 保证每间房不会太大或太小 │ │ │ │ ResourceQuota 保证整层楼的使用不超过上限 │ │ │ │ → 不管租户怎么装修总面积就是500平米 │ │ │ └────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘特性LimitRangeResourceQuota作用范围单个Pod/Container/PVC整个Namespace管什么个体资源的上下限/默认值资源总和上限约束CPU/内存的 min/max/defaultCPU/内存的requests/limits总和额外能力自动填充默认值限制对象数量Pod/Service等生效时机创建Pod时创建任何资源时类比房间的施工标准整层楼的面积上限二、ResouceQuota的两种配额类型2.1 计算资源配额——“你们团队总共能用多少CPU/内存”apiVersion:v1kind:ResourceQuotametadata:name:team-a-quotanamespace:team-aspec:hard:# # 计算资源配额——requests# requests.cpu:12# 所有Pod的CPU requests总和 ≤ 12核requests.memory:24Gi# 所有Pod的内存requests总和 ≤ 24Gi# # 计算资源配额——limits# limits.cpu:24# 所有Pod的CPU limits总和 ≤ 24核limits.memory:48Gi# 所有Pod的内存limits总和 ≤ 48Gi# # 对象数量配额# count/pods:30# 最多30个Podcount/services:10# 最多10个Servicecount/services.nodeports:2# 最多2个NodePort Servicecount/secrets:20# 最多20个Secretcount/configmaps:30# 最多30个ConfigMapcount/persistentvolumeclaims:5# 最多5个PVCcount/deployments.apps:15# 最多15个Deploymentcount/ingresses.networking.k8s.io:3# 最多3个Ingresscount/jobs.batch:10# 最多10个Job# # 存储配额# requests.storage:100Gi# 所有PVC的存储requests总和 ≤ 100Gi# 特定StorageClass的配额fast-ssd.storageclass.storage.k8s.io/requests.storage:50Gi# SSD类型的PVC总和不超过50Gi# # 扩展资源配额如GPU# requests.nvidia.com/gpu:4# 最多请求4块GPUlimits.nvidia.com/gpu:4# 最多限制4块GPU【计算资源配额——requests和limits各算各的】 名称格式 动作.资源 ┌────────────────────────────────────────────┐ │ │ │ requests.cpu 所有Pod cpu.requests 的和 │ │ requests.memory 所有Pod mem.requests 的和 │ │ limits.cpu 所有Pod cpu.limits 的和 │ │ limits.memory 所有Pod mem.limits 的和 │ │ │ │ 注意requests 和 limits 是独立计算的 │ │ requests 用完不影响 limits 余额 │ │ limits 用完不影响 requests 余额 │ │ │ │ 举例 │ │ requests.cpu: 10, limits.cpu: 20 │ │ 创建 Pod (requests2, limits4) │ │ → requests 剩余: 10-28 │ │ → limits 剩余: 20-416 │ │ 两个池子独立互不干扰 │ └────────────────────────────────────────────┘2.2 对象数量配额——“不光是资源数量也有限”apiVersion:v1kind:ResourceQuotametadata:name:object-countsnamespace:team-aspec:hard:# 常用对象数量限制count/pods:50# 最多50个Podcount/services:20# 最多20个Servicecount/configmaps:50# 最多50个ConfigMapcount/secrets:30# 最多30个Secretcount/persistentvolumeclaims:10# 最多10个PVC# 特定类型的Servicecount/services.loadbalancers:1# 最多1个LoadBalancer贵count/services.nodeports:3# 最多3个NodePort端口范围有限# 工作负载对象count/deployments.apps:20# 最多20个Deploymentcount/statefulsets.apps:5# 最多5个StatefulSetcount/jobs.batch:20# 最多20个Job包含已完成运行中count/cronjobs.batch:5# 最多5个CronJob# 创建后验证kubectl apply-fteam-a-quota.yaml# 查看所有ResourceQuotakubectl get resourcequota-nteam-a# NAME AGE REQUEST LIMIT# team-a-quota 5m requests.cpu: 0/12, requests.memory: 0/24Gi limits.cpu: 0/24# 查看详细使用情况kubectl describe resourcequota team-a-quota-nteam-a# Name: team-a-quota# Namespace: team-a# Resource Used Hard# -------- ---- ----# limits.cpu 5 24 ← 已用5核/总共24核# limits.memory 10Gi 48Gi# requests.cpu 3 12# requests.memory 6Gi 24Gi# count/pods 8 30# count/services 3 10要点对象数量配额里count/pods包括所有状态的Pod——Running、Pending甚至Completed的Job Pod。如果你的Job创建了大量Completed Pod后没清理它们会一直占用count/pods配额导致新Pod创建失败。所以记得给Job设ttlSecondsAfterFinished自动清理。三、Scope作用域——“限制更精准”3.1 四种Scope——“我只管某一类资源”【Scope 作用域——不是所有Pod都算在内】 ┌─────────────────────────────────────────────────────────┐ │ │ │ Terminating vs NotTerminating │ │ ┌───────────────────────────────────────────────┐ │ │ │ Terminating: 只统计 activeDeadlineSeconds 0 │ │ │ │ 的Pod即Job/定时任务Pod │ │ │ │ NotTerminating: 只统计没有设activeDeadline的 │ │ │ │ Pod即长期运行的服务Pod │ │ │ │ │ │ │ │ 举个例子 │ │ │ │ 你希望团队最多10个长期Pod 不限量临时Job Pod │ │ │ │ → 两条独立QuotaNotTerminating10, │ │ │ │ Terminating不限 │ │ │ └───────────────────────────────────────────────┘ │ │ │ │ BestEffort vs NotBestEffort │ │ ┌───────────────────────────────────────────────┐ │ │ │ BestEffort: 只统计BestEffort QoS的Pod │ │ │ │ NotBestEffort: 只统计Burstable或Guaranteed的 │ │ │ │ Pod即至少配了requests的 │ │ │ │ │ │ │ │ 举个例子 │ │ │ │ 你希望核心服务都用Guaranteed QoS │ │ │ │ → BestEffort: 0禁止创建不配资源的Pod │ │ │ └───────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘3.2 Scope实战——“禁止BestEffort Pod给长期服务单独配额”apiVersion:v1kind:ResourceQuotametadata:name:production-quotanamespace:productionspec:# 硬性要求所有统计都是按Scope过滤的hard:# Scope 1: 只对长期服务PodNotTerminating生效requests.cpu:10requests.memory:20Gilimits.cpu:20limits.memory:40Gicount/pods:20scopeSelector:matchExpressions:-operator:InscopeName:NotTerminating# ← 只统计服务Pod# Job Pod也算requests但不计入这个Quota---apiVersion:v1kind:ResourceQuotametadata:name:besteffort-bannamespace:productionspec:hard:count/pods:0# ← 0直接禁止scopeSelector:matchExpressions:-operator:InscopeName:BestEffort# ← 只对BestEffort Pod生效# 效果谁创建没配resources的Pod直接拒绝# 测试创建BestEffort Pod——被拒kubectl apply-nproduction-f-EOF apiVersion: v1 kind: Pod metadata: name: no-resources spec: containers: - name: nginx image: nginx # 没配resources → BestEffort EOF# Error: pods no-resources is forbidden:# exceeded quota: besteffort-ban, requested: count/pods1,# used: count/pods0, limited: count/pods0要点用Scope禁止BestEffort是生产环境的标配操作——你可以在ResourceQuota里加一条scopeName: BestEffort, count/pods: 0确保团队里没有人能创建没配resources的Pod。加上上一节的LimitRange自动补默认值双保险——从源头杜绝BestEffort。3.3 四种Scope详解表格Scope匹配的Pod典型用途Terminating设了activeDeadlineSeconds的PodJob Pod给批处理任务单独配额不跟Web服务抢NotTerminating没设activeDeadlineSeconds的Pod服务Pod给长期运行的服务设配额BestEffort没有任何resources的Pod禁止BestEffort Pod设为0NotBestEffort至少配了requests或limits的Pod只对有资源配置的Pod设配额PriorityClass指定优先级的Pod如high-priority给不同优先级的Pod分别配额四、实战——ResourceQuota LimitRange组合拳4.1 按团队划分资源池【多团队资源池规划——5台Node总计20C/64Gi】 集群物理资源 ┌─────────────────────────────────────────────────────────┐ │ Node-1: 4C/16Gi Node-2: 4C/16Gi Node-3: 4C/16Gi │ │ Node-4: 4C/16Gi Node-5: 4C/16Gi │ │ │ │ 可分配总量20C CPU / 64Gi 内存 │ └─────────────────────────────────────────────────────────┘ 资源分配计划 ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │ 团队 │ CPURq │ MemRq │ CPULim │ MemLim │ Pod上限 │ ├──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤ │ team-a │ 8核 │ 20Gi │ 12核 │ 30Gi │ 40 │ │ (核心) │ │ │ │ │ │ ├──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤ │ team-b │ 6核 │ 16Gi │ 10核 │ 24Gi │ 30 │ │ (业务) │ │ │ │ │ │ ├──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤ │ team-c │ 3核 │ 8Gi │ 6核 │ 12Gi │ 20 │ │ (数据) │ │ │ │ │ │ ├──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤ │ 系统 │ 3核 │ 20Gi │ 12核 │ 30Gi │ — │ │ (预留) │ │ │ │ │ │ ├──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤ │ 合计 │ 20核 │ 64Gi │ 40核 │ 96Gi │ — │ └──────────┴──────────┴──────────┴──────────┴──────────┴─────────┘4.2 完整实现——一个团队一个保险柜# # team-a: ResourceQuota LimitRange 组合# # 1. ResourceQuota——总量控制apiVersion:v1kind:ResourceQuotametadata:name:team-a-quotanamespace:team-aspec:hard:# 计算资源requests.cpu:8requests.memory:20Gilimits.cpu:12limits.memory:30Gi# 对象数量count/pods:40count/services:15count/services.nodeports:2# NodePort有限省着用count/configmaps:30count/secrets:20count/persistentvolumeclaims:10# 存储requests.storage:200Gi---# 2. LimitRange——质量规范apiVersion:v1kind:LimitRangemetadata:name:team-a-limitsnamespace:team-aspec:limits:-type:Containermin:cpu:100mmemory:128Mimax:cpu:2000m# 单个容器最多2核memory:8Gidefault:cpu:500mmemory:512MidefaultRequest:cpu:200mmemory:256MimaxLimitRequestRatio:cpu:2memory:1.5---# 3. 禁止BestEffortapiVersion:v1kind:ResourceQuotametadata:name:team-a-no-besteffortnamespace:team-aspec:hard:count/pods:0scopeSelector:matchExpressions:-operator:InscopeName:BestEffort# # team-b: ResourceQuota LimitRange 组合# apiVersion:v1kind:ResourceQuotametadata:name:team-b-quotanamespace:team-bspec:hard:requests.cpu:6requests.memory:16Gilimits.cpu:10limits.memory:24Gicount/pods:30count/services:10count/persistentvolumeclaims:8---apiVersion:v1kind:LimitRangemetadata:name:team-b-limitsnamespace:team-bspec:limits:-type:Containermin:cpu:50mmemory:64Mimax:cpu:2000mmemory:8Gidefault:cpu:500mmemory:512MidefaultRequest:cpu:200mmemory:256MimaxLimitRequestRatio:cpu:3memory:2# 查看各团队资源使用情况汇总echo Resource Usage Summary fornsinteam-a team-b team-c;doechoecho--- Namespace:$ns---kubectl describe resourcequota-n$ns2/dev/null|grep-EName:|Resource|Used|Harddone# 输出示例# --- Namespace: team-a ---# Name: team-a-quota# Resource Used Hard# limits.cpu 6 12# limits.memory 15Gi 30Gi# requests.cpu 3 8# requests.memory 8Gi 20Gi# count/pods 12 40# --- Namespace: team-b ---# Name: team-b-quota# Resource Used Hard# limits.cpu 4 10# ...4.3 配额超限时的表现# 模拟team-a配额用满# 假设team-a的requests.cpu已用到7.8核配额8核# 尝试创建一个request为500m的Podkubectl apply-nteam-a-f-EOF apiVersion: v1 kind: Pod metadata: name: new-app spec: containers: - name: nginx image: nginx resources: requests: cpu: 500m # 7.8 0.5 8.3 8 → 超了 memory: 256Mi EOF# 结果Pod创建失败# Error from server (Forbidden): error when creating STDIN:# pods new-app is forbidden: exceeded quota: team-a-quota,# requested: requests.cpu500m, used: requests.cpu7800m,# limited: requests.cpu8# 查看ReplicaSet/DaemonSet里的Pending Podkubectl get events-nteam-a --field-selectorreasonFailedCreate# 会看到类似 exceeded quota 的事件要点ResourceQuota配额超限时API Server直接拒绝创建——不是Pending是直接403 Forbidden。这意味着你的Deployment期望replicas5但由于配额不够只创建了3个ReplicaSet Controller会不断重试创建那2个失败的Pod——Events里会刷屏exceeded quota。这时候要么加配额要么减少副本数。五、ResourceQuota常用排错# 查看配额使用情况kubectl describe resourcequota-nteam-a# 找出哪些Pod占用了配额kubectl get pods-nteam-a-ocustom-columns\NAME:.metadata.name,\CPU_REQ:.spec.containers[*].resources.requests.cpu,\MEM_REQ:.spec.containers[*].resources.requests.memory,\CPU_LIM:.spec.containers[*].resources.limits.cpu,\MEM_LIM:.spec.containers[*].resources.limits.memory# 按CPU requests排序找大头kubectl get pods-nteam-a-ojson|jq-r .items[] | \(.metadata.name) \( (.spec.containers[].resources.requests.cpu // 0) )|sort-k2-r# 注意终止中的PodTerminating仍然占用配额# 如果Pod卡在Terminating配额被占着不放kubectl get pods-nteam-a --field-selectorstatus.phaseTerminating# → 如果发现僵尸Pod用 --force --grace-period0 删除# 更新ResourceQuotakubectl edit resourcequota team-a-quota-nteam-a# 或者patchkubectl patch resourcequota team-a-quota-nteam-a\--patch{spec:{hard:{requests.cpu:10}}}本篇小结ResourceQuota是集群级别的公平秤确保每个团队不会吃掉别人的资源管两类额度计算资源总量requests/limits的CPU和内存总和 对象数量Pod/Service/ConfigMap/PVC等最多多少个requests和limits独立计算——两个池子互不干扰用完一个不影响另一个Scope作用域让限制更精准——可以只限长期服务Pod、禁止BestEffort、给不同优先级分别配额ResourceQuota LimitRange 组合拳——LimitRange管每个Pod怎么配ResourceQuota管全Namespace能用多少配额超限直接拒绝——不是Pending是API Server直接403需要扩容配额或减少资源消耗至此咱们把资源管理的三件套Requests/Limits → QoS → LimitRange → ResourceQuota都聊完了——从单个Pod到全集群都有了规矩。下一篇切换视角看看Pod自己的一生——从Pending到Terminating的每一步Init容器、生命周期钩子这些细节。上一篇【第31篇】LimitRange——给你的Namespace画个“圈“下一篇【第33篇】Pod生命周期全解——从Pending到Terminating的每一步
返回列表