4. ResourceQuota实战

ResourceQuota 是 OpenShift 中作用于 Namespace 级别的资源总量约束对象。它和 LimitRange 的分工需要先厘清:LimitRange 管的是“单个 Pod 或容器默认给多少、最多给多少”,而 ResourceQuota 管的是“整个 Namespace 里所有对象加起来最多能用多少”。两者配合使用,才能既约束单点又约束总量。本节围绕一个名为 team-alpha 的 Namespace,完整走一遍配额定义、生效验证、超限行为和调整流程。

一、配额对象与约束维度

ResourceQuota 的约束分为两类。第一类是计算资源配额,如 requests.cpu、limits.cpu、requests.memory、limits.memory,它们统计的是 Namespace 内所有 Pod 的 requests/limits 之和。第二类是对象数量配额,如 pods、services、persistentvolumeclaims、configmaps、secrets 等,统计的是对象个数。

有一个关键前提:一旦 Namespace 中存在带 requests.cpu 或 limits.cpu 的 ResourceQuota,之后创建的 Pod 就必须显式声明对应的 requests/limits,否则会被拒绝。这是新手最容易踩的坑——配额不是“超了才拦”,而是“没声明就不让建”。

team-alpha Namespace 配额约束全景 Namespace: team-alpha ResourceQuota: team-alpha-quota requests.cpu: 4 requests.memory: 8Gi limits.cpu: 8 limits.memory: 16Gi pods: 20 services: 5 persistentvolumeclaims: 4 当前已用(示例) requests.cpu: 2.5 / 4 requests.memory: 5Gi / 8Gi limits.cpu: 5 / 8 limits.memory: 10Gi / 16Gi pods: 8 / 20 services: 2 / 5 pvc: 1 / 4 Pod × 8 含 requests/limits Service × 2 ClusterIP / NodePort PVC × 1 10Gi RWO ConfigMap 未设配额 统计

二、编写并应用配额

先创建 Namespace,再定义 ResourceQuota。以下 YAML 是本节使用的完整示例:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"
    services: "5"
    persistentvolumeclaims: "4"

应用后查看配额状态:

oc apply -f team-alpha-quota.yaml
oc describe resourcequota team-alpha-quota -n team-alpha

describe 输出中会同时列出 Resource、Used、Hard 三列。刚创建时 Used 全为 0,Hard 即上面定义的值。这个 Used 是实时统计的,每次创建或删除对象都会刷新。

三、验证配额生效

验证分两步。第一步,创建一个未声明 requests/limits 的 Pod,观察是否被拒绝:

oc run test-nolimit --image=registry.access.redhat.com/ubi9/ubi-minimal \
  --restart=Never -n team-alpha

预期返回类似 Error from server (Forbidden): pods "test-nolimit" is forbidden: failed quota: team-alpha-quota: must specify limits.cpu,limits.memory,requests.cpu,requests.memory。这说明配额已生效,且强制要求声明资源。

第二步,创建一个声明了资源但会超限的 Pod。假设当前 requests.cpu 已用 2.5,剩余 1.5,我们申请 2:

apiVersion: v1
kind: Pod
metadata:
  name: test-over
  namespace: team-alpha
spec:
  containers:
  - name: app
    image: registry.access.redhat.com/ubi9/ubi-minimal
    command: ["sleep", "3600"]
    resources:
      requests:
        cpu: "2"
        memory: 2Gi
      limits:
        cpu: "2"
        memory: 4Gi

提交后会被拒绝,错误信息形如 exceeded quota: team-alpha-quota, requested: requests.cpu=2, used: requests.cpu=2500m, limited: requests.cpu=4。注意这里报的是“请求量 + 已用量 > 硬限制”,而不是“单个 Pod 太大”。

配额校验发生在 API Server 准入阶段,Pod 对象根本不会写入 etcd,因此不会出现“创建了但调度失败”的中间状态。这与节点资源不足导致的 Pending 是两回事。

四、超限行为与常见误区

超限行为可以归纳为三点:

  • 创建即拒绝:无论是 Pod、Service 还是 PVC,只要新增后总量超过 hard 值,API Server 直接返回 403 Forbidden。
  • 已存在对象不受影响:调小配额不会驱逐已有 Pod,但会导致后续无法新建,直到用量降到新配额以下。
  • 更新也可能被拦:如果修改已有 Pod 的 requests 使其总量超限,同样会被拒绝。

常见误区是认为“配额只对新建生效,改改就行”。实际上,如果 Namespace 已有配额且你删掉了某个 Pod 的 resources 字段,更新操作也会因“must specify”被拒绝。因此配额一旦启用,所有工作负载模板都必须带上资源声明。

五、配额调整流程

调整配额不是简单改数字,需要先评估再执行。推荐流程如下:

  1. 用 oc describe resourcequota -n team-alpha 查看当前 Used 与 Hard 的差距。
  2. 确认要调整的维度,例如把 requests.cpu 从 4 提到 6。
  3. 直接 oc edit resourcequota team-alpha-quota -n team-alpha 或重新 apply 修改后的 YAML。
  4. 再次 describe,确认 Hard 已更新且 Used 不变。
  5. 尝试创建之前被拒绝的 Pod,验证新配额下能否成功。

需要注意:调大配额通常立即生效;调小配额时,如果当前 Used 已高于新 Hard,配额对象本身可以保存成功,但 Namespace 会处于“超配额”状态,任何新建操作都会被拒绝,直到用量自然下降。因此调小前务必确认现有用量。

不要用删除再重建 ResourceQuota 的方式调整配额。删除配额对象的瞬间,Namespace 会短暂失去约束,可能被其他控制器或用户趁机创建大量对象,重建后直接处于超限状态。

六、可直接使用的配额检查清单

下表可作为日常运维时的快速核对表,字段均对应真实配额维度:

检查项命令 / 观察点判断标准
配额是否存在oc get resourcequota -n <ns>至少一条记录
CPU/内存用量oc describe resourcequotaUsed < Hard,留有余量
Pod 数量同上,看 pods 行Used 接近 Hard 时预警
Service 数量同上,看 services 行避免因配额阻塞发布
PVC 数量同上,看 persistentvolumeclaims 行结合存储容量规划
工作负载是否声明资源抽查 Deployment/Pod YAML必须含 requests 与 limits

把这张清单固化到 CI 流水线或命名空间开通流程中,可以在对象创建前就发现配额风险,而不是等到发布失败才排查。ResourceQuota 的价值不在于“限制”,而在于让 Namespace 的资源账目始终清晰可查、可预期。