Kubernetes 资源配额管理实战:用 ResourceQuota 与 LimitRange 治理 Namespace 资源
2026/9/23 17:20:56 网站建设 项目流程

Kubernetes 资源配额管理实战:用 ResourceQuota 与 LimitRange 治理 Namespace 资源

【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook

当多个团队或用户共用同一个 Kubernetes 集群时,难免会发生资源竞争——一个团队的一次性大任务可能挤占其他团队的全部算力。本文基于本仓库(kubernetes-handbook)中 guide/resource-quota-management.md 的实践脉络,结合仓库内真实的 API Server 配置与manifests/spark-with-kubernetes-native-scheduler目录下的配额清单,系统讲解如何用ResourceQuotaLimitRange两类准入控制插件为 namespace 设置资源上限。读完本文,你将掌握计算资源配额、对象数量配额与默认资源请求/限制的完整配置方法,并理解这些配额在 Kubernetes API Server 内部是如何被强制执行的。

为什么需要 namespace 资源配额

Kubernetes 集群是一种共享基础设施。当多个团队、多个业务线甚至多个租户共用同一集群时,如果没有配额约束,任何一个团队都可以无限创建 Pod、申请存储卷、创建 Service,最终导致集群资源被少数使用者耗尽,其他团队的应用无法被调度。

ResourceQuota就是为解决这一问题而生的:它针对某一 namespace生效,限制该 namespace 内所有 Pod 占用的资源 request 与 limit 总量,也限制该 namespace 内可创建的对象数量。配合LimitRange可以进一步为 namespace 内未显式声明资源请求的 Pod 注入默认的 request/limit 值,使配额约束更加完整、可预期。

开启配额功能:API Server 的准入控制配置

资源配额不是一个独立服务,而是 Kubernetes API Server 中的准入控制器(Admission Controller)。准入控制器位于 API Server 中,在对象被持久化之前拦截对 API Server 的请求,用来做身份验证、授权以及对象校验与变更(详见 concepts/admission-controller.md)。

本仓库给出了真实的准入控制配置证据。在 etc/kubernetes/apiserver 中可以看到:

KUBE_ADMISSION_CONTROL="--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota"

也就是说,只要在 API Server 启动参数中加入ResourceQuota,集群便开启了资源配额限制功能;加入LimitRange,则可以对单个资源申请的范围(以及默认值)做限制。这份配置通过 systemd/kube-apiserver.service 中ExecStart=/usr/bin/kube-apiserver $KUBE_ADMISSION_CONTROL ...的方式被加载到 kube-apiserver 进程中。

关于这两个准入控制器的作用,concepts/admission-controller.md 给出了官方语义:

  • LimitRanger:确保所有资源请求不会超过 namespace 的LimitRange
  • ResourceQuota:观察传入请求并确保它不违反 namespace 的ResourceQuota对象中列举的任何约束。

版本说明--admission-control参数在 Kubernetes 1.10 中已弃用,替换为--enable-admission-plugins。对于 1.10 及以上版本,建议使用--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota的组合;1.10 之前的版本中准入控制器按指定顺序执行,ResourceQuota在验证阶段运行。本仓库对应的 etc/kubernetes/apiserver 配置适用于 1.9 及更早版本的环境。

两个控制器的分工可以这样理解:

控制器作用范围核心职责
ResourceQuota某一 namespace限制 namespace 中所有 Pod 占用的总资源request 和 limit,以及对象数量
LimitRange某一 namespace设置 namespace 中 Pod 的默认资源 request 和 limit 值,并限制单容器资源申请范围

资源配额的三种类型

按照配额对象的不同,资源配额分为三种类型:

  1. 计算资源配额:如requests.cpurequests.memorylimits.cpulimits.memory,约束 namespace 内所有 Pod 对 CPU 与内存的请求/限制总量;
  2. 存储资源配额:如requests.storage以及各类存储类(StorageClass)对应的 PVC 存储总量;
  3. 对象数量配额:如podsconfigmapssecretsservicespersistentvolumeclaims等,约束 namespace 内某类 Kubernetes 对象的数量上限。

实战:为 spark-cluster 配置计算资源配额

本仓库以 Spark 应用场景为例——spark-clusternamespace 承载着 Spark 的 resource-staging-server(见 manifests/spark-with-kubernetes-native-scheduler/kubernetes-resource-staging-server.yaml,该 Deployment 自身声明了requests.cpu: 100mrequests.memory: 256Milimits.cpu: 1000mlimits.memory: 2560Mi)。Spark 作业动辄需要大量 executor,若不加限制,很容易把集群资源吃光,因此配额管控尤为必要。

计算资源配额的清单文件为 manifests/spark-with-kubernetes-native-scheduler/spark-compute-resources.yaml:

apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources namespace: spark-cluster spec: hard: pods: "20" requests.cpu: "20" requests.memory: 100Gi limits.cpu: "40" limits.memory: 200Gi

这份配额的含义是:在spark-clusternamespace 中——

  • 同时存在的 Pod 总数最多20个;
  • 所有 Pod 的requests.cpu总和不超过20(即 20 个 CPU 核心);
  • 所有 Pod 的requests.memory总和不超过100Gi
  • 所有 Pod 的limits.cpu总和不超过40
  • 所有 Pod 的limits.memory总和不超过200Gi

其中requests.cpu的单位是 core,允许浮点数,例如0.1等价于100m(100 毫核);requests.memory以字节为单位,支持E/P/T/G/M/K十进制后缀与Ei/Pi/Ti/Gi/Mi/Ki二进制后缀(关于 CPU 与内存单位的详细约定可参考 practice/manage-compute-resources-container.md)。

创建配额后,可用如下命令查看配额生效状态:

kubectl -n spark-cluster describe resourcequota compute-resources

输出中会同时展示Resource(配额项)、Used(当前已用量)与Hard(上限)三列,例如pods一行的Used会显示当前 namespace 内实际存在的 Pod 数。若 namespace 内的资源使用量已逼近上限,新的 Pod 创建请求会被ResourceQuota准入控制器拒绝。

实战:配置对象数量限制

除了计算资源,配额同样可以约束对象的数量,防止 namespace 内堆积过多 ConfigMap、Secret、Service 等对象。对象数量配额的清单文件为 manifests/spark-with-kubernetes-native-scheduler/spark-object-counts.yaml:

apiVersion: v1 kind: ResourceQuota metadata: name: object-counts namespace: spark-cluster spec: hard: configmaps: "10" persistentvolumeclaims: "4" replicationcontrollers: "20" secrets: "10" services: "10" services.loadbalancers: "2"

这份配额的含义是:在spark-clusternamespace 中,ConfigMap 最多10个、PVC 最多4个、ReplicationController 最多20个、Secret 最多10个、Service 最多10个,其中 LoadBalancer 类型的 Service 最多2个。

对象数量配额是典型的多租户治理手段:例如限制services.loadbalancers可以避免云厂商的负载均衡资源被无限创建而产生费用;限制persistentvolumeclaims可以控制持久化存储的占用规模。ResourceQuotaLimitRange可以同时存在于同一 namespace 中,互不冲突——本仓库的 spark 示例正是同时创建了compute-resourcesobject-counts两个配额对象。

实战:配置 CPU 和内存 LimitRange

LimitRange解决的是"默认值"问题:当用户创建 Pod 时没有为容器显式声明resources.requestsresources.limitsLimitRanger准入控制器会按照 namespace 中定义的默认值自动注入,从而保证配额约束总能生效——否则用户完全可以通过不声明 request/limit 来绕过ResourceQuota的总量限制。

LimitRange 清单文件为 manifests/spark-with-kubernetes-native-scheduler/spark-limit-range.yaml:

apiVersion: v1 kind: LimitRange metadata: name: mem-limit-range spec: limits: - default: memory: 50Gi cpu: 5 defaultRequest: memory: 1Gi cpu: 1 type: Container

其中两个关键字段的含义:

  • default:即容器默认的limit值(资源上限);
  • defaultRequest:即容器默认的request值(资源申请量)。

也就是说,spark-clusternamespace 中任何未显式声明资源的容器,都会被自动注入limits.memory: 50Gilimits.cpu: 5requests.memory: 1Girequests.cpu: 1的默认值。type: Container表明该条 limit 规则作用在容器层级(Pod 的资源 request/limit 是其所有容器对应值之和,详见 practice/manage-compute-resources-container.md)。

LimitRange 与 ResourceQuota 的配合关系

  • ResourceQuota管的是 namespace 内所有 Pod 的总和是否越界;
  • LimitRange管的是单个容器的资源申请是否落在允许范围内,并为未声明资源的容器填充默认值;
  • 当两者同时开启时,LimitRanger先为 Pod 注入默认的 request/limit,ResourceQuota再校验注入后的总量是否突破配额上限——这也是推荐同时开启二者的原因。

配额生效的底层机制与验证

从源码与配置层面看,配额强制执行的链路是:

  1. 用户在 namespace 内创建ResourceQuota/LimitRange对象(如上述三个 yaml 清单);
  2. 用户创建 Pod、Service 等资源时,请求进入 API Server;
  3. API Server 依次执行已启用的准入控制器(本仓库环境为ServiceAccount, NamespaceLifecycle, NamespaceExists, LimitRanger, ResourceQuota,见 etc/kubernetes/apiserver):
    • LimitRanger校验并注入默认资源值;
    • ResourceQuota校验当前 namespace 的资源与对象用量,一旦违反hard中任一项即拒绝请求;
  4. 拒绝时 API Server 返回forbidden错误,kubectl create等客户端操作会直接报错。

配额被拒绝时的典型排查方式:

# 查看 namespace 当前配额与用量 kubectl -n spark-cluster get resourcequota # 查看配额详情(含 Used / Hard 对比) kubectl -n spark-cluster describe resourcequota compute-resources kubectl -n spark-cluster describe resourcequota object-counts # 查看被拒绝的 Pod 事件 kubectl -n spark-cluster describe pod <pod-name>

当事件中出现failed quota/exceeded quota之类的信息时,说明 Pod 创建请求被ResourceQuota拦截,需要检查describe resourcequota输出中UsedHard的差值,及时清理不再使用的 Pod、Service 或 PVC。这与节点调度失败(FailedScheduling: insufficient cpu)是两类不同的问题:配额限制发生在 API Server 的准入阶段,而节点容量不足发生在调度阶段(参见 practice/manage-compute-resources-container.md 的疑难解答部分)。

多租户场景下的配额治理建议

结合本仓库的实践,在多团队共享集群时推荐遵循以下策略:

  1. 每个团队独占 namespace:以团队或业务线为单位划分 namespace,配额天然按 namespace 隔离,互不影响;
  2. 计算配额 + 对象配额同时下发:参考本文两个ResourceQuota清单,既约束 CPU/内存总量,也约束 ConfigMap、Secret、Service、PVC 等对象的数量上限;
  3. 用 LimitRange 兜底默认值:为 namespace 配置默认 request/limit,避免用户因未声明资源而绕过配额、也避免个别容器申请超规格的资源导致 namespace 总量被快速耗尽;
  4. 配额值与业务容量匹配:配额上限应结合业务真实需求设定,例如 spark-cluster 的配额上限(pods 20、requests.memory 100Gi)需要覆盖 driver、executor 与 resource-staging-server 的总需求,过紧会导致作业无法提交,过松则失去治理意义;
  5. 结合 RBAC 控制配额管理权限:只有具备相应权限的管理员才能创建/修改ResourceQuota,防止普通用户自行调高配额或删除配额对象(RBAC 与 namespace 级权限的说明可参考 practice/rbac-support-in-kubernetes.md)。

参考

  • 本主题原始文档:管理 namespace 中的资源配额
  • 配额清单:spark-compute-resources.yaml
  • 配额清单:spark-object-counts.yaml
  • 配额清单:spark-limit-range.yaml
  • 准入控制器详解
  • API Server 配置(含 KUBE_ADMISSION_CONTROL)
  • kube-apiserver systemd 服务单元
  • 管理容器的计算资源(CPU/内存单位与调度、驱逐机制)
  • Kubernetes 中的 RBAC 支持

【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询