前文我们搭建了3Master节点4Node节点的高可用集群,本文讨论一下过程中的总结。
高可用策略
前文说了Kubernetes集群高可用的关键在于Master节点的高可用,官方也给出了2种高可用拓扑结构:
Stacked etcd topology (堆叠etcd)
该方案中,所有Master节点都部署kube-apiserver,kube-controller-manager,kube-scheduler,以及etcd等组件;kube-apiserver均与本地的etcd进行通信,etcd在三个节点间同步数据
External etcd topology (外部etcd)
该方案中,所有Master节点都部署kube-apiserver,kube-controller-manager,kube-scheduler组件,而etcd 分布式数据存储集群独立运行。这种拓扑结构解耦了Master节点组件和 etcd 。
vcontrol plane node 即Master节点
高可用方案分析
通过官方给的拓扑图,有2个关键的地方:
- etcd
- load balancer
也就是说,只要完成上述两者的高可用,整个Kubernetes集群即达到了高可用的目的。
etcd高可用
Kubernetes选用etcd作为它的后端数据存储仓库也正是看重了其使用分布式架构,没有单点故障的特性。虽然单节点的etcd也可以正常运行,但是推荐的部署方案均是采用3个或者5个节点组成etcd集群,供Kubernetes使用。
etcd的高可用方案是官方2种拓扑结构中最明显的差异,区别就是etcd的位置不同。官方对于2种etcd的方案也做了比较,我总结如下:
堆叠方式
- 所需硬件资源少
- 部署简单、利于管理
- 横向扩展容易
- 缺点在于一台宿主机挂了,Master节点和etcd就少了一套,会大大降低集群冗余度和健壮性。
外部方式
- Master节点和etcd解耦,Master节点挂了后不影响etcd,集群健壮性增强
- 缺点是硬件资源几乎2倍于堆叠方案,并且运维复杂度会变高。
不管从我个人角度还是企业角度,我毫不犹豫选择堆叠方式,横向扩展的便捷性以及对于硬件的需求这2点理由就足够了。另外在搜集资料的时候还发现了一篇文章-Scaling Kubernetes to 2,500 Nodes,里面实践证明,etcd挂载本地ssd的方式会大幅提高超大规模(节点大于2000)集群性能。
除了上述2种方式之外,在网上冲浪时还发现了一篇文章提到另一种方式:
CoreOS提出的self-hosted etcd方案
将本应在底层为Kubernetes提供服务的etcd运行在Kubernetes之上。实现Kubernetes对自身依赖组件的管理。在这一模式下的etcd集群可以直接使用etcd-operator来自动化运维,最符合Kubernetes的使用习惯。
当然,这种方式资料并不多,也没找到具体的实践方式,并且在官方文档中多带有实验性
的前缀,并且官方文档如下说明:
- The self-hosted portion of the control plane does not include etcd, which still runs as a static Pod.
也不知道是曾经版本中支持过后来取消还是怎么的,在此不做深究吧,只是提一句题外话。一切还是以官方文档的两种方式为准。
kube-apiserver高可用
在官方的拓扑图中,除了etcd以外很容易忽略load balancer
这个节点。kube-apiserver
节点通过前置负载均衡器load balancer
实现高可用,但是目前尚没有官方的推荐方案。常用的思路或者方案大致归纳有以下几种:
外部负载均衡器
不管是使用公有云提供的负载均衡器服务或是在私有云中使用LVS或者HaProxy自建负载均衡器都可以归到这一类。负载均衡器是非常成熟的方案,如何保证负载均衡器的高可用,则是选择这一方案需要考虑的新问题。
目前网上大部分资料都是通过
HAproxy
实现kube-apiserver
的高可用并且通过Keepalived
方式确保HAproxy自身的高可用,前文我们使用的就是这种方式,刚入门随大流总没有错的。网络层做负载均衡
比如在Master节点上用BGP做ECMP,或者在Node节点上用iptables做NAT都可以实现。采用这一方案不需要额外的外部服务,但是对网络配置有一定的要求。
在Node节点上使用反向代理对多个Master做负载均衡
这一方案同样不需要依赖外部的组件,但是当Master节点有增减时,如何动态配置Node节点上的负载均衡器成为了另外一个需要解决的问题。
目前除了自己用的方式外,对于其他方式还需留待后续研究和尝试。
kube-controller-manager与kube-scheduler 高可用
这两项服务是Master节点的组件,他们的高可用相对容易,仅需要运行多份实例即可。Kubernetes自身通过leader election
机制保障当前只有一个副本是处于运行状态。
至于leader选举的机制,简单来说是:多个kube-controller-manager与kube-scheduler的副本对 endpoint 锁资源做抢占,谁能抢到并将自己的信息写入 endpoint的 annotation 中,谁就成为了leader,leader需要在可配置的一个间隔时间内更新消息,其他节点也能看见当前的leader和过期时间;当过期时间到并且leader没有更新后,其他副本会尝试去获取锁,去竞争leader,直到自己成为leader。
关于Kubernetes的高可用方案就总结这些。
ipvs VS iptables
上文部署过程中,我使用了ipvs的方式代替了默认的iptables,起初呢只是抱着不明觉厉,自定义的肯定要比默认的强哈的想法,事实上呢还是要自己调研对比下才行。
从前文集群配置文件kubeadm.yaml中可以看到ipvs配置是针对kube-proxy组件的。kube-proxy 是 Kubernetes 中的关键组件。他的角色就是在服务(仅限ClusterIP 和 NodePort方式)和其后端 Pod 之间进行负载均衡。kube-proxy 有三种运行模式,每种都有不同的实现技术:userspace、iptables 或者 IPVS。userspace 模式非常陈旧、缓慢,已经不推荐使用。
iptables
iptables 是一个 Linux 内核功能,是一个高效的防火墙,并提供了大量的数据包处理和过滤方面的能力。它可以在核心数据包处理管线上用 Hook 挂接一系列的规则。iptables 模式中 kube-proxy 在
NAT pre-routing
Hook 中实现它的 NAT 和负载均衡功能。这种方法简单有效,依赖于成熟的内核功能,并且能够和其它跟 iptables 协作的应用(例如 Calico)融洽相处。然而 kube-proxy 的用法是一种 O(n) 算法,其中的 n 随集群规模同步增长,这里的集群规模,更明确的说就是服务和后端 Pod 的数量。
ipvs
IPVS 是一个用于负载均衡的 Linux 内核功能。IPVS 模式下,kube-proxy 使用 IPVS 负载均衡代替了 iptable。这种模式同样有效,IPVS 的设计就是用来为大量服务进行负载均衡的,它有一套优化过的 API,使用优化的查找算法,而不是简单的从列表中查找规则。
这样一来,kube-proxy 在 IPVS 模式下,其连接过程的复杂度为 O(1)。换句话说,多数情况下,他的连接处理效率是和集群规模无关的。
另外作为一个独立的负载均衡器,IPVS 包含了多种不同的负载均衡算法,例如轮询、最短期望延迟、最少连接以及各种哈希方法等。而 iptables 就只有一种随机平等的选择算法。
IPVS 的一个潜在缺点就是,IPVS 处理数据包的路径和通常情况下 iptables 过滤器的路径是不同的。如果计划在有其他程序使用 iptables 的环境中使用 IPVS,需要进行一些研究,看看他们是否能够协调工作。(Calico 已经和 IPVS kube-proxy 兼容)
看完概念还是不明觉厉,这里我贴出一篇文章供大家了解一下kube-proxy 模式对比:iptables 还是 IPVS?这是一篇译文,原文地址Comparing kube-proxy modes: iptables or IPVS?,感谢二位作者,这篇文章详细对比了两种模式的优劣。我直接贴出结论:
在超过 1000 服务的规模下,kube-proxy 的 IPVS 模式会有更好的性能表现。虽然可能有多种不同情况,但是通常来说,让微服务使用持久连接、运行现代内核,也能取得较好的效果。如果运行的内核较旧,或者无法使用持久连接,那么 IPVS 模式可能是个更好的选择。
抛开性能问题不谈,IPVS 模式还有个好处就是具有更多的负载均衡算法可供选择。
如果你还不确定 IPVS 是否合适,那就继续使用 iptables 模式好了。这种传统模式有大量的生产案例支撑,他是一个不完美的缺省选项。
我自己含蓄的总结就是:以普通企业的业务规模,两者没有差异。
关于初始化集群时ipvs配置问题
在使用kubeadm初始化集群时,开启ipvs配置如下,这里我着实遇到一个小坑:
# 错误配置
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true # 这个配置错误错误错误!!!按照网上资料这样配,kubeproxy组件会启动失败并一直重试!!
mode: ipvs
# 正确配置
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
已经搭建好的集群中开启ipvs
修改kube-proxy配置
kubectl edit configmap kube-proxy -n kube-system
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: "ipvs" # 修改此处
nodePortAddresses: null
删除所有kube-proxy的pod
kubectl delete pod xxx -n kube-system
校验
kubectl logs kube-proxy-xxx -n kube-system
日志出现Using ipvs Proxier
即可
检查ipvs代理规则
kubectl get svc --all-namespaces
#可以看到service对应的很多规则
ipvsadm -ln
有趣的现象-kubelet的默认cgroup driver
在初始化过程中出现错误:
failed to create kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd"
前面我们在部署Docker时设置了cgroupfs driver
为systemd,因为Kubernetes官方这么建议,你这么建议就建议吧,为什么自己还默认cngroupfs?所以在实际部署时,Docker和kubelet都需要设置为systemd
。
Keepalived配置文件须知
检测脚本
vrrp_script chk_haproxy {
script "/bin/bash -c 'if [[ $(netstat -nlp | grep 9443) ]]; then exit 0; else exit 1; fi'" # haproxy 检测脚本,这里需要根据自己实际情况判断
interval 2 # 每2秒执行一次检测
weight 11 # 权重变化
}
检测健康的脚本需要根据实际情况判断,如果Haproxy是二进制方式安装,需要判断进程。如果是docker方式安装,光判断进程就无效了,需要判断Haproxy的端口号是否有监听存在。
当然,我觉得最完美的方式应该是判断apiserver的状态,这点还需要后续再完善,先留个问题待处理。
配置文件注意点
interface
默认的Keepalived文件
interface
是eth0interface eth0
此处要根据自己的实际情况,否则Keepalived会失败
unicast_peer
首先我的三台Master节点是跨网段的,keepalived默认的方式是组播,并不支持跨网段,所以我刚开始采用默认配置启动时出现了不同网段的2个Master,解决方法就是改成单播模式:
unicast_peer { 10.128.2.53 10.128.2.52 }
nopreempt 抢占/非抢占
抢占模式是当master从故障中恢复后,会将VIP从BACKUP中抢过来,非抢占模式是master恢复后不抢占backup升级为master后的vip。
vrrp_instance myland_slb { ... state MASTER # 状态 nopreempt #不抢占表示 priority 90 # 优先级(0~255) ... }
Kubectl get cs 废弃
在第一篇快速搭建集群时候遇到以上问题,并也给出了解决办法:检查配置文件/etc/kubernetes/manifests/kube-scheduler.yaml
与/etc/kubernetes/manifests/kube-controller-manager.yaml
并将两个配置文件的配置项- --port=0
均注释掉。
本次部署也按照此方法消除了错误,但是版本升级过后配置文件又恢复原状,这明显不符合常理,说明官方并不认同修改配置文件。于是乎查找资料,发现自1.19版本后kubectl get cs
已弃用,增加port=0
是为了符合 CIS kubernetes 安全白皮书要求而添加。不推荐开启此http端口。
参考文章:
直接查看相关组件pod运行状态即可
kubectl get po -n kube-system
配置自动补全命令
所有master节点执行
#安装bash自动补全插件
yum install bash-completion -y
设置kubectl与kubeadm命令补全,下次login生效
kubectl completion bash >/etc/bash_completion.d/kubectl
kubeadm completion bash > /etc/bash_completion.d/kubeadm
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。