news 2026/10/14 3:17:19

K8s高可用集群搭建实战:HAProxy+Keepalived完美融合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8s高可用集群搭建实战:HAProxy+Keepalived完美融合

k8s高可用集群

集群环境初始化

实验环境

主机名

IP

角色

reg.westos.org

192.168.36.151

harbor私有镜像仓库

k8s-master01

192.168.36.155

control-plane,haproxy,keepalived

k8s-master02

192.168.36.156

control-plane,haproxy,keepalived

k8s-master03

192.168.36.157

control-plane,haproxy,keepalived

k8s-worker01

192.168.36.158

worker

k8s-worker02

192.168.36.159

worker

使用现有的集群,k8s1,2,3做master

配置解析,禁用swap,配置yum源,升级内核

HAProxy 负载均衡

1. 安装 HAProxy

# yum install -y haproxy

2. 配置 HAProxy

# cat /etc/haproxy/haproxy.cfg global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemon stats socket /var/lib/haproxy/stats defaults mode http log global option dontlognull option http-server-close option redispatch retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s frontend monitor bind *:8000 mode http option httplog stats uri /status frontend k8s-apiserver bind *:8443 mode tcp option tcplog default_backend k8s-master backend k8s-master mode tcp option tcplog option tcp-check balance roundrobin server master1 192.168.36.152:6443 check fall 3 rise 2 server master2 192.168.36.153:6443 check fall 3 rise 2 server master3 192.168.36.154:6443 check fall 3 rise 2

配置说明

8000 ↓ HAProxy 状态监控页面 /status
8443 ↓ Kubernetes API Server ↓ master1 / master2 / master3

balance roundrobin表示采用轮询方式将请求分配给多个 Master。

客户端 ↓ HAProxy :8443 ↓ ┌───────┬───────┬───────┐ ↓ ↓ ↓ master1 master2 master3 :6443 :6443 :6443

check表示检查后端 Master 是否正常。


3. 启动 HAProxy

# systemctl enable --now haproxy.service

检查:

# ss -antlp | grep haproxy

应该看到:

LISTEN 0 2000 *:8000 LISTEN 0 2000 *:8443

其它 Master 节点的 HAProxy 配置相同。


Keepalived 高可用

HAProxy 解决的是:

多个 Master 之间如何进行负载均衡。

Keepalived 解决的是:

如果当前 HAProxy 所在节点发生故障,谁接管 VIP。


1. 安装 Keepalived

# yum install -y keepalived

2. 配置 Keepalived

# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived global_defs { router_id LVS_DEVEL script_user root enable_script_security } vrrp_script check_haproxy { script "/etc/keepalived/check_haproxy.sh" interval 5 weight -20 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.36.200 } track_script { check_haproxy } }

关键参数

virtual_ipaddress ↓ 192.168.36.200 ↓ VIP

客户端只需要访问:

192.168.36.200:8443

不需要关心具体是哪一台 Master 提供服务。

优先级:

k8s-master01 100 k8s-master02 90 k8s-master03 80

正常情况下:

MASTER → priority 100 BACKUP → priority 90 BACKUP → priority 80

HAProxy 检测脚本

# cat /etc/keepalived/check_haproxy.sh
#!/bin/bash if ! ps aux | grep -q [h]aproxy; then systemctl start haproxy sleep 2 if ! ps aux | grep -q [h]aproxy; then systemctl stop keepalived fi fi

添加执行权限:

# chmod +x /etc/keepalived/check_haproxy.sh

这个脚本的逻辑:

检查 HAProxy ↓ 正常 ↓ 继续运行 异常 ↓ 尝试启动 HAProxy ↓ 再次检查 ↓ 启动成功 → 继续运行 启动失败 → 停止 Keepalived ↓ VIP 发生切换

启动 Keepalived

# systemctl enable --now keepalived.service

检查:

# systemctl status keepalived

查看 VIP:

# ip addr

应该可以看到:

192.168.36.200

其他 Master 节点配置

其他 Master 节点的keepalived.conf大部分配置保持一致。

只需要修改:

k8s-master02

state BACKUP priority 90

k8s-master03

state BACKUP priority 80

kubeadm部署集群

之前已经部署过的,修改系统限制,修改内核参数,安装 IPVS 依赖,部署containerd,安装kubeadm、kubectl、kubelet

集群初始化

使用kubeadm初始化 Kubernetes 集群,通过HAProxy + Keepalived VIP提供统一的 API Server 入口,使用Calico作为 Pod 网络插件,使用Harbor作为私有镜像仓库。


配置集群初始化文件

# cat kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4 bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.36.152 #本机IP bindPort: 6443 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock imagePullPolicy: IfNotPresent imagePullSerial: true name: k8s-master01 #本机主机名 taints: null timeouts: controlPlaneComponentHealthCheck: 4m0s discovery: 5m0s etcdAPICall: 2m0s kubeletHealthCheck: 4m0s kubernetesAPICall: 1m0s tlsBootstrap: 5m0s upgradeManifests: 5m0s --- apiServer: certSANs: #添加VIP到证书 - 192.168.36.200 apiVersion: kubeadm.k8s.io/v1beta4 caCertificateValidityPeriod: 876000h0m0s certificateValidityPeriod: 87600h0m0s certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controlPlaneEndpoint: 192.168.36.200:8443 #负载均衡地址端口 controllerManager: {} dns: {} encryptionAlgorithm: RSA-2048 etcd: local: dataDir: /var/lib/etcd imageRepository: reg.westos.org/k8s #harbor私有仓库 kind: ClusterConfiguration kubernetesVersion: 1.34.1 #k8s部署版本 networking: dnsDomain: cluster.local serviceSubnet: 10.96.0.0/12 #service网段 podSubnet: 10.244.0.0/16 #Pod网段 proxy: {} scheduler: {} --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs #kube-proxy使用IPVS模式 ipvs: scheduler: "rr" #调度算法 strictARP: true #高可用场景必须开启,避免 ARP 冲突

关键配置

192.168.36.200:8443 ↓ HAProxy + Keepalived ↓ 多个 Master:6443

其中:

  • advertiseAddress:当前 Master 节点 IP。
  • controlPlaneEndpoint:集群统一 API Server 地址,也就是 HAProxy + Keepalived 的 VIP。
  • certSANs:把 VIP 加入 API Server 证书,避免通过 VIP 访问时证书校验失败。
  • imageRepository:使用 Harbor 私有仓库。
  • serviceSubnet:Service 网段。
  • podSubnet:Pod 网段。
  • mode: ipvs:kube-proxy 使用 IPVS。
  • strictARP: true:IPVS + 高可用环境下开启。

初始化集群

要先清理之前集群残留的配置

# 1. 先把重要数据备份(etcd 快照、YAML 清单等) mkdir -p /backup/etcd ETCDCTL_API=3 etcdctl \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/apiserver-etcd-client.crt \ --key=/etc/kubernetes/pki/apiserver-etcd-client.key \ --endpoints https://127.0.0.1:2379 \ snapshot save /backup/etcd/etcd-final-$(date +%F).bak cp -r /etc/kubernetes /backup/kubernetes-$(date +%F) # 业务 YAML 也备份一下 # 2. reset 掉旧集群 kubeadm reset -f rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet/* \ /etc/cni/net.d $HOME/.kube # 3. 清理网络插件残留(Calico / kube-proxy 的 iptables / ipvs) iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X ipvsadm -C 2>/dev/null # 4. 清理容器 crictl rm -f $(crictl ps -aq) 2>/dev/null crictl rmi --prune 2>/dev/null # 5. 重启 containerd 和 kubelet systemctl restart containerd kubelet

在k8s-master01执行:

kubeadm init --config=kubeadm-config.yaml --upload-certs

初始化成功后会生成:

  • 管理员 kubeconfig
  • Worker 加入命令
  • Master 加入命令
  • certificate-key

设置 KUBECONFIG

export KUBECONFIG=/etc/kubernetes/admin.conf

写入环境变量文件,确保重启后依然生效:

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile

设置 kubectl 命令补齐

安装:

yum install -y bash-completion

开启补齐:

echo "source <(kubectl completion bash)" >> ~/.bashrc source ~/.bashrc

查看集群状态

# kubectl get node

刚初始化完成时:

NAME STATUS ROLES AGE VERSION k8s-master01 NotReady control-plane 9m42s v1.34.1

此时NotReady通常是因为还没有安装 CNI 网络插件。


初始化失败时重置节点

如果初始化出现严重错误,可以重置:

kubeadm reset -f --ignore-preflight-errors=all

然后根据实际情况重新初始化。


安装 Calico 网络插件

1. 下载 Calico

wget https://raw.githubusercontent.com/projectcalico/calico/v3.31.0/manifests/calico.yaml

2. 修改镜像仓库

将 Calico 镜像从官方仓库修改为 Harbor:

# sed -i 's#quay.io/#reg.westos.org/#g' calico.yaml

3. 部署 Calico

# kubectl apply -f calico.yaml

4. 查看节点状态

# kubectl get node

正常:

NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 17m v1.34.1

扩容 Master 节点

在其他 Master 节点执行初始化时生成的kubeadm join命令。

kubeadm join 192.168.36.200:8443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:bd1808e77dd5669cfdd5c5b7859cf0ea9c8444b1c1bce990231eaefe80457b6e \ --control-plane --certificate-key 815568fa321d937c4a342dace14fbb657d77ee658431035b5fd218518691cf63

注意:实际实验中使用kubeadm init输出的 join 命令,不要直接照抄示例中的 token 和 certificate-key。


查看 Master 节点

# kubectl get node

例如:

NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 17m v1.34.1 k8s-master02 Ready control-plane 87s v1.34.1 k8s-master03 Ready control-plane 76s v1.34.1

扩容 Worker 节点

在 Worker 节点执行:

kubeadm join 192.168.36.200:8443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:bd1808e77dd5669cfdd5c5b7859cf0ea9c8444b1c1bce990231eaefe80457b6e

Worker 加入后查看:

# kubectl get node

例如:

NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 87m v1.34.1 k8s-master02 Ready control-plane 71m v1.34.1 k8s-master03 Ready control-plane 71m v1.34.1 k8s-worker01 Ready <none> 20s v1.34.1

给 Worker 节点添加标签

kubectl label nodes k8s-worker01 node-role.kubernetes.io/worker=

再次查看:

kubectl get node

最终形成:

k8s-master01 control-plane k8s-master02 control-plane k8s-master03 control-plane k8s-worker01 worker

kube-vip 云原生高可用

官网:Static Pods | kube-vip

原理

kube-vip 以静态 Pod形式部署在所有 master 节点,通过ARP + Leader 选举为一个 VIP 提供服务。任意 master 挂了,VIP 自动漂移到其他节点 → 集群 apiserver 高可用。

kubeadm init 前 ↓ kube-vip 先跑起来(提供 VIP 192.168.36.200) ↓ kubeadm init 用 VIP 作为 controlPlaneEndpoint ↓ apiserver 高可用

一、上传镜像到 Harbor

# 从 ghcr.io 拉取(或用镜像代理) docker pull ghcr.io/kube-vip/kube-vip:v1.2.4 # 打 tag 指向私有仓库 docker tag ghcr.io/kube-vip/kube-vip:v1.2.4 \ reg.westos.org/k8s/kube-vip:v1.2.4 # 推送 docker login reg.westos.org -u admin -p westos docker push reg.westos.org/k8s/kube-vip:v1.2.4

二、从镜像提取二进制(可选)

只是为了本机有kube-vip命令,方便生成 YAML。直接用docker run也能生成,可跳过这步。

docker create --name demo ghcr.io/kube-vip/kube-vip:v1.2.4 docker cp demo:/kube-vip /usr/local/bin/kube-vip chmod +x /usr/local/bin/kube-vip docker rm -f demo # 验证 kube-vip version # Version: v1.2.4

三、在所有 master 节点放 kube-vip 静态 Pod

1. 生成 YAML(推荐用docker run)

docker run --rm --net=host \ reg.westos.org/k8s/kube-vip:v1.2.4 manifest pod \ --interface eth0 \ --address 192.168.150.200 \ --controlplane \ --services \ --arp \ --leaderElection \ --image reg.westos.org/k8s/kube-vip:v1.2.4 \ | sudo tee /etc/kubernetes/manifests/kube-vip.yaml

2. 或直接手写 YAML

apiVersion: v1 kind: Pod metadata: name: kube-vip namespace: kube-system spec: containers: - args: - manager env: - name: vip_arp value: "true" - name: port value: "6443" - name: vip_nodename valueFrom: fieldRef: fieldPath: spec.nodeName - name: vip_interface value: eth0 - name: vip_subnet value: "32" - name: dns_mode value: first - name: cp_enable value: "true" - name: cp_namespace value: kube-system - name: svc_enable value: "true" - name: svc_leasename value: plndr-svcs-lock - name: vip_leaderelection value: "true" - name: vip_leasename value: plndr-cp-lock - name: vip_leaseduration value: "5" - name: vip_renewdeadline value: "3" - name: vip_retryperiod value: "1" - name: address value: 192.168.150.200 - name: prometheus_server value: :2112 image: reg.westos.org/k8s/kube-vip:v1.2.4 imagePullPolicy: IfNotPresent name: kube-vip resources: {} securityContext: capabilities: add: - NET_ADMIN - NET_RAW drop: - ALL volumeMounts: - mountPath: /etc/kubernetes/admin.conf name: kubeconfig hostAliases: - hostnames: - kubernetes ip: 127.0.0.1 hostNetwork: true volumes: - hostPath: path: /etc/kubernetes/super-admin.conf name: kubeconfig status: {}

3. 检查三处必改

字段说明
image改成你的私有仓库地址
vip_interface改成实际网卡名(ip a查)
address改成你规划的 VIP

4. 复制到所有 master 节点

scp /etc/kubernetes/manifests/kube-vip.yaml root@k8s2:/etc/kubernetes/manifests/ scp /etc/kubernetes/manifests/kube-vip.yaml root@k8s3:/etc/kubernetes/manifests/

四、初始化集群

kubeadm-config.yml 里必须把controlPlaneEndpoint指向 VIP:

controlPlaneEndpoint: 192.168.150.200:6443 apiServer: certSANs: - 192.168.150.200
kubeadm init --config=kubeadm-config.yml --upload-certs

别的节点正常加入集群


五、验证

1. Pod 是否 Running

crictl ps | grep kube-vip # 输出示例: # xxx xxx 19 minutes ago Running kube-vip ... kube-vip-k8s1 kube-system

2. VIP 是否绑到网卡

ip a show eth0 | grep 192.168.150.200 # 输出示例: # inet 192.168.150.200/32 scope global deprecated eth0

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:17:17

第6章: 同步与 Fence 机制

前几章介绍了 context、resource 与 capset 三个静态抽象。GPU 的执行是异步的:命令提交后不会立即完成,Guest 与 Host、CPU 与 GPU 之间需要一套同步原语来协调先后顺序。本章说明 virglrenderer 的 fence 体系:两代 fence 模型、时间线与 ring_idx、VMM 获知完成的两种途径…

作者头像 李华
网站建设 2026/10/14 3:16:27

PDF轻编辑实战:精准擦除水印与添加文字图片

1. 轻编辑需求为什么越来越常见先聊一个很多人都会遇到的场景。某份合同扫描件里有一行备注写错了&#xff0c;需要清掉重新批注&#xff1b;某本电子书上有水印和阅读器自带的页码&#xff0c;想擦掉再打印&#xff1b;某份课件截图上有多余的公式或标注&#xff0c;想删干净后…

作者头像 李华
网站建设 2026/10/14 3:15:03

MySQL零基础入门:从安装建库到增删改查全流程教程

1. MySQL到底是个啥&#xff0c;为什么零基础也要学它这一篇我们聊聊 MySQL。不管你之前有没有接触过数据库&#xff0c;只要你会用电脑打字&#xff0c;跟着这份超详细的教程&#xff0c;就能把 MySQL 装起来、跑起来&#xff0c;然后亲手写下第一条 SQL。我见过不少零基础学编…

作者头像 李华
网站建设 2026/10/14 3:14:49

ORA-12505故障精解:Oracle监听器服务注册与连接描述符匹配原理

1. 问题本质与典型场景还原“ORA-12505, TNS:listener does not currently know of SID given in connect descriptor”——这行报错&#xff0c;我在过去十年带过的二十多个Oracle数据库项目里&#xff0c;几乎每三个月就要亲手处理一次。它不是那种高深莫测的内核级错误&…

作者头像 李华