「Kubernetes」- 集群与高可用

问题描述

在 Kubernetes 的官方文档中,已经介绍搭建集群的方法,以及各种拓扑的利弊(为了保证知识是有效的,建议定期阅读官方文档);

在进行研究和对比之后,我们便编写该笔记,用于日后指导我们如何选择高可用集群的拓扑结构,以及注意需要关注的问题;

该部分笔记将记录:在 Kubernetes 中,搭建高可用的 Kubernetes Cluster 的选择,以及相关问题处理,并附有集群搭建笔记;

解决方案

在生产环境中,集群的高可用(比如 容灾、稳定性、故障恢复 等等),是必须考虑的问题;

创建高可用集群:
Creating Highly Available clusters with kubeadm
Set up High-Availability Kubernetes Masters

集群拓扑类型概览

高可用集群有两种方案:
1)With stacked control plane nodes(内部 etcd 服务)
2)With an external etcd cluster(外部 etcd 服务)

两种方案各有利弊,在文档 Options for Highly Available topology 中有所描述,需要根据各自需求进行选择;

内部 etcd 服务(Stacked etcd topology)

该类型高可用集群集群,提供数据存储的 etcd 服务在集群(由节点组成,由运行主节点组件的 kubeadm 管理)内部;

1)主机节点运行 APIServer、Scheduler、Controller-Manager 组件,而 APIServer 会暴露为工作节点;
2)每个主机节点会创建本地 etcd 成员,它只与本地的 APIServer 通讯;Controller-Manager、Scheduler 只与本地 APIServer 通讯;
3)对于 Load Balancer 服务,可以选择独立主机来运行,或者在每台主节点上运行;

优点:
1)节省主机:该集群 etcd 成员与主节点在相同节点,相对于外部 etcd 服务集群,该方案需要的主机数量少;
2)部署简单:集群部署比较简单,复制易于管理;

缺点:
1)如果主节点故障,则将无法访问 etcd 服务(因此需要多个主节点),此外该节点的 kube-apiserver、kube-scheduler、kube-controller-manager 组件也将不可用;
2)正如官方文档所说,最少需要 3 个 Control Plane 节点。两个节点是无法容错的,因为一个节点失败后,etcd 无法完成选举,导致 etcd 不可用,进而导致集群不可用;

集群部署参考:
1)1.17, keepalived, Stacked Control Plane
2)1.18, kube-vip, Stacked Control Plane

外部 etcd 服务(External etcd topology)

该类型高可用集群集群,提供数据存储的 etcd 服务在集群(由节点组成,由运行主节点组件的 kubeadm 管理)外部;

主机节点运行 kube-apiserver、kube-scheduler、kube-controller-manager 组件,而 kube-apiserver 会暴露为工作节点。但是 etcd 运行在独立主机,每个 etcd 服务与每个主节点上的 kube-apiserver 通讯;

优点:
1)该类性集群解耦主节点与数据存储(etcd),因此主节点故障或者 etcd 故障不会影响到集群冗余;

缺点:
1)更多主机:至少三台主机运行 etcd 服务,至少三台主机运行主机节点;

集群升级流程概览

不同的高可用集群方案具有不相同的集群升级方法,参考 Upgrading kubeadm clusters 文章;

该部分将概述如何升级由 kubeadm 命令创建的高可用集群(该高可用集群应是依照官方「Creating HA clusters with kubeadm」文档进行搭建的)

开始升级之前

升级不能跨越次版本号:在文档中提及,即可以从 1.12 升级到 1.13 版本,但是不能从 1.12 直接升级到 1.14 版本;
集群需要运行在 1.12.0 或以后版本,但是不能 1.12 版本;
系统 SWAP 分区需要被禁用;
集群需要使用静态的「Control Plane」和「etcd」POD 实例;
仔细阅读「发行说明」页面;
确定已经备份重要组件,比如存储在数据库的应用状态。虽然升级只涉及 Kubernetes 组件,但是备份永远是最佳实践;
检查「Upgrading/downgrading kubeadm clusters between v1.12 to v1.13」中的要求;
所有命令需要以 root 用户执行;
在升级后,所有容器将重启,因为容器 spec hash 发生变化(Container spec hash changed. Container will be killed and recreated. #53644

确定目标版本

假如目前为 1.12.1 版本,而目标为 1.16.2 版本,但是不能跨次版本号,所以只能升级到 1.13 的最后一个版本:

# yum list --showduplicates kubeadm --disableexcludes=kubernetes | grep 1.13
kubeadm.x86_64                     1.13.12-0                      kubernetes-ali

// 很显然,我们要升级到 1.13.12-0 版本(我使用阿里云的源仓库);

升级 Master 节点

首先,升级 kubeadm 命令:

// 后面的 kubelet-1.13.12-0 是我们自己添加的(如果不添加该包,系统 kubelet 会被升级到 1.16.3-0 版本)
yum install -y --disableexcludes=kubernetes kubeadm-1.13.0 kubelet-1.13.0
yum install -y --disableexcludes=kubernetes kubeadm-1.13.12-0 kubelet-1.13.12-0

# 版本回退
yum downgrade -y kubeadm-1.12.1 --disableexcludes=kubernetes kubelet-1.12.1 kubernetes-cni-0.6.0-0.x86_64

# 升级到其他版本
yum install -y kubeadm-1.12.10 --disableexcludes=kubernetes kubelet-1.12.10

# 验证版本
kubeadm version

然后,检查集群是否可升级,并获取可升级版本:

# 该命令将输出可用版本,也将输出升级命令
kubeadm upgrade plan

执行升级命令:

kubeadm upgrade apply v1.12.10

kubeadm upgrade apply v1.12.10 --config kubeadm-config.yaml # 使用自定义配置,以拉去镜像

kubeadm upgrade apply

该命令执行如下动作:
1)检查集群处于可升级状态:可以访问 API Server 服务;所有节点为 Ready 状态;「Control Plane」处于健康状态;
2)强制执行版本外泄策略;
3)确保「Control Plane」镜像可以拉取;
4)升级「Control Plane」组件。如果失败,则回滚;
5)应用新的 kube-dns 与 kube-proxy 清单文件,并强制所有必要的 RBAC 规则被创建;
6)创建 API Server 的新证书及密钥文件,并备份旧文件(如果在 180 天内过期);

升级 Worker 节点

在每个节点上执行如下命令,以驱除工作负载:

kubectl drain '<NODE_NAME>' --ignore-daemonsets

升级软件包

yum install -y kubeadm-1.12.10-0 kubelet-1.12.10-0 --disableexcludes=kubernetes

在除了主节点外的所有节点中,升级 kubelet 配置。执行如下命令:

kubeadm upgrade node config --kubelet-version $(kubelet --version | cut -d ' ' -f 2)

systemctl restart kubelet
systemctl status kubelet

执行如下命令恢复工作负载:

kubectl uncordon '<NODE_NAME>'
kubectl get nodes

从失败中恢复

如果kubeadm upgrade失败并且没有回滚,比如在执行期间意外关机,可再次运行kubeadm upgrade命令。该命令幂等的,它会确保最终状态与期望状态是一致的;

如果从坏状态恢复,可以执行kubeadm upgrade --force命令,不改变集群运行的版本;

常见问题梳理

如果 Master 全部失败,会发生什么?

What happens when Kubernetes master fails? – Quora

我们一直担心如果 Master 节点失败,那我们部署在集群里的监控服务将无法正常运行。再后来我们了解到,如果 Master 节点全部失败,集群的管理功能将会丢失,比如 Pod 失败退出之后不会被重启,我们无法在集群中创建新的对象。但是,这并不会影响正在运行的 Pod 实例,外部依旧能够访问;

# 01/10/2023 话虽如此,但是在实际的使用过程中,如果 Master Node 故障,集群工作负载还是会出现问题;

关于“多环境共用集群”的优劣

部署高可用的 Kuernetes Cluster 需要多台主机,成本较高。其中一种解决方法为:多环境共用同个集群,比如 Production 与 Staging 位于相同集群,并做好资源限制;

那么问题是,我们是否应该采用这种方案呢?

在进行调研对比之后,我们并未采用“多环境共用集群”的方案,原因如下:
1)因为该方案并没有解决其他问题,只是单纯节省资源,
2)它带来的其他优势可以忽略不计:
3)于此同时,还带来其他问题。比如:需要严格控制资源限制、跨命名空间服务访问(同个集群里一定会面临命名冲突的问题,或者会转移为其他问题)

官方文档 Using Kubernetes Namespaces to Manage Environments/Caveats 也进行一定程度的说明,并未鼓励使用该方法;

换个角度,如果这些主机成本我们无法负担,那也许是因为我们的业务还没有那么大规模以至于要使用 Kubernetes 服务;

相关链接

Creating Highly Available clusters with kubeadm
Creating High Available Baremetal Kubernetes cluster with Kubeadm and Keepalived (More Simple Guide)

参考文献

How to Save Big Using One Kubernetes Cluster for Multiple Environments | Blue Sentry
Checklist: pros and cons of using multiple Kubernetes clusters, and how to distribute workloads between them
Multiple environments (Staging, QA, production, etc) with Kubernetes – Stack Overflow
Multiple stages within a Kubernetes cluster – JAXenter
kubernetes – can we create 2 node master-only cluster with High availability – Stack Overflow