前景
这里谈 kube-proxy
如何保证规则的一致性以及提升 kube-proxy
性能点的地方,这也是 kubernetes 使用稳定性的一部分。
kube-proxy 如何做到的CRUD
kube-proxy
实际上与其他内置 controller 架构是相同的,实际上也属于一个 controller ,但它属于一个 service, endpoints 的可读可写的控制器,node的读控制器。对于CRUD方面,kube-proxy,在设计上分为 增/改 两方面。正如下面代码所示 pkg/proxy/ipvs/proxier.go
|
|
可以看到代码最终调用的都是 OnServiceUpdate
,最终 调用的是 proxier.Sync()
。对于 Sync(),这里会调用在 Proxier 初始化时注入的那个函数,而 Sync() 本质上是 一个异步有限的函数管理器,这里将实现两个方面,一是,定时去触发执行这个函数;二是满足规则去触发这个函数;而 Sync() 属于条件2
对于注入的函数,则是 proxier.syncProxyRules ,由下列代码可以看到
|
|
这样就是说,kube-proxy 通过 syncProxyRules 实现了整个 service 与 endpoint 的增删改查
性能提升点1
由上面有限的函数管理器 runner,可以作为性能提升点,而该runner初始化时提供了minSyncPeriod, syncPeriod 两个函数,这两个函数代表的意思为,minSyncPeriod是runner允许你在最小多少时间内可以调用,如果你的集群规模大,那么则可以适当配置该参数小写,因为service的频繁更改会被这个参数限制。
如何通过一个函数做CRUD
对于增改,存在三个资源,ClusterIP, NodePort, Ingress,当这些资源被触发时,会同步这个service与endpoint,如代码所示 syncProxyRules
|
|
由上面代码可知,所有的 service 与 endpoint 的更新,都会触发 Sync()
,而 Sync()
执行的是 syncProxyRules()
,当service有变动时,就会通过 syncService/syncEndpoint 进行同步
而对于删除动作来说,kube-proxy 提供了 cleanLegacyService 函数在变动做完时,进行清理遗留的service规则,如下列代码所示。
|
|
并且通过两个数组来维护两个 activeIPVSServices , 与 currentIPVSServices 为主,来维护删除的数据
CRUD实际实现
上面了解到了删除与添加的逻辑,下面分析这些是如何进行的
当添加被触发时,会触发 proxier.syncService() ,首先会进行本机上ipvs规则是否存在这个规则,存在则更改,而后返回一个 error, 这个 error 取决于是否更新 endpoints,如下列代码所示
|
|
接下来通过后会 触发 proxier.syncEndpoint() 这里传入了当前的 service, 这里是为了与 IPVS 概念相吻合,如IPVS 中存在 RealServers/VirtualServers,首先会拿到本机这个VirtualServer下的所有RealServer,而后进行添加,而后对比 传入的 Endpoints 列表 与 本机这个VirtualServer下的所有RealServer,不相等的则被删除;删除的动作是一个异步操作。由 gracefuldeleteManager 维护
|
|
删除 service 将删除所有的 RealServer,这点上面提到过,kube-proxy 通过 cleanLegacyService 进行删除,如下列代码所示
|
|
性能提升点2
由上面的讲解可知,CRUD动作是每一个事件 syncProxyRules 被触发时都会进行执行,而删除动作存在多组循环(如构建维护的两个列表;进行循环删除)即每一次 Endpoints 变动也会触发 大量的 Service 的循环,从而检测 是否由遗留的Service资源,而这个操作保留到kubernetes 1.26版本
假设你的集群节点是5000个,service资源是两万个,那么当你更新一个Service资源循环的次数,会至少循环多达数万次(Service, EndpointSpilt, currentServices, NodeIP, Ingress)其中无用的为currentServices,因为这个只有在删除Service本身才会有效(如果存在20000个service,其中currentServices在构建与对比的过程超过4万次)