Skip to content

控制平面高可用

单控制平面宕机后,kubectl 连不上、新 Pod 无法调度、变更无法提交——虽然已有 Pod 可能还在跑,但集群已经不可管理了。生产集群的高可用控制平面需要四个层面同时成立:API Server 入口、多控制平面节点、etcd quorum 和证书配置。任何一环是单点都不算真正的高可用。

四层结构

层次解决的问题
API Server 入口给 kubectl、kubelet、控制器提供稳定地址,单个节点 IP 挂掉不影响访问
多控制平面节点多个 apiserver、scheduler、controller-manager 实例
etcd 高可用多成员 Raft 集群保证状态不丢
证书和配置controlPlaneEndpoint、SAN、admin kubeconfig 全部指向入口地址

API Server 无状态,多副本各接各的请求。scheduler 和 controller-manager 通过 leader election 保证同一时间只有一个实例在执行控制动作——备实例随时待命接管。etcd 用 Raft quorum——三成员允许坏一个,五成员允许坏两个。

stacked etcd 和 external etcd

kubeadm 高可用分两类:

方式结构优点代价
stacked etcdetcd 和控制平面跑在同一批节点机器少,部署简单控制平面节点压力集中
external etcdetcd 单独一组节点隔离好,故障域清楚机器更多,证书和运维更复杂

中小规模自建集群常用 stacked etcd。规模大、控制平面压力高、对 etcd 有单独运维要求时用 external。普通机房环境用三控制平面 stacked etcd,把 etcd 磁盘、备份和告警做好就够。

API Server 高可用入口

controlPlaneEndpoint 是 kubeadm 高可用的核心配置——它会写进所有 kubeconfig 和节点连接地址。入口方案:

方案说明
HAProxy + Keepalived裸机常见,VIP 漂移,HAProxy 四层转发到多个 API Server
kube-vip以静态 Pod 提供 VIP,K8s 场景集成度更高
云负载均衡云上集群直接用 SLB/ELB/NLB
硬件负载均衡已有设备时使用

HAProxy 配置——四层 TCP 转发,不需要 HTTP 层检查:

haproxy
frontend kube-apiserver
    bind *:6443
    mode tcp
    option tcplog
    default_backend kube-apiserver-backend

backend kube-apiserver-backend
    mode tcp
    option tcp-check
    balance roundrobin
    server cp1 192.168.10.11:6443 check
    server cp2 192.168.10.12:6443 check
    server cp3 192.168.10.13:6443 check

Keepalived 提供 VIP:

conf
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass k8s-ha
    }
    virtual_ipaddress {
        192.168.10.100/24
    }
}

HAProxy 和 Keepalived 放在控制平面节点上时,要确认 6443 端口没有冲突——HAProxy 监听 VIP 的 6443,转发到各控制平面节点自己的 6443。

kubeadm 高可用初始化

第一台控制平面初始化时最关键的配置是 controlPlaneEndpoint

yaml
# kubeadm-ha.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.36.0
controlPlaneEndpoint: "192.168.10.100:6443"
imageRepository: registry.aliyuncs.com/google_containers
networking:
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
bash
kubeadm init --config kubeadm-ha.yaml --upload-certs

--upload-certs 把证书加密上传到集群 Secret,后续控制平面节点加入时不需要手动拷贝证书。输出里的 --certificate-key 要保存好。

第二、三台控制平面加入:

bash
kubeadm join 192.168.10.100:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash> \
  --control-plane \
  --certificate-key <certificate-key>

工作节点加入时不带 --control-plane

etcd quorum

quorum 是“超过半数成员同意”的意思。etcd 用 Raft 保存控制平面状态,写入一条数据时,不是 leader 自己写完就算成功,而是要复制给多数成员。这样 leader 挂掉后,新 leader 仍然能从多数成员里拿到已经确认过的数据。

三成员 etcd 最常见。超过半数存活才能写入:

etcd 成员数可容忍故障数说明
10实验环境
31常见生产最小规模
52更高容错,但写入延迟和维护成本更高

3 个成员需要 2 个成员存活,5 个成员需要 3 个成员存活。成员数量通常用奇数,因为 2 个成员仍然需要 2 个都活着才能满足多数派,容错能力没有比单成员强多少;4 个成员需要 3 个存活,比 3 个成员同样只能坏 1 个,但多了一份复制和维护成本。

查看成员:

bash
kubectl -n kube-system exec etcd-k8s-master01 -- \
  etcdctl member list \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

成员越多,写入需要复制到更多节点,网络和磁盘延迟对控制平面的影响更明显。多数普通集群三成员够用。

验证高可用

入口可访问:

bash
curl -k https://192.168.10.100:6443/readyz
kubectl get nodes -o wide

控制平面组件:

bash
kubectl -n kube-system get pods -o wide | grep -E 'apiserver|scheduler|controller|etcd'
kubectl get endpoints kubernetes -o wide

模拟单个控制平面节点故障:

bash
systemctl stop kubelet

观察——kubectl 通过 VIP 仍然能访问其他 API Server:

bash
kubectl get nodes
kubectl get pods -A
curl -k https://192.168.10.100:6443/readyz

只停一个控制平面节点时,kubectl 仍可用,但该节点上的 etcd 成员如果跟着停了、quorum 还在,集群写入不受影响。业务 Pod 是否受影响取决于它们是否运行在该节点上。

常见问题

现象常见原因处理方向
join 控制平面失败certificate-key 过期或错误重新 kubeadm init phase upload-certs --upload-certs
kubelet 仍连单节点 IP初始化时没写 controlPlaneEndpoint重建或修改 kubeconfig
VIP 能 ping 但 6443 不通HAProxy 未监听或后端检查失败HAProxy 日志和后端端口
etcd member 异常节点故障、证书、磁盘慢etcd 日志、member list、磁盘延迟
kubectl 偶发超时负载均衡后端有坏节点健康检查和后端列表