4. Helm Chart中声明资源配额:在templates/中编写ResourceQuota与LimitRange YAML、通过Values动态控制配额

在生产级 Kubernetes 集群中,资源配额(ResourceQuota)与限制范围(LimitRange)是保障多租户隔离与 Pod 稳定性最核心的准入控制机制。本章将演示如何在 Helm Chart 的 templates/ 目录中声明这两类资源,并通过 values.yaml 实现动态参数化,使同一套 Chart 能适配开发、测试、生产等不同环境的资源管控策略。

4.1 资源配额与限制范围的核心差异

维度 ResourceQuota LimitRange
作用范围 命名空间级别,聚合所有 Pod 的资源总和 Pod / 容器级别,约束单个 Pod 的资源上下限
主要功能 限制 CPU/内存/存储/对象数量的总量上限 设置默认 request/limit、最小/最大值
触发时机 创建/更新 Pod 时检查命名空间累计用量 创建/更新 Pod 时校验单个容器声明值
典型场景 防止单个 Namespace 耗尽集群资源 防止容器未声明资源导致调度异常
Helm 模板化 通过 .Values.quota 控制总量阈值 通过 .Values.limits 控制默认值与边界
最佳实践:ResourceQuota 与 LimitRange 必须成对部署。仅设置 Quota 而不设 LimitRange,会导致未声明资源的 Pod 被拒绝;仅设 LimitRange 而不设 Quota,则无法防止命名空间整体资源超卖。

4.2 在 templates/ 中编写 ResourceQuota YAML

以下是一个标准的 ResourceQuota 模板文件 templates/resourcequota.yaml,通过 .Values.quota 动态注入所有阈值:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: {{ include "myapp.fullname" . }}-quota
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
spec:
  hard:
    requests.cpu: {{ .Values.quota.requestsCpu | default "4" | quote }}
    requests.memory: {{ .Values.quota.requestsMemory | default "8Gi" | quote }}
    limits.cpu: {{ .Values.quota.limitsCpu | default "8" | quote }}
    limits.memory: {{ .Values.quota.limitsMemory | default "16Gi" | quote }}
    persistentvolumeclaims: {{ .Values.quota.pvcCount | default "10" }}
    pods: {{ .Values.quota.podCount | default "50" }}
    count/deployments.apps: {{ .Values.quota.deploymentCount | default "10" }}
    count/services: {{ .Values.quota.serviceCount | default "10" }}
关键设计点:
  • 使用 include "myapp.fullname" . 保证资源名称唯一,避免多 Release 冲突。
  • 所有数值型字段通过 default 函数提供安全默认值,防止 values.yaml 未定义时模板渲染失败。
  • requests.cpu 等字段使用 quote 转换为字符串,符合 Kubernetes API 规范。
  • 对象计数(pods、deployments、services)使用整数类型,无需 quote。

4.3 在 templates/ 中编写 LimitRange YAML

LimitRange 模板 templates/limitrange.yaml 用于约束单个容器的资源声明范围:

apiVersion: v1
kind: LimitRange
metadata:
  name: {{ include "myapp.fullname" . }}-limits
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
spec:
  limits:
    - type: Container
      default:
        cpu: {{ .Values.limits.defaultCpu | default "500m" | quote }}
        memory: {{ .Values.limits.defaultMemory | default "512Mi" | quote }}
      defaultRequest:
        cpu: {{ .Values.limits.defaultRequestCpu | default "100m" | quote }}
        memory: {{ .Values.limits.defaultRequestMemory | default "128Mi" | quote }}
      max:
        cpu: {{ .Values.limits.maxCpu | default "2" | quote }}
        memory: {{ .Values.limits.maxMemory | default "2Gi" | quote }}
      min:
        cpu: {{ .Values.limits.minCpu | default "50m" | quote }}
        memory: {{ .Values.limits.minMemory | default "64Mi" | quote }}
注意:LimitRange 的 default 与 defaultRequest 必须同时设置。如果只设 default 而不设 defaultRequest,Kubernetes 会将 default 的值同时作为 request 使用,可能导致资源预留过高。建议始终显式声明两者。

4.4 通过 Values 动态控制配额

在 values.yaml 中定义完整的配额与限制结构,支持多环境覆盖:

# values.yaml — 默认开发环境配置
quota:
  requestsCpu: "4"
  requestsMemory: "8Gi"
  limitsCpu: "8"
  limitsMemory: "16Gi"
  pvcCount: 10
  podCount: 50
  deploymentCount: 10
  serviceCount: 10

limits:
  defaultCpu: "500m"
  defaultMemory: "512Mi"
  defaultRequestCpu: "100m"
  defaultRequestMemory: "128Mi"
  maxCpu: "2"
  maxMemory: "2Gi"
  minCpu: "50m"
  minMemory: "64Mi"

生产环境覆盖文件 values-production.yaml:

# values-production.yaml
quota:
  requestsCpu: "16"
  requestsMemory: "64Gi"
  limitsCpu: "32"
  limitsMemory: "128Gi"
  podCount: 200
  deploymentCount: 50

limits:
  maxCpu: "8"
  maxMemory: "8Gi"
  minCpu: "100m"
  minMemory: "128Mi"

部署时通过 -f 参数加载环境特定配置:

helm install myapp ./myapp-chart -f values-production.yaml --namespace production

4.5 资源配额与网络拓扑的协同关系

在 Cilium 网络拓扑中,ResourceQuota 与 LimitRange 直接影响 Pod 的 QoS 等级与网络带宽分配。下图展示了配额、限制与 Cilium 网络策略的协同工作流:

ResourceQuota / LimitRange 与 Cilium 网络拓扑协同 Helm Chart values.yaml quota / limits 参数 渲染 K8s 准入控制 ResourceQuota LimitRange 约束 Pod 运行时 QoS: Guaranteed/Burstable Cilium 带宽管理 网络策略执行 Cilium 网络拓扑层 CNI 带宽插件 | eBPF 流量控制 | 网络策略 基于 QoS 等级的带宽保障与限速 流量经过 QoS 等级传递 协同效果 LimitRange 设置 request=limit → Pod 获得 Guaranteed QoS → Cilium 优先分配带宽

4.6 多环境配额策略对比

环境 CPU 请求总量 内存请求总量 Pod 上限 单容器最大 CPU QoS 策略
开发 (dev) 4 核 8 Gi 50 2 核 Burstable(默认)
测试 (test) 8 核 16 Gi 100 4 核 Burstable + 部分 Guaranteed
预发 (staging) 16 核 32 Gi 150 4 核 Guaranteed(核心服务)
生产 (prod) 32 核 128 Gi 200 8 核 Guaranteed(全部服务)
性能调优提示:当 LimitRange 设置 request.cpu == limit.cpu 且 request.memory == limit.memory 时,Pod 的 QoS 等级为 Guaranteed。Cilium 的 eBPF 带宽管理器会为 Guaranteed Pod 分配独立的带宽预算,避免 Burstable/BestEffort Pod 的流量争抢。在生产环境中,建议将核心业务 Pod 的 request 与 limit 设置为相等值。

4.7 验证配额生效的 Helm 测试钩子

在 Chart 的 templates/tests/ 目录下添加测试 Pod,验证 ResourceQuota 与 LimitRange 是否正确加载:

# templates/tests/test-quota.yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ include "myapp.fullname" . }}-quota-test
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  containers:
    - name: quota-check
      image: bitnami/kubectl:latest
      command:
        - sh
        - -c
        - |
          echo "=== ResourceQuota ==="
          kubectl get resourcequota -n {{ .Release.Namespace }}
          echo "=== LimitRange ==="
          kubectl get limitrange -n {{ .Release.Namespace }}
          echo "=== Pod QoS Check ==="
          kubectl get pod -n {{ .Release.Namespace }} -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.qosClass}{"\n"}{end}'
  restartPolicy: Never

执行 helm test myapp -n production 即可自动运行上述验证,输出配额与 QoS 状态。

4.8 常见错误与排障

  • 错误:failed to create resource quota: the server could not find the requested resource — 检查 Kubernetes 版本是否支持 ResourceQuota(v1.0+ 均支持)。
  • 错误:exceeded quota: myapp-quota, requested: pods=1, used: pods=50, limited: pods=50 — 命名空间 Pod 数量已达上限,需调整 .Values.quota.podCount。
  • 错误:container has resource requests but no limit set, and no limit range exists — 未部署 LimitRange 或 LimitRange 未设置 default 字段。
  • 错误:LimitRange min memory > request memory — 容器声明的 request 小于 LimitRange 的 min 值,需调整 values 或容器声明。
生产环境警告:ResourceQuota 的 limits.cpu 与 limits.memory 必须大于或等于所有 Pod 的 limit 总和。如果设置过小,会导致部分 Pod 无法调度。建议在生产环境中预留 20% 的缓冲余量。