当用户创建LoabBalancer类型的service时,cloud-controller-manager中的service controller就会利用informer监听service的创建、更新、删除事件,然后调用各个云厂商注册的接口,云厂商只需要提供以上的接口就行了。
对于Loadbalancer,具体各个厂商实现不同, 但是目前的实现基本都是直接挂载nodePort, 可以看到上述EnsureLoadBalancer中传递的参数也是nodes列表。 上述的接口我们无法直接使用,需要对其改造, 实现一个自定义的service controller。在EnsureLoadBalancer的时候传递的参数也应该是pod的IP列表, 我们挂载的是pod而不是node。所以此处需要不断监听pod的变化,然后选择判断该pod是否被service label selector选中,如果选中则该pod是service的后端,需要设置将流量转发到该pod上面, 这里很多熟悉kubernetes的小伙伴就会好奇,这里不是和endpoints的功能一模一样吗? 为什么不直接监听endpoint, 然后将endpoint中的ip列表拿出来直接使用?
要弄明白这个问题,我们需要回顾我们在保证流量不丢的时候设置了readinessGate, 此时pod就绪状态会变为: 容器就绪+LB就绪。但是在endpoint的工作原理中, endpoint controller会判断pod是否就绪,pod就绪之后才会将podIP放在endpoint的结构体中。而我们期望容器就绪之后就在endpoint显示出来,这样我们就可以拿着这个enpoint的ip列表去注册到LB上, LB注册成功之后,pod才能变为就绪。 社区endpoint中iplist的顺序和我们期望的略有差异, 只能自己实现一个类似的结构体了,和社区的使用方式大部分相同, 只是判断就绪的逻辑略有不同。
自定义endpoint的另外一个原因是: endpoint controller会将service选中的所有pod分为ready和unready两组, 当pod刚启动时, 还未通过readiness探针检查时会将pod放置在unReadAddress列表中,通过readiness检查后会移动到address列表中,随后在退出时会直接将pod移出address列表中。 在我们的场景下,更加合理的逻辑应该是在退出过程中应该从endpoint中address列表移动到unReadyAddress列表,这样我们就可以根据unReadyAddress来决定在退出的时候将哪些podIP在LB上面将权重置为0。
自定义endpoint controller并没有更改kubernetes原来的endpoint controller的代码, 这里我们只是作为一个内部的数据结构体使用, 直接结合在service controller中即可,也无需监听endpoint变化,直接监听pod变化生成对应的service 即可。
收获在落地kubernetes的过程中, 相信kube-proxy被不少人诟病,甚至有不少公司完全抛弃了kube-proxy。 不好的东西我们就要积极探索一种更好,更适合公司内部情况的解决方案。目前该满足了不同业务上云时的网络需求,承载了不同的流量类型。 同时很好地应用在多云环境下,私有云和公有云下都可以适配, 尽管私有云或者公有云的底层网络方案或者LB实现不同,但是整个架构相同,可以无缝地在私有云,aws, 阿里,金山云直接迁移。
kubernetes的快速发展为我们带来了很多惊喜,但是于此同时很多细节的地方需要打磨,需要时间的沉淀才能更加完美, 相信在落地kubernetes的过程中不少人被kubernetes的网络模型所困扰,此时我们需要根据企业内部的情况, 结合已有的基础设施,根据社区已经提供的和尚未提供的功能进行一些大胆的微创新,然后探索更多的可能性。