且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

详解 Kubernetes 的稳定性和可用性

更新时间:2022-04-24 10:15:44

大家好,我叫杨朝乐,来自才云科技基础设施部门。今天给大家分享一个平时可能接触得较少的话题:关于 Kubernetes 的稳定性和可用性。

下面是今天分享以下 5 个主题:

  • 认识稳定性
  • 认识异常
  • Kubernetes 里面的高可用方案
  • 如何处理异常
  • 我的经验分享

认识稳定性

Kubernetes 集群的稳定性和众多因素相关。比如我们有一个集群,上面会有很多应用,这些应用可能是无状态的,通过 Deployment 来管理;也可能是有状态的应用,通过 StatefulSet 来管理。Kubernetes 集群之上,通过多种 Controller 来管理我们的应用。而在集群之下,比如集群节点的存储、网络、资源等,比如物理硬件的好坏,都是影响集群稳定性的重要一环。

就像有一个叫做 “Jenga” 这个游戏,某些元素的单个故障不会导致集群不可用,一旦某些关键元素或者多个元素故障,超过了集群的自恢复能力,集群便不再可用了。

详解 Kubernetes 的稳定性和可用性

那么,Kubernetes 为我们提供了哪些提高集群可用性的利器呢?下面分享几个使用较多的特性:Replica,Qos,HPA,Health Check。

详解 Kubernetes 的稳定性和可用性

我们先来看一个一切正常的 Kubernetes 集群,包含 3 个节点,每个节点上跑了一些应用。可以注意到,有些应用有多个实例,有些只有一个实例。下面,如果第一个节点的 Console 和第二个节点的 Api 故障了,集群服务的可用性会怎样呢?

详解 Kubernetes 的稳定性和可用性

1、Replica

我们可以联想到,对于 Console 的故障,当 Console 不可用时,Console 对应的服务也不可用;而 Kubernetes 会保证应用的副本时,所以 Console 这个应用会重新的创建出来,并正常提供服务。但在重新调度和创建起来之前,服务是会中断的。作为对比,Api 服务因为使用了多个副本,在图中的故障情况下,服务是仍然可用的。所以这里我们推荐使用多个副本。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

2、QoS

下面再看一张图,图中应用的大小对应应用的资源占用,这里以占用的内存为例。比如在节点 3 上,Db 因为资源不足,无法正常运行。

详解 Kubernetes 的稳定性和可用性

这里列出了几个可能的场景:

  • 应用(节点 1 上的 Db)使用了过多的内存,会发生什么呢?Db 自己可能会因为内存不足或超限而被 kill 掉;Db 可能会导致其他优先级低的应用被 kill 掉。
  • 应用(节点 3 上的 App)申请了过多的内存,导致原先想调度到这个节点上的应用无法调度上来

这些场景会在配置不同的 QoS classes 策略下有所不同,Kubernetes 提供了三种资源使用策略,根据应用的资源申请(request)和资源限额(limit)的不同、对于到 Guaranteed Burstable 和 BestEffort 三种模式。实际场景下,应该合理分配资源,避免资源的浪费和服务的不稳定。

详解 Kubernetes 的稳定性和可用性

3、HPA

和 Qos 类似的,HPA 是应用水平自动扩容。切换到这样场景:集群的 Db 服务负载很低,多个副本显得浪费;或者,集群的 Api 服务,突然流量剧增,当前的副本数已经不够了。这个时候,通过配置 HPA,可以使应用在负载高的时候,自动的添加副本数来减小单个实例的压力;也可以在压力小的时候,降低副本数,释放资源。

说到这里,可以提一下这里的负载,目前 Kubernetes HPA 实现上是通过衡量 CPU 的负载来评估服务负载的,实际使用中可能不能满足我们的需求。不过 Kubernetes 还提供了 Custom metric 让我们来自定义负载的指标。而与 HPA 类似的,还有集群的自动扩缩容(Cluster Autoscaler)和应用的垂直扩容(VPA)。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

4、Health Check

下面讲讲健康检测(Health Check)。比如应用 Api 出现了问题,我们实际访问 Api 服务时发现这个服务确实不可用了,但我们查询到的 Api pod 运行的状态的 Running,也就是正常在跑,Kubernetes 不会知道这个应用不工作了。默认情况下,如果应用没有异常退出,Kubernetes 会认为这个应用是正常的,不会做特殊处理。

但我们或许会遇到以下 2 种情况:

  1. 应用因为死锁而卡死;
  2. 应用还在初始化阶段等导致服务不可用,我们可以借助健康检测来让 Kubernetes 发现和处理这类异常。

对于状况 1,我们可以配置存活性检测(Liveness Probes),如果存活性检测没有通过,Kubernetes 会自动来重启这个应用。

对于状态 2,我们可以配置可用性检测(Readiness Probes),这样在服务初始化完成前,通过 Service 不能访问到这个服务,避免造成意想不到的后果。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

提高集群的稳定性,Kubernetes 还提供了许多高级功能,这些功能可能没有前面提到的那几个常见,但却也是十分有用的。下面分享两个功能特性:资源预留和关键组件调度保证。

资源预留

实际场景下的资源使用,除开用户运行的实际业务,操作系统本身也会占有一定的资源,比如系统内核,比如系统服务(sshd udev 等)。如果用户业务使用了过多的资源,以至于系统的资源得不到保障,导致系统不稳定,集群服务就也得不到保障了。这个时候,我们可以通过配置 System-reserved 来给系统预留部分的资源。

但是这样就够了么?我们知道,Kubernetes 集群本身也有许多控制组件,这些组件如果因为资源不足出现故障,整个集群也没法保障稳定了。这个时候,我们可以类似配置 System-reserved 一样,配置 Kube-reserved,来预留资源给 Kubernetes 相关的组件,比如 Kubelet 和 Docker daemon。这样一来,哪怕用户业务负载很高,也可一定程度上通过保证系统核心组件的稳定来提高集群的稳定性。

详解 Kubernetes 的稳定性和可用性

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

关键组建调度保证

除了 Kubernetes 的系统组件,还有一些组件,这些组件如果没有跑起来,整个集群都可能不可用,比如 dns 服务,比如网络插件等。这些关键的应用(Critical Add-On),Kubernetes 提供了一种机制,来保证这些关键应用的存活。

比如这样一种情况,DNS 调度到了一个节点,这个节点存在一些问题,导致 DNS 一直不停的出错重启。默认情况下,除非 Kubernetes 认为这个节点不可用,进而重新调度 DNS,DNS 服务是不会重新调度的,这样会导致集群不可用,并且不能自动修复。这个时候,如果配置了 Rescheduler 组件,并且把 DNS 配置成了关键应用,DNS 会被重新调度到另外一个节点。这样,集群的服务一定程度下,可以自动的修复。

详解 Kubernetes 的稳定性和可用性

认识异常

讲了许多的提高集群稳定性的方法,下面谈谈集群使用中可能遇到的异常。回到最初的那个图,图上每一个节点,都可能出现异常,比如:应用没有跑起来;节点挂掉了;网络故障;Docker 卡死等。下面以电力故障为例,来谈谈出现异常时候,对集群服务的影响。

详解 Kubernetes 的稳定性和可用性

下面三张图中三个节点上分别跑着一些服务,假设故障分别出现在这三个节点上,会发生什么呢?前面提到了 Replica,我们知道如果 Replica 为 1,服务是会中断的。这个中断时间可能没有大家想象的那么短。

默认情况下,从节点状态变为不可用,到 pod 重新调度到其他可用节点,可能需要几分钟的时间。我们可以通过配置 pod-eviction-timeout 来调整这个时间,但不建议配的太小,这样可能因为比如网络不稳导致 pod 不停地重新调度,造成抖动。

那是否 Replica 配置成 2 或者更多就可以了呢?我们可以想想节点 1 出现故障,服务 Console 全部跑在了节点 1 上,哪怕 Console 有多个服务,故障还是会造成 Console 服务中断。这个时候,我们可以配置 podAntiAffinity,来保证服务的多个副本不会调度到相同的节点上,以此来进一步提高可用性。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

我们继续假设,如果出现电力故障的节点是 Master 呢?如果这是唯一的 Master,那么故障的服务不会重新调度和恢复;通过 Service 方式访问这个应用,有可能访问到故障的后端服务。

K8S 里的高可用方案

如果是有多个 Master 呢?理想的情况下,故障节点上的应用会重新调度,故障的服务也会自动恢复。为什么说理想的情况下呢,这个我们稍后会解释,在此之前,我们先看看高可用在 Kubernetes 是如何实现和工作的。

详解 Kubernetes 的稳定性和可用性

图中描述了一个典型的 Kubernetes HA 方案架构,包括几个重要的地方:

详解 Kubernetes 的稳定性和可用性
  • Masters:集群 Master 节点数不再是一个,而是三个,etcd 作为集群的模式工作在三个 Master 节点上,每个节点上都会跑一个 apiserver,并连接这个 etcd 集群;其他有状态的组件比如 controller scheduler 会采用主备的方式,在三个 Master 上都会运行,但是只有一个节点上的会选举为主,提供服务。
  • Nodes:集群 Node 节点的 Kubelet proxy 服务,连接 apiserver 的负载均衡地址。
  • load balancer:一个负载均衡服务,把流量导入到存活的 Master 节点的 apiserver 服务上。这个负载均衡即可以是一个外部 IaaS 提供的云负载均衡,也可以是自己通过keepalived 和 nginx 搭建出来的内部负载均衡。
详解 Kubernetes 的稳定性和可用性

社区热门的部署工具 Kubeadm,也有整合 HA master 的计划,下图是一个目前的完成度情况,可以发现里面还有不少工作要做,预计的发布版本是 v1.10。如果不想等得太久,社区也给出了一个基于 Kubeadm 手动创建一个 HA master 集群的方案和操作流程。这里给出了相关文档的链接,感兴趣的同学可以自己选择阅读。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

回到刚才说的理想的情况,HA 方案可以保证集群高可用。但实际情况呢?

目前的 HA 集群,在实际使用上,会有一些坑,虽然某些可能在最新的上游版本修复了,但如果没有更新版本,这些问题还会存在。

  • etcd client 问题:当三台 Master 节点挂掉一台时,apiserver 可能仍然连接的是停止服务的那台 Master 节点上的 etcd ,这样 apiserver 无法获取和更新最新的集群状态,导致可能通过 kubectl get node 查询集群的状态,在一个节点上查询到的是三个节点全正常,另外一个节点显示有一台 not ready。
  • default/kubernetes svc 问题:一台 Master 节点故障时,default/kubernetes 这个服务不会像其他服务那样,去更新它的 endpoint,异常的 Master 节点 IP 仍然会保留在 endpoint 里面。这样许多通过 svc 方式来访问 apiserver 的应用都会出问题。默认 svc 的实现是通过 iptables 规则来实现的。目前的 kubernetes svc 会根据 client IP 做会话保持,这样如果访问的恰好是坏掉的 Master 节点 IP,这个节点上的 kubernetes svc 就会一直不可用了。如果去掉会话保持,会有三分之一的概率服务不可用。
详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

抛开上面提到的两个问题,还是电力故障的情况,这次情况比较糟糕,所有节点都受到了影响。但运气比较好,电力很快就恢复了,这个时候,集群服务会怎样呢?

场景一:负载均衡服务没有恢复,Master 节点很快恢复正常了。因为负载均衡还未恢复,所有 Node 节点都会认为是不可用的,导致的一个可能后果是,所有 Node 上的服务都重新调度并在 Master 节点创建,Master 节点负载会非常高。哪怕后面 LB 恢复了,master 节点的任务也不会自己迁出,集群的负载会极度不均衡。

场景二:负载均衡服务正常,Master 节点和 Node 节点都在快速的启动服务中。这个时候,如果 Node 节点规模很大,apiserver 和 etcd 的请求会非常的多。比较糟糕的情况是,Master 节点的 etcd 因为负载太高不能正常提供服务,导致 Node 节点注册失败,然后不断尝试重新注册 Node;哪怕负载降下来后,Node 节点全部注册成功,大量应用重新调度,产生大量的事件,etcd 很可能马上又坏掉了。这个时候,就需要对 apiserver 做限流了,防止突发的压力增长导致集群不可用。

详解 Kubernetes 的稳定性和可用性详解 Kubernetes 的稳定性和可用性

处理异常

谈了很多异常的状态,那么有什么好的办法来处理这些异常呢?限于时间关系,以下图为例给大家简单讲讲如何处理异常。

详解 Kubernetes 的稳定性和可用性
  • Symptom:通常发现异常时,是因为发现了一些不寻常的征状,比如某个服务不可用了,某个 pod 卡在了 terminating 状态;某个创建的 deployment 没有看到运行的 pod。根据这些征状,我们对于出现的异常有了一个初步的了解,便于借助工具做进一步的诊断。
  • Tools:诊断问题时,我们可以借助许多工具。比如 kubectl describe 来查看事件,kubectl logs 来查看日志,nsenter 进入容器的命名空间诊断问题,tcpdump 抓包来诊断网络问题等。借助这些工具,和诊断的一些结论,我们可以猜测可能的原因
  • Root Cause:导致异常的原因多种多样,异常的直接原因,借助工具可以快速发现,比如创建了 deployment 没有创建出 pod 原因是节点资源不足。我们可以继续追踪这个异常,为什么会突然资源不足了呢,借助工具可以发现是有一个节点不可用了。继续追查,可能是这个节点的 kubelet 异常退出了。通过一步步,找到了根本原因,才能从根源上解决这个问题。

上图中列出了一些有趣的 Root Cause,比如内核的 panic,dockerd 卡死,错误的挂载目录,配置了错误的网络策略等。

我的经验分享

这里给大家分享一下经验:

  • 借助日志系统和监控系统发现和诊断异常
  • 优先查看节点的负载情况,确保不是资源不足,磁盘写满导致的
  • 诊断问题不仅限于 Kubernetes 本身,相关的存储、网络、容器运行时等都可能出问题
  • 不要忽略硬件本身的问题,比如磁盘本身有故障
详解 Kubernetes 的稳定性和可用性

今天的分享到这里,感谢大家!

本文转自kubernetes中文社区-详解 Kubernetes 的稳定性和可用性