关于k8s集群高可用性的探究

  1. k8s的高可用的核心是什么?

说到核心、本质

意味着要从物理层来考虑技术

k8s是一个容器编排管理工具,k8s受欢迎的时机

是docker容器受欢迎时,因为太多的docker容器,管理起来是一个大工程

那么刚好k8s是google自己用了十来年的borg系统的开源版

google早就用这个来编排管理容器了,所以开源之后,竞品也选择了支持k8s

一起发展

google把这个开源并给了cloud native computing foundation云原生基金会之后

还给了一个项目,算是cloud native foundation云原生基金会的第二个项目

是borgmon,全称是 borg monitor,borg的班长,borg的监视器,也就是borg的监控

borg变成了k8s

borgmon变成了prometheus

这也是为什么监控k8s集群,基本上都是用prometheus了。

那么k8s高可用的核心本质是什么呢?

是容器镜像和数据库

image 和 etcd

如果一个k8s集群的image是ok的,etcd是ok的

整个集群暂时由于计算压力也好,网络问题也好,暂时休息了

那么用image和etcd就可以快速恢复集群。

image属于生产资料级别的东西

可以认为,对于计算机来讲,最底层的价值生产资料是物理层的设备

具体来讲,主要是光、电、半导体材料。

我们不延伸,因为精密如芯片,也是由半导体材料来实现,包括光

比如极紫外光

那么计算机的底层原来是电荷记录数据,光纤和铜缆传输电荷记录的数据,

半导体材料存储电荷,和高低电荷的各种逻辑运算,加减乘除,与或非

这些东西是计算机通用的底层

那么k8s的底层是什么

k8s是在物理硬件(光、电、半导体材料)的基础上,以容器镜像image为生产资料

产生一大堆的pod,对于pod不够清晰的管理员来讲,理解为容器,也可以,更加直观

因为pod里面的核心是主容器

虽然主容器还带着一堆小弟

比如打前站的initcontainer,初始化容器

开局热场选手,poststart hook 开始后的钩子函数,

用脚本要把什么服务开局的时候搞起来;

散会的时候,prestop hook 停止前的钩子函数,主容器关闭的时候要干点什么,

用自定义脚本写进去。

还有三个容器探针

就跟三个上级一样,一个人干活,三个人管

一个主容器干活,三个探针管着它

startupprobe,监控主容器启动的时候,什么服务跟着启动了没

没启动的话,怎么搞?资源文件里面的自定义脚本写出来

startupprobe这个上级就开始按着这个脚本管理主容器了

如果主容器没有实现它开局要弄的效果,它就会决定怎么搞

重启主容器还是怎么样

livenessprobe,意思是容器还在转着没,running没,

如果容器没有在转着,那么它就去用镜像重建容器还是怎样,

如果容器在正常跑着,容器里面装的就是进程

容器就是这个进程需要的依赖环境,包括环境变量什么的

但是不包括操作系统,这也是容器化和虚拟化本质的区别之一

比较重要,虚拟化是得给虚拟机搞出来一个虚拟操作系统

虽然这个虚拟操作系统的很多东西可以直接用真机操作系统的

但总归是得搞出来个虚拟操作系统给虚拟机用

而容器化不需要这个

容器里面就是什么环境变量啊、依赖包啊

比如nginx进程的容器,需要nginx的主程序

nginx软件包的那一堆东西,包括一些要用的nginx模块

比如stub_states_on,统计网站访问数据的这个功能模块

就是这些必须要有的东西,得弄到镜像里,起容器的时候

把这些0和1读起来,产生一个读写层

读写层再怎么折腾,跟镜像没关系

因为镜像是只读的一层一层的文件

容器是在这个只读层上面再新建一个读写层

除非要用容器做镜像,否则容器再怎么折腾

不影响产生容器的模版,也就是镜像这个多层的只读文件。

还有一个readinessprobe,字面意思上也可以看出来

就是ready了还是没ready?

谁ready了还是没ready?

就是主容器

因为这个readinessprobe探针,也是主容器的上级

等于它有三个上级,

startupprobe 管容器启动情况

livenessprobe 管容器运行情况

readinessprobe 管容器准备好跑服务了没

如果没就怎样,探针资源文件里面写了嵌入式脚本

如果都ok,那就ok

这三个探针和两个钩子函数和初始化容器

和核心的主容器

都是放在pod里面的东西

所以pod可以理解为一个主容器和它的领导以及伙伴们。


再说回k8s高可用的核心

k8s要跑任务,真正在一线干活的是主容器

其它很多都是辅助,后勤,还有很多领导

那么从跑计算任务的角度来讲

主容器是核心

那么主容器的核心又是什么呢?

就是镜像了,image

只要镜像ok

那么主容器就可以ok

用runtime拿着镜像跑容器就行了

这个相对来说不难

因为runtime现在默认的是containerd

可以理解为一个符合oci标准的docker

docker run 就能跑容器

containerd 也能run

跑容器出来

podman这个管容器的程序,也可以

所以核心不是docker还是containerd、podman

核心是这个镜像

如果是官方镜像,那么从官方拉一个也不是特别麻烦

如果是自定义的镜像,而且自定义的配置有点多,这个镜像的高可用就比较重要

用私有镜像仓库harbor来管理自己的私有镜像

而harbor是一个服务,用程序运行的服务

harbor支持分布式,所以,项目镜像数据非常重要的时候,

配置harbor仓库的分布式高可用,是一个比较重要的点,

对于k8s的高可用来说。


对于k8s的高可用的另一个核心,是etcd数据库

etcd数据库里面存放的是k8s集群的各种各样状态信息

谁干了什么,哪个组件又怎么样了,怎么配置的,怎么使用的

kube-apiserver忙来忙去都忙了写什么

各个节点都在干啥

各个pod都在干啥

什么服务什么时候干了什么

这些事情,都记录在etcd数据库里面

所以,其他服务,不管是计算的还是监控的,还是利用内核,在内核那注册服务的kube-proxy这些

可以简单这么理解,k8s集群上所有产生数据的动作都在etcd数据库里面记录了

那么如果k8s集群因为什么原因,休息了

那么etcd数据库是ok的

就可以利用etcd数据库里面的数据来恢复集群

跟那个mysql数据库的binlog日志有点像

只要是写的操作,就记录在这个binlog日志里面

mysql的主从同步就是从机器用io线程从主机器那里把binlog日志读过来

然后在从机器上用sql线程把这个binlog日志重跑一遍

那么数据库所有写操作的东西就复制过来了

而binlog日志,其实是binary log

也就是二进制的日志,可以理解为各种0和1的组合

的日志,对于数据库来讲,记录的是写操作的数据,

把这些跑一遍,数据库就备份了。

那么etcd数据库是k8s高可用的核心

所以k8s要做成高可用集群

核心就是etcd数据库高可用

和harbor仓库高可用

这两个都可以单点跑

也可以做成分布式集群

etcd用raft一致性算法来保证数据的一致性和顺序性

所有的写操作都需要通过raft算法达成一致后才能提交

那么把etcd数据库做成高可用,一般是3个节点,如果高可用非常重要

那么就部署5个节点以上

有两种部署方式

一种是把master节点做成3个,每个master节点上

有kube-apiserver scheduler controller-manager etcd

当然也有kube-proxy和kubelet

kube-proxy是旁路模式,调用ipvs内核模块,来进行负载均衡

比如一个clusterip服务创建出来了,那么clusterip通过selector选择器选择

的那些pod,自动进行负载均衡,比如一个clusterip服务,对应着

3个后端pod,那么clusterip服务接到的流量,为什么能够负载均衡的给

pod呢,这个就是kube-proxy干的事

它去找内核模块ipvs说,你看,我这搞了个服务

这个得负载均衡,你给我给这个clusterip生成一个ip地址

就是虚的

然后把这几个后端pod的ip加入到lvs负载均衡集群

就让它们负载均衡的去跑就行了


etcd数据库高可用的另一种方式

是把etcd数据库和k8s集群的master组件不部署在同一个节点上

专门把etcd数据库集群独立出来,搞一个高可用的

etcd数据库集群,k8s集群要读和写数据,就可以etcd数据库交互就可以了

那么这样,

把etcd和harbor仓库都独立出来

虽然harbor仓库本身就是独立的机器

暂且这么说

就会有一个图

前面是一个etcd高可用分布式集群,中间是k8s主节点和计算节点集群,后面是harbor镜像仓库集群

那么,这样一个架构

保证etcd数据库的分布式高可用,后生产资料harbor仓库的分布式高可用

那么整个k8s集群的高可用基本就ok了

看着核心是k8s集群,但是考虑高可用方面来讲

似乎核心不在k8s,而在前面的etcd数据和后面的harbor镜像仓库

这个就跟一些竞争一样

前面的侦测信息

和后面的后勤保障

很重要

说,兵马未动,粮草先行

再说,那啥那啥的是经济


放到k8s的高可用来说,核心是前面的etcd数据库分布式集群,和后面的harbor镜像仓库分布式集群

有了这个,服务休息了,可以启动,k8s的工作节点怎么样了,也可以直接用数据库恢复服务。

那么问题是,kube-apiserver kube-controller-manager schdeluer,这几个主节点上的核心组件

的配置信息和各种信息怎么办

这些也都在etcd数据库上记录着

关于用kubeadm init初始化集群的时候,我们用到的一些文件信息,需要做备份保存。


那么对于k8s集群中,各种资源文件,之前都是自己写的

需要写一个保存一个吗

不用

只要对etcd数据库做了快照备份snapshot save

那么用etcdctl snapshot restore用数据库把集群恢复起来之后

用kubectl get ... -o yaml > filename

就可以把yaml格式的资源文件恢复出来


总的来说,做三个步骤

  1. etcd数据库的分布式集群,加定期备份快照

  2. harbor仓库的分布式集群

  3. 初始化集群用到的kubeadm配置文件,kube-apiserver、controller-manager、scheduler的配置文件,证书和密钥文件。做备份。

那么如果k8s集群休息了

k8s集群需要从零开始重新搭建

利用这三个部分的准备工作的内容

就可以从零把集群再恢复起来。

这个也就是k8s高可用的核心部分了。


那么针对这些核心内容,要实践中做到高可用,可以用跨地区备份的方式

和多云平台的备份方式,来进一步加强高可用性。

etcd数据库高可用的两种方式:堆叠式和外部式

资料来源:k8s官网

高可用拓扑选项 | Kubernetes本页面介绍了配置高可用(HA)Kubernetes 集群拓扑的两个选项。你可以设置 HA 集群:使用堆叠(stacked)控制平面节点,其中 etcd 节点与控制平面节点共存 使用外部 etcd 节点,其中 etcd 在与控制平面不同的节点上运行 在设置 HA 集群之前,你应该仔细考虑每种拓扑的优缺点。说明: kubeadm 静态引导 etcd 集群。 阅读 etcd 集群指南以获得更多详细信息。堆叠(Stacked)etcd 拓扑 堆叠(Stacked)HA 集群是一种这样的拓扑, 其中 etcd 分布式数据存储集群堆叠在 kubeadm 管理的控制平面节点上,作为控制平面的一个组件运行。每个控制平面节点运行 kube-apiserver、kube-scheduler 和 kube-controller-manager 实例。 kube-apiserver 使用负载均衡器暴露给工作节点。每个控制平面节点创建一个本地 etcd 成员(member),这个 etcd 成员只与该节点的 kube-apiserver 通信。 这同样适用于本地 kube-controller-manager 和 kube-scheduler 实例。这种拓扑将控制平面和 etcd 成员耦合在同一节点上。相对使用外部 etcd 集群, 设置起来更简单,而且更易于副本管理。然而,堆叠集群存在耦合失败的风险。如果一个节点发生故障,则 etcd 成员和控制平面实例都将丢失, 并且冗余会受到影响。你可以通过添加更多控制平面节点来降低此风险。因此,你应该为 HA 集群运行至少三个堆叠的控制平面节点。这是 kubeadm 中的默认拓扑。当使用 kubeadm init 和 kubeadm join --control-plane 时, 在控制平面节点上会自动创建本地 etcd 成员。https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/ha-topology/

这张图能大概说明kube-proxy组件的工作流程,但是也有一点需要清晰。

clusterIP这个服务本身,和这个服务对应的ip,比如10.254.xx.xx

是由kube-apiserver,也就是api服务器来产生的

就是apiserver这个服务器创建了clusterIP这个服务,并且给它了一个预定义范围内的

ip地址,当然这个ip地址也可以固定指定

然后kube-proxy是监听着apiserver的,

一旦apiserver创建了服务

kube-proxy就会去找ipvs内核模块,做出来一个lvs负载均衡规则,

将clusterip和后端pod连起来,并且由负载均衡的规则,比如轮询,加权轮询,最少连接数


那么再说一下,服务本身和服务的ip由apiserver产生

服务到后端的负载均衡由kube-proxy监听apiserver然后找ipvs内核模块

生成负载均衡规则

那么用到ingress,比如为什么可以通过服务名就访问到后端的服务呢

ingress的配置规则就是访问什么url

就给到后端的服务名加端口号

这是怎么连上的呢

是通过coredns的自动注册功能

当apiserver创建一个服务时

coredns会监听着apiserver并感知到这一个行为

coredns会根据服务的元数据生成dns记录

总之,有了dns解析,就可以通过服务名找到具体的服务。

相关推荐
aherhuo5 小时前
kubevirt网络
linux·云原生·容器·kubernetes
陌北v16 小时前
Docker Compose 配置指南
运维·docker·容器·docker-compose
catoop6 小时前
K8s 无头服务(Headless Service)
云原生·容器·kubernetes
阿里嘎多学长6 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
小峰编程7 小时前
独一无二,万字详谈——Linux之文件管理
linux·运维·服务器·云原生·云计算·ai原生
小马爱打代码7 小时前
云原生服务网格Istio实战
云原生
liuxuzxx7 小时前
1.24.1-Istio安装
kubernetes·istio·service mesh
G_whang8 小时前
windos 安装docker
运维·docker·容器
道一云黑板报8 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
运维小文8 小时前
K8S中的PV、PVC介绍和使用
docker·云原生·容器·kubernetes·存储