返回首页

8.2 Kubernetes 高可用架构

本章目标

这一章不再停留在“集群能跑起来”,而是进入“集群故障后还能不能继续跑”的问题。学完后应该能理解:

  • 控制平面高可用到底在保障什么
  • etcd 为什么是整个控制平面的生命线
  • API Server、Controller Manager、Scheduler 分别怎样做 HA
  • 负载均衡、故障切换、备份恢复、异地灾备之间是什么关系

1. 控制平面高可用的基本要求

Kubernetes 的控制平面不是单个二进制,而是一组协作组件:kube-apiserverkube-controller-managerkube-scheduleretcd。如果你只有一个控制平面节点,那么任何单点故障——机器宕机、磁盘损坏、进程崩溃、系统升级失败——都有可能导致整个集群失去管理能力。Kubernetes 官方在 kubeadm 高可用拓扑文档中明确给出了两种主流 HA 方案:stacked control plane(控制平面与 etcd 同机)和 external etcd(独立 etcd 集群)::cite[426].

1.1 高可用不是“零故障”,而是“可持续服务”

理解高可用,先要区分两个层面:

层面 目标
控制平面可用性 集群仍可接受 API 请求、继续调度、持续调和
业务平面可用性 已运行 Pod 尽量不中断,对外服务持续可访问

要注意:控制平面短时不可用,不一定意味着业务立刻中断;但控制平面长期不可用,一定会影响扩缩容、故障恢复、滚动更新和节点治理。

1.2 控制平面 HA 的最低基线

一个较为稳妥的生产基线通常包括:

  • 至少 3 个控制平面节点
  • 至少 3 个 etcd 成员(如果使用 external etcd)
  • 一个稳定的控制平面访问入口(VIP 或负载均衡)
  • 控制组件多副本运行
  • 有明确的快照、恢复、演练流程

官方高可用安装文档强调,搭建 HA 集群前应该先选择拓扑,再按对应流程初始化集群,否则后续扩容和维护成本会明显上升::cite[427].

1.3 两种 HA 拓扑怎么选

拓扑 特点 适合场景
Stacked control plane etcd 与控制平面同机,部署简单,节点更少 中小规模、团队经验有限、先追求可落地
External etcd etcd 独立部署,故障域更清晰,扩展性更好 大规模生产、对控制面可靠性要求更高

如果你刚开始建设生产集群,通常可以先从 stacked control plane 入手;当集群规模、故障域隔离要求、升级窗口要求进一步提高时,再考虑 external etcd。


2. etcd 高可用与备份恢复策略

etcd 保存的是 Kubernetes 的全部核心状态:对象元数据、期望副本数、调度结果、配置、租约、状态信息等。换句话说,API Server 是入口,etcd 才是状态真源。官方运维文档指出,恢复 etcd 需要可用快照,恢复流程本质上就是从快照重建失败集群的数据状态::cite[233].

2.1 etcd HA 的关键原则

etcd 做高可用时,要记住几个原则:

  1. 奇数节点:通常是 3 或 5 个成员
  2. 跨故障域分布:最好跨机架 / 可用区
  3. 磁盘性能稳定:etcd 对延迟和 fsync 很敏感
  4. 避免频繁抖动:网络不稳比节点少更危险

如果使用 kubeadm 搭建 external etcd,官方示例就是 3 成员集群,节点之间通过 2379 / 2380 端口通信::cite[428].

2.2 etcd 备份为什么不能只“口头要求”

很多团队都知道 etcd 要备份,但真正出事故时,问题常常出在:

  • 没有定期备份
  • 备份文件没有异地保存
  • 恢复流程没演练过
  • 恢复时才发现版本、证书、数据目录参数都不清楚

因此,etcd 备份必须制度化,而不是“有空的时候做一下”。

2.3 etcd 快照备份示例

下面给出一个教学型备份脚本。实际生产中通常会把证书路径、备份目录、保留策略做成标准脚本或 CronJob。

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/var/backups/etcd"
TS="$(date +%F-%H%M%S)"
mkdir -p "${BACKUP_DIR}"

export ETCDCTL_API=3
etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save "${BACKUP_DIR}/snapshot-${TS}.db"

etcdctl snapshot status "${BACKUP_DIR}/snapshot-${TS}.db" -w table
find "${BACKUP_DIR}" -type f -name 'snapshot-*.db' -mtime +7 -delete

2.4 使用 CronJob 定时备份 etcd(学习示例)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-snapshot
  namespace: kube-system
spec:
  schedule: "0 */6 * * *"
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          restartPolicy: OnFailure
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
            - key: node-role.kubernetes.io/control-plane
              operator: Exists
              effect: NoSchedule
          containers:
            - name: snapshot
              image: quay.io/coreos/etcd:v3.5.16
              command:
                - /bin/sh
                - -c
                - |
                  export ETCDCTL_API=3
                  TS=$(date +%F-%H%M%S)
                  mkdir -p /backup
                  etcdctl \
                    --endpoints=https://127.0.0.1:2379 \
                    --cacert=/etc/kubernetes/pki/etcd/ca.crt \
                    --cert=/etc/kubernetes/pki/etcd/server.crt \
                    --key=/etc/kubernetes/pki/etcd/server.key \
                    snapshot save /backup/snapshot-${TS}.db
              volumeMounts:
                - name: pki
                  mountPath: /etc/kubernetes/pki
                  readOnly: true
                - name: backup
                  mountPath: /backup
          volumes:
            - name: pki
              hostPath:
                path: /etc/kubernetes/pki
            - name: backup
              hostPath:
                path: /var/backups/etcd

2.5 etcd 恢复思路

官方文档指出,恢复操作的前提是你已经有可用快照;恢复后,本质上是基于快照重建一个新的数据目录,再让 etcd 以恢复后的状态重新启动::cite[233].

一个学习型恢复步骤如下:

export ETCDCTL_API=3
etcdctl snapshot restore /var/backups/etcd/snapshot-2026-06-08-020000.db \
  --data-dir=/var/lib/etcd-restore \
  --name=cp1 \
  --initial-cluster=cp1=https://10.0.0.11:2380,cp2=https://10.0.0.12:2380,cp3=https://10.0.0.13:2380 \
  --initial-advertise-peer-urls=https://10.0.0.11:2380

恢复策略建议至少覆盖:

项目 建议
备份频率 按 RPO 设计,常见为 6 小时或 12 小时一次
存储位置 本地 + 远端对象存储 / 备份系统
保留策略 日备份 + 周备份 + 月备份
演练机制 每月或每季度做恢复演练
版本管理 恢复参数、证书、拓扑清单纳入变更记录

2.6 etcd 运维常见误区

  • 只做备份,不验证恢复
  • 把 etcd 和其他高 IO 组件堆在一起
  • 多数成员部署在同一故障域
  • 磁盘慢、延迟高,却只盯 CPU 和内存
  • 没有定期压缩、碎片整理和健康检查

3. API Server、Controller Manager、Scheduler 的高可用部署

3.1 API Server 的 HA 重点

API Server 是所有客户端进入控制平面的统一入口:kubectl、controller、scheduler、kubelet、Operator、CI/CD 工具都要访问它。因此 API Server 高可用的重点不是“主从切换”,而是:

  • 多实例无状态部署
  • 统一接入层
  • 证书和参数一致
  • 与 etcd 连接稳定

这也是为什么高可用集群通常会把多个 kube-apiserver 放在控制平面节点上,再通过一个负载均衡入口对外提供统一地址::cite[427].

3.2 kube-controller-manager 与 kube-scheduler 如何做 HA

这两个组件都可以多实例运行,但同一时刻真正工作的通常只有一个活跃实例。Kubernetes 使用 Lease 对象做组件级 leader election,这正是高可用场景下避免多个调度器或控制器同时写状态的基础机制::cite[431].

也就是说:

  • 你可以部署多个 controller-manager 和 scheduler
  • 但借助 leader election,只会有一个 leader 执行关键动作
  • leader 故障后,其他实例会接管

这是控制平面高可用里非常关键、但又很容易被忽略的一层。

3.3 一个学习型 kubeadm 高可用初始化流程

下面以 stacked control plane 为例,给出一个便于理解的流程:

  1. 准备负载均衡入口,例如 10.0.0.100:6443
  2. 在第一个控制平面节点执行 kubeadm init
  3. 上传证书并生成加入命令
  4. 其他控制平面节点通过 kubeadm join --control-plane 加入
  5. 校验 API Server、Scheduler、Controller Manager 是否全部多副本运行

示例配置如下:

apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.32.0
controlPlaneEndpoint: "10.0.0.100:6443"
networking:
  podSubnet: 10.244.0.0/16
apiServer:
  certSANs:
    - 10.0.0.100
    - k8s-api.internal.example.com
controllerManager: {}
scheduler: {}
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
nodeRegistration:
  criSocket: unix:///run/containerd/containerd.sock

初始化命令示例:

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

加入其他控制平面节点:

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

3.4 关键检查点

完成部署后,建议立刻检查:

kubectl get nodes
kubectl get pods -n kube-system -o wide
kubectl get endpoints kubernetes -o yaml
kubectl -n kube-system get lease

你要关注的是:

  • 多个控制平面节点是否 Ready
  • kube-apiserver 是否都在运行
  • kube-controller-managerkube-scheduler 是否正常参与 leader election
  • API 入口是否始终指向负载均衡地址

4. 负载均衡、故障切换与灾难恢复思路

4.1 为什么控制平面前面必须有统一入口

如果客户端直接写死某个 API Server 地址,那么一旦这台机器不可用,整个控制平面访问就会中断。因此,高可用集群通常都需要:

  • 一个四层负载均衡器
  • 或者一个 VIP(配合 keepalived / HAProxy)
  • 或云厂商托管的 Load Balancer

这个入口应该稳定暴露为:

  • 固定 IP
  • 或固定 DNS 名称
  • 统一证书 SAN

4.2 故障切换怎么理解

故障切换大致分成三层:

层级 典型故障 切换方式
接入层 单个 API Server 宕机 负载均衡摘除后转发到其他实例
控制器层 scheduler / controller-manager leader 故障 Lease 重新选主
存储层 etcd 节点故障 少数节点失效下继续形成法定多数

所以,真正的 HA 从来不是某一个组件单独做出来的,而是接入层、控制器层、存储层一起配合的结果。

4.3 灾难恢复(DR)要解决什么问题

高可用解决的是“单点故障”,灾难恢复解决的是“区域级或人为级事故”,例如:

  • 整个机房不可用
  • 控制平面配置被误删
  • etcd 数据严重损坏
  • 证书或节点系统批量异常

一个实用 DR 思路通常包括:

  1. etcd 定期快照
  2. 集群关键清单备份(证书、kubeadm 配置、LB 配置)
  3. GitOps 化保存业务清单
  4. 预先定义 RPO / RTO
  5. 有异地恢复演练

4.4 面向生产的故障演练清单

建议至少做以下演练:

  • 杀掉一个 kube-apiserver 实例,看是否无感切换
  • 停掉 controller-manager leader,看 Lease 是否转移
  • 模拟一个 etcd 成员下线,确认集群仍可写
  • 使用历史快照恢复测试集群
  • 演练新增控制平面节点、替换坏节点

4.5 一个最小 DR 检查表

drPolicy:
  rpo: "6h"
  rto: "2h"
  etcdSnapshot:
    enabled: true
    schedule: "0 */6 * * *"
    remoteBackup: true
  controlPlaneInventory:
    kubeadmConfigBackup: true
    certificatesBackup: true
    loadBalancerConfigBackup: true
  drills:
    quarterlyRestoreTest: true
    monthlyFailoverTest: true

5. 生产落地建议

5.1 中小团队可采用的稳妥方案

对于大多数团队来说,推荐从下面这条路线起步:

  • 3 控制平面节点
  • stacked etcd
  • 前置负载均衡或 VIP
  • 定时 etcd 快照
  • 每季度恢复演练

这是复杂度和可靠性比较均衡的一种方案。

5.2 大规模集群常见增强项

当集群进入更高要求的生产阶段时,可以进一步增强:

  • external etcd
  • 多可用区控制平面分布
  • 更严格的监控告警(etcd 延迟、leader 变更、API 错误率)
  • GitOps + 基础设施即代码
  • 更细粒度的 DR Runbook

5.3 你真正要带走的核心认知

  • API Server 是入口,但 etcd 才是状态核心
  • 多副本并不天然等于高可用,必须配合统一入口和 leader election
  • 备份不是结果,可恢复才是结果
  • HA 是架构设计,DR 是组织能力

6. 本章小结

这一章可以用一句话总结:

高可用不是多放几台机器,而是让控制平面在组件故障、节点故障、存储故障和局部网络故障下依然能够持续提供管理能力。

你需要真正掌握的重点是:

  • 会区分 stacked 与 external etcd 拓扑::cite[426]
  • 理解 etcd 快照与恢复是控制面生命线::cite[233]
  • 知道 scheduler / controller-manager 的 HA 依赖 Lease leader election::cite[431]
  • 明白统一 API 入口、故障切换和灾备演练缺一不可

📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

7.1 Metrics:Prometheus + Grafana

下一篇

2.4 ConfigMap 与 Secret:配置与敏感信息管理