LoadBalancer在kubernetes架构下的实践 (2)

异常处理不集中, 在容器被暴力清理掉之后,来不及从LB上解绑就退出, 进而导致流量继续转发到该容器之中, 或者需要另一个异步清理的进程来实现清理

系统调用耦合严重,接口难以升级, 升级接口需要重启所有的容器

耗费资源,每个富容器中都会有相关的agent

由于老的架构设计较早,问题比较多,再重新思考这个问题的时候, 希望用云原生的方式,运用operater模式实现整个流程。

可用性

在容器动态扩缩过程中,需要保证流量平滑迁移,不能导致业务流量丢失。这是最基本的可用性保证。也是需要考虑最多的地方。kubernetes为了架构的简单,将功能分成多个模块异步执行,例如pod启动和健康检查是由kubelet负责,但是流量转发是由kube-proxy负责,他们之间没有直接的交互,这就会碰到分布式系统中执行时序的问题。如果容器还没启动流量就已经转发过来了就导致流量的丢失,或者容器已经退出但流量继续转发过来也会导致流量的丢失,这些情况对于滚动更新的pod尤其明显。 因为所有的操作都需要远程调用来操作LoadBalaner, 我们不得不考虑执行速度带来的影响。

一般情况下对于容器启动的时候我们无需过多担心, 只有启动之后才能接收流量, 需要担心的容器退出的过程中,需要确保流量还没有摘掉前容器不能退出,否则就会导致流量丢失。主要体现为两点:

滚动更新的过程中需要保证新版本容器正常接收到流量之后才能继续滚动更新的过程,才能去删除老版本容器。如果随便kill掉老版本实例,此时新版本注册还没有生效, 就会导致流量的丢失。

在退出的过程中需要等待流量完全摘除掉之后才能去删除容器。

滚动更新过程

对于滚动更新, 该过程一般是由对应的workload controller负责的, 例如deployment,statfulSet。 以deployment滚动更新为例,如果不加干预整个流程为: 新版本pod启动,readiness探针通过, controller将podIP挂载到LB上面, LB生效一般都需要时间,此时流量还不能转发到新版本pod里面。于此同时deployment认为新容器已经就绪,就进行下一步,删除掉老版本的pod。 此时新老版本都不能接收流量了,就导致了整个服务的不可用。这里根本原因是deployment认为pod就绪并不会考虑LB是否就绪,LB是k8s系统外部的资源,deployment并不认识。退一步来讲,我们平时使用的InCluster类型的service也是有这个问题的,kubelet中容器退出和kube-proxy流量摘除似乎是同时进行的,并没有时序保证,如果kube-proxy执行的稍微慢一点,kubelet中容器退出的稍微快一点,就会碰到流量丢失地情况。幸运的是目前kub-proxy是基于iptables实现的转发,刷新iptables规则在一般情况下执行速度足够快,我们很难碰到这种情况。 但是如果我们基于LoadBalancer直接挂载容器IP,就没有这么幸运了,我们需要远程调用操作LB,而且需要云厂商的LB生效都比较慢,鉴于此,我们需要想办法等到LB就绪之后才能认为整个pod就绪, 即pod就绪等于容器就绪(健康检查探针通过) + LB挂载就绪, pod就绪后才能进行滚动更新。

社区也碰到过过这个问题,开发了Pod Readiness Gates(ready++)的特性,用户可以通过 ReadinessGates 自定义 Pod 就绪的条件,当用户自定义的条件以及容器状态都就绪时,kubelet 才会标记 Pod 准备就绪。 如下所示,用户需要设置readinessGate:

apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: nginx name: nginx spec: replicas: 1 selector: matchLabels: run: nginx template: metadata: labels: run: nginx spec: readinessGates: - conditionType: cloudnativestation.net/load-balancer-ready # <- 这里设置readinessGatea containers: - image: nginx name: nginx

当我们给deployment设置了readinessGate这个字段之后, 当pod启动成功通过reainess的检查之后,并不会认为整个pod已经就绪,因为此时LB还没有就绪, 如果我们此时观察pod的status会发现如下信息

status: conditions: - lastProbeTime: null lastTransitionTime: "2020-03-14T11:34:18Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2020-03-14T11:34:18Z" message: corresponding condition of pod readiness gate "cloudnativestation.net/load-balancer-ready" does not exist. reason: ReadinessGatesNotReady status: "False" type: Ready # <--- Ready为False - lastProbeTime: null lastTransitionTime: "2020-03-14T11:34:20Z" status: "True" type: ContainersReady # <--- container Ready为Ture - lastProbeTime: null lastTransitionTime: "2020-03-14T11:34:18Z" status: "True" type: PodScheduled containerStatuses: - containerID: docker://42e761fd53ccb2b2886c500295ceeff8f1d2ffc2376eb66dd95a436c395b95c0 image: nginx:latest imageID: docker-pullable://nginx@sha256:2e6775f4300fc79b9d7fe6bb60c83b5fefe584258d9318ed408746789af48885 lastState: {} name: nginx ready: true restartCount: 0 state: running: startedAt: "2020-03-14T11:34:19Z"

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxdpf.html