将单点Control Plane的Kubernetes扩充为多个Control Plane实现集群高可用性
1656 字
8 分钟
将单点Control Plane的Kubernetes扩充为多个Control Plane实现集群高可用性
一、基础环境
- 一个已经全部节点都已Ready的kubernetes集群,包含一控制平面、二工作节点
- 两台台将要作为Control Plane加入集群的新虚拟机
- 使用kubeadm 1.31.14、kubelet 1.31.14 和 kubectl 1.31.14
- 两台虚拟机各部署一套Nginx + keepalived服务
二、配置Nginx + Keepalived
1. 安装并设置为开机自启
# 安装# conntrack是一个kubeadm在加入集群时所需的依赖,这里先安装一下防止加入集群失败yum install nginx keepalived conntrack -y
# 确保nginx有stream模块yum install nginx-mod-stream -y
# 设置开机自启systemctl enable --now nginxsystemctl enable --now keepalived2. 配置Nginx反向代理
修改/etc/nginx/nginx.conf文件如下:
user nginx;worker_processes auto;error_log /var/log/nginx/error.log;pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;
events { worker_connections 1024;}
### 重点是这一段,配置反向代理,将请求转发给三个control plane实现负载均衡stream { log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent'; access_log /var/log/nginx/k8s-access.log main;
upstream kubernetes-apiserver { server 192.168.100.8:6443 weight=5 max_fails=3 fail_timeout=30s; server 192.168.100.11:6443 weight=5 max_fails=3 fail_timeout=30s; server 192.168.100.12:6443 weight=5 max_fails=3 fail_timeout=30s; }
server { # listen可以选择任意没被占用的端口 listen 16443; # proxy_pass将请求转发到上面upstream中定义的server池 proxy_pass kubernetes-apiserver; }}###### 下面是默认配置,没有修改http { ... }3. 配置Nginx健康检查
创建文件/etc/nginx/conf.d/health.conf:
server { listen 20080; location /health { default_type text/plain; return 200 'ok'; }}这样,当 curl 127.0.0.1:20080失败时可以执行重启Nginx服务或者漂移动作
4. 配置keepalived
- 修改
/etc/keepalived/keepalived.conf文件如下
global_defs { # 本节点在 VRRP 集群中的唯一标识名,主节点用 NGINX_MASTER;备用节点需要改为 NGINX_BACKUP router_id NGINX_MASTER}# 健康检查脚本vrrp_script check_nginx { script "/etc/keepalived/check_nginx.sh" interval 3 # 健康检查间隔 timeout 2 # 脚本超时时间,超过2秒视为失败 fall 3 # 连续失败3次才认定为不健康 rise 2 # 连续成功2次才认定为恢复健康 weight -10 # 检查失败时本节点优先级降低10}vrrp_instance VI_1 { # 节点的初始角色,主节点用 MASTER;备用节点需要将此配置改为 BACKUP state MASTER # VVIP 绑定的网卡 interface eth0 # VRRP 组的唯一标识,同一组的主备节点必须相同 virtual_router_id 51 # 优先级,谁高谁当Master,需要将备用节点的priority设置低于主节点 priority 100 # MASTER 每隔多少秒向组播地址发送一次心跳,BACKUP 节点如果超过这个时间没收到心跳,就认为 MASTER 挂了并发起竞选 advert_int 1 # 主备节点之间通信的认证方式,防止局域网内其他机器伪造 VRRP 报文 # PASS是明文传输,安全性较低,生产环境建议用 AH authentication { auth_type PASS auth_pass 1111 } # 虚拟IP地址,此地址必须是网络中没有被占用的 virtual_ipaddress { 192.168.100.211/24 } # 引用健康检查 track_script { check_nginx }}- 主副节点配置差异
| router_id | state | priority | |
|---|---|---|---|
| 主 | NGINX_MASTER | MASTER | 100 |
| 副1 | NGINX_BACKUP | BACKUP | 90 |
| 副2 | NGINX_BACKUP | BACKUP | 80 |
- 创建
check_nginx.sh脚本
#!/bin/bash
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://127.0.0.1:20080/health)
if [ "$http_code" == "200" ]; then exit 0fi
# 探测失败,尝试重启 nginxsystemctl restart nginxsleep 2
# 重启后再探测一次,决定返回值给 keepalived 计数http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://127.0.0.1:20080/health)if [ "$http_code" == "200" ]; then exit 0 # 重启后恢复了,keepalived 不计失败else exit 1 # 重启也没救,keepalived 累计失败次数fi- 给脚本增加可执行权限
chmod +x check_nginx.sh5. 重启keepalived和nginx,应用配置
systemctl restart nginx keepalived三、修改原Control Plane,使用VIP作为apiserver入口
1. 修改集群配置文件
kubectl -n kube-system edit cm kubeadm-config修改如下
apiVersion: v1data: ClusterConfiguration: | apiVersion: kubeadm.k8s.io/v1beta4 caCertificateValidityPeriod: 87600h0m0s certificateValidityPeriod: 8760h0m0s certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controllerManager: {} dns: {} encryptionAlgorithm: RSA-2048 etcd: local: dataDir: /var/lib/etcd imageRepository: registry.k8s.io kind: ClusterConfiguration kubernetesVersion: v1.31.14 controlPlaneEndpoint: "192.168.100.211:16443" # 将VIP设置为控制平面入口 apiServer: certSANs: # 添加 VIP 到证书备用名称(关键!) - "192.168.100.8" - "192.168.100.11" - "192.168.100.12" - "192.168.100.211" - "kubernetes" - "kubernetes.default" - "kubernetes.default.svc" - "kubernetes.default.svc.cluster.local" - "localhost" - "127.0.0.1" networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 proxy: {} scheduler: {}kind: ConfigMapmetadata: creationTimestamp: "2026-03-15T08:07:27Z" name: kubeadm-config namespace: kube-system resourceVersion: "110579" uid: 765ac92b-04ba-4ec2-8959-b1d2060f3d3f2. 备份原证书
# 备份mkdir -p /root/pki-backupcp -r /etc/kubernetes/pki /root/pki-backup/
# 删除rm /etc/kubernetes/pki/apiserver.crt -frm /etc/kubernetes/pki/apiserver.key -f3. 重新生成证书
kubeadm certs renew apiserver4. 修改kubelet.conf和admin.conf文件中apiserver的IP地址
sed -i 's|192.168.100.8:6443|192.168.100.211:16443|g' /etc/kubernetes/kubelet.confsed -i 's|192.168.100.8:6443|192.168.100.211:16443|g' /etc/kubernetes/admin.conf5. 重启 kubelet 让新证书和配置生效
systemctl restart kubelet重启后,kubelet 会自动重建 apiserver pod
6. 验证是否能够通过VIP实现健康检查
curl -k https://192.168.100.211:16443/healthz如果返回OK,则说明网络链路已经没有问题
7. 上传证书
kubeadm init phase upload-certs --upload-certs上传成功后会生成certificate-key,例如:
[root@k8s-master-08 ~]# kubeadm init phase upload-certs --upload-certsI0321 18:57:15.525254 182649 version.go:261] remote version is much newer: v1.35.3; falling back to: stable-1.31[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace[upload-certs] Using certificate key:e503a8796c5b9bdf30e84db5eaae520fcbe59fca7e0c833d30e9319931d26e8a需要保存好这个certificate key,这是后面新节点以control plane加入集群的关键凭据
8. 生成join命令
kubeadm token create --print-join-command结果
[root@k8s-master-08 ~]# kubeadm token create --print-join-commandkubeadm join 192.168.100.8:6443 --token bs6bl6.ax3x7vc0n6mydfqx --discovery-token-ca-cert-hash sha256:0b967cdce19efe6a15d6215cd671857624d25230a86809d8ea922495bdba82ddTip
需要注意的是,在control plane上执行生成join命令时,生成的并不一定是以VIP为入口的命令。如果join的IP地址仍然是当前节点的IP,则需要后面在使用时,将IP地址手动修改为VIP。
四、新节点加入集群
1.加入集群
在新节点上执行
kubeadm join 192.168.100.211:16443 --control-plane \--token bs6bl6.ax3x7vc0n6mydfqx \--discovery-token-ca-cert-hash sha256:0b967cdce19efe6a15d6215cd671857624d25230a86809d8ea922495bdba82dd \--certificate-key e503a8796c5b9bdf30e84db5eaae520fcbe59fca7e0c833d30e9319931d26e8a其中:
- kubeadm join 192.168.100.211:16443 这个IP和端口是我手动修改的;
- —certificate-key 对应刚才 upload-certs 时生成的 certificate key;
- —control-plane 则表示该节点以 control plane 的身份加入集群;
2. 为新control plane配置kubeconfig
mkdir -p $HOME/.kubecp -i /etc/kubernetes/admin.conf $HOME/.kube/configchown $(id -u):$(id -g) $HOME/.kube/config五、修改全部节点的kubelet配置文件
修改/etc/kubernetes/kubelet.conf文件,将server一行的IP地址修改为VIP地址,然后重启kubelet
只有这样,当其中一个control plane宕机时,其他节点才不受影响,否则可能会出现备用control plane可以正常使用kubectl命令,但是节点全都是Not Ready状态的问题。
五、测试
1. 查看节点
有三个control plane,并且都是Ready
NAME STATUS ROLES AGE VERSIONk8s-master-08 Ready control-plane 7d1h v1.31.14k8s-master-11 Ready control-plane 22h v1.31.14k8s-master-12 Ready control-plane 22h v1.31.14k8s-node-09 Ready <none> 7d1h v1.31.14k8s-node-10 Ready <none> 7d1h v1.31.142. 停止当前VIP所在的节点
可以看见当前VIP绑定在192.168.100.8节点上

poweroff这个节点VIP漂移到了192.168.100.11主机上

在这个节点上操作集群,查看节点状态

六、关于Quorum 选举机制
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
将单点Control Plane的Kubernetes扩充为多个Control Plane实现集群高可用性
https://white-festa.net/posts/高可用kubernetes-control-plane/ 相关文章 智能推荐
1
深入 etcd:Raft 共识协议中的选举机制: 角色、Quorum 与 Pre-Vote
容器 从节点角色、Quorum 公式、选举流程、split vote 处理,到 Pre-Vote 预投票机制,系统梳理 etcd 在主节点宕机场景下的完整共识过程
2
Kubernetes节点压力驱逐、cgroups与Kernel OOM之间的关系
DevOps Kubernetes内存管理深度解析:当内存不足时,Pod如何被驱逐或杀死?本文从节点驱逐、cgroups限制、内核OOM三个层面,结合Logstash实例追踪cgroups路径,详解QoS与oom_score_adj如何决定Pod生死。
3
Kubernetes Label与分层模型
容器 如何更好的使用kubernetes label管理工作资源,使用基于服务身份、组织/管理维度与发布维度的分层模型
4
Kubernetes学习笔记三:Pod的调度策略
容器 Pod的调度策略与节点亲和性
5
Kubernetes学习笔记十三:Kubernetes Ingress
容器 在Kubernetes中通过Ingress实现Web代理、HTTPS站点和灰度发布
随机文章 随机推荐