bigywater.tech
Kubernetes · 41

ResourceQuota:超额创建被拒绝的时机

命名空间的资源总量上限是怎么执行的?超了会在哪一步失败?为什么 Deployment 看起来创建成功了 Pod 却起不来?这篇用一个 ResourceQuota 把记账、拒绝点、与 LimitRange 的搭配、对象数量配额和 scope 范围都量了一遍。

exceeded quota
超额请求被拒绝的原因,写明 requested、used、limited 三个数字
READY 2/5
replicas=5 的 Deployment 在 pods 配额还剩 2 个时的状态
{pods: 1}
scopes: [BestEffort] 的配额在有 1 个 BestEffort 和 1 个 Burstable Pod 时的用量

配额怎么记账

实测 · 本机执行输出
  ResourceQuota q(pods 3、requests.cpu 1、limits.cpu 2、requests.memory 1Gi、limits.memory 1Gi、count/configmaps 4)刚创建:count/configmaps=1/4, limits.cpu=0/2, limits.memory=0/1Gi, pods=0/3, requests.cpu=0/1, requests.memory=0/1Gi
  创建 p1(requests cpu 400m / memory 200Mi,limits cpu 500m / memory 300Mi)之后:count/configmaps=1/4, limits.cpu=500m/2, limits.memory=300Mi/1Gi, pods=1/3, requests.cpu=400m/1, requests.memory=200Mi/1Gi
  创建 p2(requests cpu 400m / memory 200Mi,limits cpu 500m / memory 300Mi)之后:count/configmaps=1/4, limits.cpu=1/2, limits.memory=600Mi/1Gi, pods=2/3, requests.cpu=800m/1, requests.memory=400Mi/1Gi

ResourceQuota 对每种资源分别记账。创建 p1(requests cpu 400m / memory 200Mi,limits cpu 500m / memory 300Mi)之后,status.used 里 pods=1/3、requests.cpu=400m/1、limits.cpu=500m/2;再创建 p2,requests.cpu 到 800m、limits.memory 到 600Mi。用量在创建那一刻就更新。count/configmaps 这种写法可以给任何命名空间级资源按个数计数。

超了在哪一步失败

实测 · 本机执行输出
  第 3 个同样的 Pod(requests.cpu 会变成 1200m,超过 1):退出码 1;Error from server (Forbidden): error when creating "STDIN": pods "p3" is forbidden: exceeded quota: q, requested: requests.cpu=400m, used: requests.cpu=800m, limited: requests.cpu=1
  换一个小的(100m / 50Mi,第 3 个 Pod):退出码 0;pod/s1 created;count/configmaps=1/4, limits.cpu=1100m/2, limits.memory=650Mi/1Gi, pods=3/3, requests.cpu=900m/1, requests.memory=450Mi/1Gi
  再来一个小的(第 4 个 Pod,pods 已经 3/3):退出码 1;Error from server (Forbidden): error when creating "STDIN": pods "s2" is forbidden: exceeded quota: q, requested: pods=1, used: pods=3, limited: pods=3
  用 Deployment 创建时,Deployment 本身是创建成功的,被拒绝的是它的 ReplicaSet 去创建 Pod 的那一步:
    kubectl get deploy web:web    2/5     2            2           8s
    ReplicaSet 的 FailedCreate 事件:Error creating: pods "web-7c4988568c-wqdnl" is forbidden: exceeded quota: q, requested: pods=1, used: pods=3, limited: pods=3
    配额:count/configmaps=1/4, limits.cpu=300m/2, limits.memory=150Mi/1Gi, pods=3/3, requests.cpu=300m/1, requests.memory=150Mi/1Gi

准入阶段、创建对象的那个请求被拒绝:第 3 个 400m 的 Pod 报 exceeded quota: q, requested: requests.cpu=400m, used: requests.cpu=800m, limited: requests.cpu=1,小 Pod 能放进去直到 pods=3/3,再多一个报 requested: pods=1, used: pods=3, limited: pods=3。用 Deployment 时,Deployment 本身创建成功,失败的是它的 ReplicaSet 去创建 Pod 那一步:kubectl get deploy 显示 2/5,原因要看 ReplicaSet 的 FailedCreate 事件。

必须写明资源

实测 · 本机执行输出
  什么都没写的 Pod:退出码 1;Error from server (Forbidden): error when creating "STDIN": pods "naked" is forbidden: failed quota: q: must specify limits.cpu for: c; limits.memory for: c; requests.cpu for: c; requests.memory for: c
  同命名空间加了一个 LimitRange(补默认值)之后同一个 Pod:退出码 0;pod/naked created;count/configmaps=1/4, limits.cpu=300m/2, limits.memory=150Mi/1Gi, pods=2/3, requests.cpu=200m/1, requests.memory=100Mi/1Gi

配额里管着 requests / limits 的时候,没写这些字段的 Pod 直接被拒:failed quota: q: must specify limits.cpu for: c; limits.memory for: c; requests.cpu for: c; requests.memory for: c。同命名空间加一个 LimitRange 补默认值,同一个 Pod 就能创建,并且按补完的值记账。ResourceQuota 管总量,LimitRange 管单个对象和默认值,常常成对使用。

数量与范围

实测 · 本机执行输出
  count/configmaps 上限 4:命名空间里原有 kube-root-ca.crt,c0~c4 里成功创建了 3 个;count/configmaps=4/4, limits.cpu=100m/2, limits.memory=50Mi/1Gi, pods=1/3, requests.cpu=100m/1, requests.memory=50Mi/1Gi
    再建一个:error: failed to create configmap: configmaps "one-more" is forbidden: exceeded quota: q, requested: count/configmaps=1, used: count/configmaps=4, limited: count/configmaps=4
  另一个命名空间里 scopes: [BestEffort]、pods: 1 的配额:第 1 个 BestEffort Pod 成功;第 2 个:退出码 1;Error from server (Forbidden): error when creating "STDIN": pods "be2" is forbidden: exceeded quota: be, requested: pods=1, used: pods=1, limited: pods=1
    Burstable 的 Pod 不受这个配额管:退出码 0;pod/bu1 created
    配额 be 的用量:{"pods":"1"}(只数了 BestEffort 的那一个)
  删除 be1 之后 be 的用量:{"pods":"0"}

count/configmaps: 4 在命名空间里已有 kube-root-ca.crt 加 3 个之后拒绝第 5 个。scopes: [BestEffort] 让配额只统计 BestEffort 的 Pod:第 1 个 BestEffort Pod 通过,第 2 个被拒,Burstable 的 Pod 不受影响,status.used 只是 {pods: 1};删掉 Pod 之后 used 立刻回到 0。

分步演示

ResourceQuota 记账
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);命名空间 k35 里的 ResourceQuota q:pods 3、requests.cpu 1、limits.cpu 2、requests.memory 1Gi、limits.memory 1Gi、count/configmaps 4,另在 k35b 里建 scopes: [BestEffort]、pods: 1 的配额 be(同一个命名空间里放两个配额会互相影响,第一次这样做时被另一个配额的“必须写明资源”规则干扰了,所以分开);Pod 用 busybox:1.36;用量读自 status.used;每种情形各一次
    • 没有验证:PriorityClass、Terminating / NotTerminating 等其他 scope;scopeSelector 的表达式;存储类配额(requests.storage、.storageclass.storage.k8s.io/…);配额在对象更新(如 resize)时的重新计算;配额控制器的重新同步延迟(用量更新在本实验里是即时的);超额之后已存在的对象不会被驱逐
    京ICP备2026067502号-1京公网安备11010502063487号