每个节点的预留资源,对应kubelet的system-reserved, kube-reserved, eviction-hard配置的资源之和,Kubernetes计算Node的Allocatable资源时会减去这部分预留资源。
目前我们集群的平均资源碎片大概在5%~10%左右,根据不同规格的CVM机型略有不同。这些资源碎片分散在集群中的各个节点,以1c1g, 2c2g, 3cxg为主,平台提供用户选择的容器规格都很难match到这些碎片,经常存在这这种情况:要调度某个Pod时,发现某个节点上的cpu足够,但是mem不足,或者相反。
剩下的就是可以被业务Pod真正分配使用的资源了,业务在选择容器规格时带有一定的主观性和盲目性,导致业务容器的负载很低,这样的业务占比一大就容易导致集群低负载的情况,但是集群按照Kubernetes静态调度策略又无法再容纳更多的业务容器了。如上图中所示的,集群分配CPU水位线很高,但是实际CPU利用率不高的情况。
每个Workload负载变动规律不同,因此Pod分配资源压缩比例也对应不一样,需要支持每个Workload自定义配置,而且这是对用户无感知的。这个压缩比,我们设置到Workload的Annotation中,比如cpu资源压缩对应Annotation stke.platform/cpu-requests-ratio;
压缩比,谁去设置?自研组件(Pod-Resource-Compress-Ratio-Reconciler)基于Workload的历史监控数据,动态的/周期性去调整压缩比。比如某Workload连续7d/1M的负载持续很低,那么可以把压缩比设置的更大,以此让集群剩余可分配资源更大,容纳更多的业务容器。当然实际上压缩比的调整策略并不会这么简单,需要更多的监控数据来辅助。
Pod分配压缩特性一定要是可以关闭的和恢复的,通过Workload Annotation stke.platform/enable-resource-compress: "n"针对Workload级别disable,通过设置压缩比为1进行压缩恢复。
何时通过压缩比去调整Pod Spec中的Request Resource?Kubernetes发展到现阶段,直接改Kubernetes代码是最愚蠢的方式,我们要充分利用Kubernetes的扩展方式。这里,我们通过kube-apiserver的Mutating Admission Webhook对Pod的Create事件进行拦截,自研webhook(pod-resource-compress-webhook)检查Pod Annotations中是否enable了压缩特性,并且配置了压缩比,如果配置了,则根据压缩比重新计算该Pod的Request Resource,Patch到APIServer。
每个节点的资源超卖比例,我们设置到Node的Annotation中,比如cpu超卖对应Annotation stke.platform/cpu-oversale-ratio。
每个节点的超卖比例,谁去设置?自研组件(Node-Resource-Oversale-Ratio-Reconciler)基于节点历史监控数据,动态的/周期性的去调整超卖比例。比如某个Node连续7d/1M持续低负载并且节点已分配资源水位线很高了,那么可以把超卖比例适当调高,以此使Node能容纳更多的业务Pod。
Node超卖特性一定要是可以关闭和还原的,通过Node Annotation stke.platform/mutate: "false"关闭Node超卖,Node在下一个心跳会完成资源复原。
何时通过压缩比去调整Node Status中的Allocatable&Capacity Resource?同样的,我们通过kube-apiserver的Mutating Admission Webhook对Node的Create和Status Update事件进行拦截,自研webhook(node-resource-oversale-webhook)检查Node Annotations中是否enable了超卖并且配置了超卖比,如果配置了,则根据安超卖比重新计算该Node的Allocatable&Capacity Resource,Patch到APIServer。
Kubelet Register Node To ApiServer的详细原理是什么,通过webhook直接Patch Node Status是否可行?
当节点资源超卖后,Kubernetes对应的Cgroup动态调整机制是否能继续正常工作?
Node status更新太频繁,每次status update都会触发webhook,大规模集群容易对apiserver造成性能问题,怎么解决?
节点资源超卖对Kubelet Eviction的配置是否也有超配效果,还是仍然按照实际Node配置和负载进行evict? 如果对Evict有影响,又该如解决?
超卖比例从大往小调低时,存在节点上 Sum(pods' request resource) > node's allocatable情况出现,这里是否有风险,该如何处理?
监控系统对Node的监控与Node Allocatable&Capacity Resource有关,超卖后,意味着监控系统对Node的监控不再正确,需要做一定程度的修正,如何让监控系统也能动态的感知超卖比例进行数据和视图的修正?
Node Allocatable和Capacity分别该如何超卖?超卖对节点预留资源的影响是如何的?
性能问题:一个goroutine中循环遍历集群中所有的HPA对象,针对每个HPA对象获取对应的Pod监控数据、计算新Replicas,这对于大业务是比较耗时的。
核心配置不支持Workload自定义:HPA伸缩响应时间是每个业务都可能不一样的,有些业务期望能5s进行响应,有些业务觉得60s就够了。而内置HPA Controller在响应时间控制上只能配置全局的启动参数horizontal-pod-autoscaler-sync-period。还有每个业务对负载的抖动容忍是不一样的,在内置的HPA Controller中只能通过horizontal-pod-autoscaler-tolerance做全局配置,无法提供业务级的自定义。
Kubernetes目前对custom metrics的支持,只能注册一个后端监控服务,如果集群中有些业务通过prometheus来expose应用自定义指标,也有一些业务通过Monitor来监控应用自定义指标,这个时候就做不到All in了,这在for自研上云的场景中,是一定存在的场景。
每个HPA对象会启动一个goroutine协程专门负责该HPA对象的管理和计算工作,各个协程并行执行,极大的优化了性能。HPAPlus-Controller独立部署,其资源需求可以是集群规模和HPA数量进行合理调整,相比于原内置HPA-Controller有更大的灵活性。
HPAPlus-Controller支持各个HPA对象自定义伸缩响应时间,支持自动感应业务是否在变更发布并决定是否要禁用HPA(某些业务有这样的需求:升级时禁止触发弹性伸缩),支持基于pod resource limit为基数进行Pod资源利用率计算,从而推导出扩缩容后的期望replicas,这一点对于节点超卖和Pod资源压缩后的集群非常重要。
-
支持业务级别对负载的抖动容忍度的个性化配置。
支持基于更多维度的监控数据进行Scale决策,比如Pod历史7d/1M的CPU负载。
支持CronHPA,满足规律性扩缩容的业务诉求。
通过Extension APIServer的方式对接公司Monitor监控,保留Prometheus-Adaptor的方式来支持基于Prometheus的应用监控,满足基于多种应用监控系统的custom metrics进行HPA。