1 要解决的问题
集群分配给多个用户使用时,需要使用配额以限制用户的资源使用,包括 CPU 核数、内存大小、GPU 卡数等,以防止资源被某些用户耗尽,造成不公平的资源分配。
大多数情况下,集群原生的 ResourceQuota
机制可以很好地解决问题。但随着集群规模扩大,以及任务类型的增多,我们对配额管理的规则需要进行调整:
ResourceQuota
针对单集群设计,但实际上,开发/生产中经常使用 多集群 环境。- 集群大多数任务通过比如
deployment
、mpijob
等 高级资源对象 进行提交,我们希望在高级资源对象的 提交阶段 就能对配额进行判断。但ResourceQuota
计算资源请求时以pod
为粒度,从而无法满足此需求。
基于以上问题,我们需要自行进行配额管理。而 Kubernetes 提供了动态准入的机制,允许我们编写自定义的插件,以实现请求的准入。我们的配额管理方案,就以此入手。
2 集群动态准入原理
进入 K8s 集群的请求,被 API server 接收后,会经过如下几个顺序执行的阶段:
- 认证/鉴权
- 准入控制(变更)
- 格式验证
- 准入控制(验证)
- 持久化
请求在上述前四个阶段都会被相应处理,并且依次被判断是否允许通过。各个阶段都通过后,才能够被持久化,即存入到 etcd 数据库中,从而变为一次成功的请求。其中,在 准入控制(变更) 阶段,mutating admission webhook
会被调用,可以修改请求中的内容。而在 准入控制(验证) 阶段,validating admission webhook
会被调用,可以校验请求内容是否符合某些要求,从而决定是否允许或拒绝该请求。而这些 webhook
支持扩展,可以被独立地开发和部署到集群中。
虽然,在 准入控制(变更) 阶段,webhook
也可以检查和拒绝请求,但其被调用的次序无法保证,无法限制其它 webhook
对请求的资源进行修改。因此,我们部署用于配额校验的 validating admission webhook
,配置于 准入控制(验证) 阶段调用,进行请求资源的检查,就可以实现资源配额管理的目的。
3 方案
3.1 如何在集群中部署校验服务
在 K8s 集群中使用自定义的 validating admission webhook
需要部署:
ValidatingWebhookConfiguration
配置(需要集群启用 ValidatingAdmissionWebhook) ,用于定义要对何种资源对象(pod
,deployment
,mpijob
等)进行校验,并提供用于实际处理校验的服务回调地址。推荐使用在集群内配置Service
的方式来提供校验服务的地址。- 实际处理校验的服务,通过在
ValidatingWebhookConfiguration
配置的地址可访问即可。
单集群环境中,将校验服务以 deployment
的方式在集群中部署。多集群环境中,可以选择:
- 使用 virtual kubelet,cluster federation 等方案将多集群合并为单集群,从而退化为采用单集群方案部署。
- 将校验服务以
deloyment
的方式部署于一个或多个集群中,但要注意保证服务到各个集群网络连通。
需要注意的是,不论是单集群还是多集群的环境中,处理校验的服务都需要进行资源监控,这一般由单点实现。因此都需要 进行选主。
3.2 如何实现校验服务
3.2.1 校验服务架构设计
3.2.1.1 基本组件构成
- API server:集群请求入口,调用
validating admission webhook
以验证请求 - API:准入服务接口,使用集群约定的 AdmissionReview 数据结构作为请求和返回
- Quota usage service:请求资源使用量接口
- Admissions:准入服务实现,包括
deployment
和mpijob
等不同资源类型准入 - Resource validator