Kubernetes集群高可用


Kubernetes具有自愈能力,它跟踪到某工作节点发生故障时,控制平面可以将离线节点上的Pod对象重新编排至其它可用工作节点运行,因此,更多的工作节点也意味着更好的容错能力,因为它使得Kubernetes在实现工作节点故障转移时拥有更加灵活的自由度。而当管理员检测到集群负载过重或无法容纳其更多的Pod对象时,通常需要手动将节点添加到群集,其过程略繁琐,Kubernetes cluster-autoscaler还为集群提供了规模按需自动缩放的能力。

然而,添加更多工作节点并不能使群集适应各种故障,例如,若主API服务器出现故障(由于其主机出现故障或网络分区将其从集群中隔离),将无法再跟踪和控制集群。因此,还需要冗余控制平面的各组件以实现主节点的服务高可用性。基于冗余数量的不同,控制平面能容忍一个甚至是几个节点的故障。一般来说,高可用控制平面至少需要三个Master节点来承受最多一个Master节点的丢失,才能保证等待状态的Master能保持半数以上以满足节点选举时的法定票数。一个最小化的Master节点高可用架构如下图所示。
图片_1.png

最小化Master节点高可用架构

Kubernetes组件中仅etcd需要复杂逻辑完成集群功能,其它组件间的松耦合特性使得能够通过多种方式实现Master节点的高可用性,上图是较为常用的一种架构,各架构方式也通常有一些共同的指导方针:
  • 利用etcd自身提供的分布式存储集群为Kubernetes构建一个可靠的存储层;
  • 将无状态的API Server运行为多副本,并在其前端使用负载均衡器调度请求;需要注意的是,负载均衡器本身也需要高可用;
  • 多副本的控制器管理器,并通过其自带的leader选举功能(--leader-election)选举出主角色,余下的副本在主角色故障时自动启动新一轮的选举操作;
  • 多副本的调度器,并通过其自带的leader选举功能(--leader-election)选举出主角色,余下的副本在主角色故障时自动启动新一轮的选举操作;


etcd高可用

分布式服务之间进行可靠、高效协作的关键前提是有一个可信的数据存储和共享机制,etcd项目正是致力于此目的构建的分布式数据存储系统,它以键值格式组织数据,主要用于配置共享和服务发现,也支持实现分布式锁、集群监控和leader选举等功能。

etcd基于Go语言开发,内部采用Raft协议作为共识算法进行分布式协作,通过将数据同步存储在多个独立的服务实例上从而提高数据的可靠性,避免了单点故障导致数据丢失。Raft协议通过选举出的leader节点实现数据一致性,由leader节点负责所有的写入请求并同步给集群中的所有节点,在取决半数以上follower节点的确认后予以持久存储。这种需要半数以上节点投票的机制要求集群数量最好是奇数个节点,推荐的数量为3个、5个或7个。etcd集群的建立有三种方式:
  • 静态集群:事先规划并提供所有节点的固定IP地址以组建集群,仅适合于能够为节点分配静态IP地址的网络环境,好处是它不依赖于任何外部服务;
  • 基于etcd发现服务构建集群:通过一个事先存在的etcd集群进行服务发现来组建新集群,支持集群的动态构建,它依赖于一个现存可用的etcd服务;
  • 基于DNS的服务资源记录构建集群:通过在DNS服务上的某域名下为每个节点创建一条SRV记录,而后基于此域名进行服务发现来动态组建新集群,它依赖于DNS服务及事先管理妥当的资源记录;


一般说来,对于etcd分布式存储集群来说,三节点集群可容错一个节点,五节点集群可容错两个节点,七节点集群可容错三个节点,依次类推,但通常多于七个节点的集群规模是不必要的,而且对系统性能也会产生负面影响。

Controller Manager和Scheduler高可用

Controller Manager通过监控API Server上的资源状态变动并按需分别执行相应的操作,于是,多实例运行的kube-controller-manager进程可能会导致同一操作行为被每一个实例分别执行一次,例如某一Pod对象创建的请求被3个控制器实例分别执行一次进而创建出一个Pod对象副本来。因此,在某一时刻,仅能有一个kube-controller-manager实例正常工作状态,余下的均处于备用状态,或称为等待状态。

多个kube-controller-manager实例要同时启用“--leader-elect=true”选项以自动实现leader选举,选举过程完成后,仅leader实例处于活动状态,余下的其它实例均转入等待模式,它们会在探测到leader故障时进行新一轮选举。与etcd集群基于Raft协议进行leader选举不同的是,kube-controller-manager集群各自的选举操作仅是通过在kube-system名称空间中创建一个与程序同名的Endpoint资源对象实现。
≈~]$ kubectl get endpoints -n kube-system
NAME                       ENDPOINTS       AGE
kube-controller-manager   <none>           13h
kube-scheduler            <none>           13h


这种leader选举操作是分布式锁机制的一种应用,它通过创建和维护Kubernetes资源对象来维护锁状态,目前Kubernetes支持ConfigMap和Endpoints两种类型的资源锁。初始状态时,各kube-controller-manager实例通过竞争方式去抢占指定的Endpoint资源锁。胜利者将成为leader,它通过更新相应的Endpoint资源的注解control-plane.alpha.kubernetes.io/leader中的“holderIdentity”为其节点名称从而将自己设置为锁的持有者,并基于周期性更新同一注解中的“renewTime”以声明自己对锁资源的持有状态以避免等待状态的实例进行争抢。于是,一旦某leader不再更新renewTime,等待状态的各实例将一哄而上进行新一轮竞争。
~]$ kubectl describe endpoints kube-controller-manager -n kube-system
Name:         kube-controller-manager
Namespace:    kube-system
Labels:       <none>
Annotations:  control-plane.alpha.kubernetes.io/leader={"holderIdentity":"master1.ilinux.io_846a3ce4-b0b2-11e8-9a23-00505628fa03","leaseDurationSeconds":15,"acquireTime":"2018-09-05T02:22:54Z","renewTime":"2018-09-05T02:40:55Z","leaderTransitions":1}'
Subsets:
Events:
Type    Reason          Age   From                     Message
----    ------          ----  ----                     -------
Normal  LeaderElection  13h   kube-controller-manager  master0.ilinux.io_e8fca6fc-b049-11e8-a247-000c29ab0f5b became leader
Normal  LeaderElection  5m   kube-controller-manager  master1.ilinux.io_846a3ce4-b0b2-11e8-9a23-00505628fa03 became leader

kube-scheduler的实现方式与此类似,只不过它使用自己专用的Endpoint资源kube-scheduler。


提示:基于kubeadm部署高可用集群的方式可参考文档:https://kubernetes.io/docs/set ... lity/给出的步骤进行。
本文摘编自《Kubernetes进阶实战》,经出版方授权发布。

0 个评论

要回复文章请先登录注册