为了解决这个问题,后台服务会定时全局更新每个应用组的 usage 值。这样,如果出现了 验证 阶段增加了 usage 值,但任务实际提交到数据库失败的情况,在全局更新的时候,usage 值最终会重新更新为那个时刻应用组在集群内资源使用的准确值。
但在极少数情况下,全局更新会在这种时刻发生:某最终会成功存入 etcd 持久化 的资源对象创建请求,已经通过 webhook 验证,但尚未完成 持久化 的时刻。这种时刻的存在,导致全局更新依然会带来用户占用 超过 配额的问题。
比如,在之前的例子中,deployment1 更新了 usage 值之后,恰巧发生了全局更新。此时 deployment1 的信息恰好尚未存入 etcd,所以全局更新会把 usage 重新更新为旧值,这样会导致 dployment2 也能被通过,从而超过了配额限制。
但通常,从 验证 到 持久化 的时间很短。低频 的全局更新情况下,此种情况 几乎不会发生。后续,如果有进一步的需求,可以采用更复杂的方案来规避这个问题。
K8s 集群中原生的配额管理 ResourceQuota 针对上述 资源申请竞争 和 资源创建失败 问题,采用了类似的解决方案:
即时更新解决申请竞争问题
检查完配额后,即时更新资源用量,K8s 系统自带的乐观锁保证并发的资源控制(详见 K8s 源码中 的实现),解决资源竞争问题。
checkQuotas 中最相关的源码解读:
// now go through and try to issue updates. Things get a little weird here: // 1. check to see if the quota changed. If not, skip. // 2. if the quota changed and the update passes, be happy // 3. if the quota changed and the update fails, add the original to a retry list var updatedFailedQuotas []corev1.ResourceQuota var lastErr error for i := range quotas { newQuota := quotas[i] // if this quota didn't have its status changed, skip it if quota.Equals(originalQuotas[i].Status.Used, newQuota.Status.Used) { continue } if err := e.quotaAccessor.UpdateQuotaStatus(&newQuota); err != nil { updatedFailedQuotas = append(updatedFailedQuotas, newQuota) lastErr = err } }这里 quotas 是经过校验后的配额信息,其中 newQuota.Status.Used 字段则记录了该配额的资源使用情况。如果针对该配额的资源请求通过了,运行到这段代码时,Used 字段中已经被加上了新申请资源的量。随后,Equals 函数被调用,即如果 Used 字段未变,说明没有新的资源申请。否则,就会运行到 e.quotaAccessor.UpdateQuotaStatus,立刻去把 etcd 中的配额信息按照 newQuota.Status.Used 来更新。
定时全局更新解决创建失败问题
定时全局更新资源使用量(详见 K8s 源码中 的实现),解决可能的资源创建失败问题 。
Run 中最相关的源码解读:
// the timer for how often we do a full recalculation across all quotas go wait.Until(func() { rq.enqueueAll() }, rq.resyncPeriod(), stopCh)这里 rq 为 ResourceQuota 对象对应 controller 的自引用。这个 Controller 运行 Run 循环,持续地控制所有 ResourceQuota 对象。循环中,不间断定时调用 enqueueAll,即把所有的 ResourceQuota 压入队列中,修改其 Used 值,进行全局更新。
4 参考Controlling Access to the Kubernetes API
Dynamic Admission Control
A Guide to Kubernetes Admission Controllers
深入理解 Kubernetes Admission Webhook
https://github.com/kubernetes/kubernetes/blob/v1.13.0/test/images/webhook/main.go
Admission Webhooks: Configuration and Debugging Best Practices - Haowei Cai, Google
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!