跳转到内容
123xiao | 无名键客

《Kubernetes 集群架构实战:从控制平面高可用到工作负载弹性扩缩的设计与落地》

字数: 0 阅读时长: 1 分钟

Kubernetes 集群架构实战:从控制平面高可用到工作负载弹性扩缩的设计与落地

Kubernetes 用久了,大家很容易把关注点放在“怎么把应用跑起来”,但真正进到生产环境,问题会马上变成另一个层面:

  • 控制平面挂一个节点,集群还能不能继续管?
  • API Server 抖一下,发布是不是全卡住?
  • 业务流量突然翻倍,Pod 扩不扩得起来?
  • 扩起来以后,节点资源够不够?
  • 控制平面高可用和工作负载弹性,到底应该怎么配合?

这篇文章不打算只讲概念,而是从一个可落地的集群架构视角,把“控制平面高可用”与“工作负载弹性扩缩”串起来。你可以把它理解成:如何设计一个既不容易挂、又能扛住波峰的 Kubernetes 集群


背景与问题

很多团队在搭 Kubernetes 初期,通常会经历下面几个阶段:

  1. 单控制平面起步

    • 快,省机器,适合测试环境
    • 但一旦 master 宕机,虽然已有 Pod 可能继续运行,整个集群管理能力会明显受影响
  2. 增加工作节点

    • 解决“能跑更多服务”的问题
    • 但没有解决“集群核心组件可靠性”的问题
  3. 开始做 HPA

    • 业务能按 CPU 或内存扩容
    • 但如果节点本身资源不够,HPA 只会让 Pod Pending
  4. 补上 Cluster Autoscaler

    • 节点能自动扩
    • 但如果控制平面本身不稳,扩容决策和调度过程也会变得脆弱

所以生产集群的真实问题,不是“高可用”和“弹性扩缩”二选一,而是:

控制平面保证“能管”,工作负载弹性保证“能扛”,两者一起构成完整的生产架构。


先给结论:一个实用的生产架构长什么样

如果你让我给中型业务团队一个比较稳妥的建议,我通常会推荐下面这种形态:

  • 3 个控制平面节点
    • 部署 kube-apiserverkube-controller-managerkube-scheduler
    • etcd 使用 3 节点或外部托管
  • API Server 前置负载均衡
    • 如 HAProxy、Keepalived,或云厂商 SLB/NLB
  • 多工作节点池
    • 按业务类型分池:通用、计算密集、内存密集、系统组件专用
  • 工作负载弹性
    • Pod 级别:HPA
    • 节点级别:Cluster Autoscaler
  • 基础可观测性
    • Metrics Server、Prometheus、Alertmanager、日志系统
  • 调度与隔离
    • requests/limits、PDB、亲和性、污点与容忍、优先级

这个结构的核心思想是:

  • 控制平面高可用负责“控制链路不中断”
  • 弹性扩缩负责“业务容量自动适配”
  • 资源治理负责“扩缩过程中不把自己搞挂”

核心原理

这一节我们把几个关键部件串起来。

1. 控制平面高可用的本质

Kubernetes 控制平面核心由这些组件构成:

  • kube-apiserver:所有请求入口
  • kube-controller-manager:执行控制器逻辑
  • kube-scheduler:给 Pod 选节点
  • etcd:保存集群状态

其中真正最敏感的是两类:

  • API Server
  • etcd

因为:

  • 没有 API Server,集群对象不能正常读写
  • 没有 etcd,多数状态无法持久化和一致维护

2. etcd 为什么通常是奇数节点

etcd 基于 Raft,一致性依赖多数派。
3 节点可容忍 1 个故障,5 节点可容忍 2 个故障。

很多人一开始会觉得“4 台不是比 3 台更稳吗”,其实不是这么算的:

  • 3 节点,多数派是 2
  • 4 节点,多数派是 3

也就是说,4 节点并不会比 3 节点多容忍一个故障,却会增加通信复杂度。所以 etcd 常见建议是 3 节点或 5 节点

3. 控制平面高可用的数据流

flowchart LR
    User[运维/CI/CD/控制器请求] --> LB[API LB / VIP]
    LB --> APIS1[kube-apiserver-1]
    LB --> APIS2[kube-apiserver-2]
    LB --> APIS3[kube-apiserver-3]

    APIS1 --> ETCD[(etcd 集群)]
    APIS2 --> ETCD
    APIS3 --> ETCD

    APIS1 --> CM1[kube-controller-manager]
    APIS2 --> CM2[kube-controller-manager]
    APIS3 --> CM3[kube-controller-manager]

    APIS1 --> SCH1[kube-scheduler]
    APIS2 --> SCH2[kube-scheduler]
    APIS3 --> SCH3[kube-scheduler]

    Worker1[Worker Node 1] --> LB
    Worker2[Worker Node 2] --> LB
    WorkerN[Worker Node N] --> LB

注意一个容易误解的点:

  • controller-managerscheduler 可以多副本部署
  • 但它们通常通过**leader election(主选举)**保证同一时刻只有一个实例在主导工作
  • 所以高可用不是所有实例都一起干活,而是主备切换快、服务不中断

4. 弹性扩缩的真实链路

在 Kubernetes 里,弹性扩缩并不只有 HPA。

完整链路通常是:

  1. 业务流量增长
  2. Pod CPU/内存/自定义指标升高
  3. HPA 调整 Deployment 副本数
  4. 新 Pod 创建
  5. 调度器尝试调度
  6. 如果节点资源不足,Pod Pending
  7. Cluster Autoscaler 发现有 Pod 因资源不足无法调度
  8. 扩容节点池
  9. 新节点加入集群
  10. Pending Pod 被重新调度

这是一条典型的“Pod 扩缩 + 节点扩缩联动”链路。

sequenceDiagram
    participant U as 用户流量
    participant H as HPA
    participant D as Deployment
    participant S as Scheduler
    participant C as Cluster Autoscaler
    participant N as Node Group

    U->>H: 指标升高
    H->>D: 增加 replicas
    D->>S: 创建新 Pod
    S-->>D: 资源不足,Pod Pending
    S->>C: 暴露不可调度 Pod
    C->>N: 扩容节点
    N-->>S: 新节点 Ready
    S->>D: 重新调度 Pod

5. 为什么只做 HPA 不够

我在一些团队里见过很典型的情况:
HPA 配得很漂亮,但没有节点自动扩容。结果高峰期副本从 4 个扩到 12 个,最后 6 个 Pod Pending,业务还是抖。

原因很直接:

  • HPA 解决的是**“想多跑几个 Pod”**
  • Cluster Autoscaler 解决的是**“有没有地方让这些 Pod 跑”**

两者缺一不可。


方案对比与取舍分析

方案一:单控制平面 + 多工作节点

优点:

  • 架构简单
  • 成本最低
  • 搭建和维护压力小

缺点:

  • 控制平面是单点
  • 适合测试、开发、小规模内部业务
  • 不适合关键生产系统

方案二:多控制平面 + 堆叠式 etcd

也就是控制平面节点同时运行 etcd。

优点:

  • 架构相对简单
  • kubeadm 支持较成熟
  • 对中小规模生产环境很常见

缺点:

  • 控制平面和 etcd 资源耦合
  • 排障时需要同时考虑控制组件和存储一致性

方案三:多控制平面 + 外部 etcd

优点:

  • etcd 与控制平面解耦
  • 更利于独立维护和容量规划
  • 更适合较大规模集群

缺点:

  • 部署复杂度更高
  • 运维门槛明显提升

我的建议

如果是中级团队、目标是稳定落地,而不是炫技:

  • 中小型生产集群:优先考虑 3 控制平面 + 堆叠式 etcd
  • 多集群/较大规模/合规要求高:考虑外部 etcd 或托管控制平面
  • 云上优先:如果预算允许,优先使用托管 Kubernetes 控制平面,把精力放在节点池、调度和弹性治理

容量估算:不要等到高峰才发现设计偏小

架构设计里最容易被忽略的是容量预估。一个简单实用的估算方式如下。

1. 工作负载容量估算

假设你的服务单 Pod requests:

  • CPU: 500m
  • Memory: 512Mi

目标稳态副本数 20,高峰预估翻 2 倍,即 40 副本。

那么总 requests 大致为:

  • CPU: 40 * 500m = 20 vCPU
  • Memory: 40 * 512Mi ≈ 20Gi

再考虑:

  • 系统组件开销
  • 节点碎片化
  • 滚动发布额外副本
  • 单节点故障冗余

实际通常至少要预留 20%~30% Buffer

2. 控制平面容量估算

控制平面更关注:

  • API QPS
  • 对象数量(Pod、ConfigMap、Secret、Endpoint)
  • 控制器压力
  • etcd IOPS 与延迟

如果你有以下特征,需要特别关注控制平面:

  • 命名空间多
  • 短生命周期 Job 多
  • 大量 CRD/Operator
  • 发布频繁
  • HPA / CA 动态变化频繁

控制平面高可用不是只看“挂不挂”,还要看忙的时候抖不抖


实战代码(可运行)

下面我给一套能直接落地验证的最小实践:
使用 Deployment + Service + HPA,并补上 requests/limits,便于演示弹性扩缩。

前提:集群已安装 Metrics Server。
如果你在本地实验环境(如 kind/minikube)测试,先确认 kubectl top pod 有数据。

1. 示例应用 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-demo
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
        - name: web-demo
          image: nginx:1.25
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 300m
              memory: 256Mi

2. 暴露 Service

apiVersion: v1
kind: Service
metadata:
  name: web-demo
  namespace: default
spec:
  selector:
    app: web-demo
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP

3. 配置 HPA

这里基于 CPU 利用率扩缩。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-demo-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-demo
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

4. 一次性应用

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f hpa.yaml

5. 查看效果

kubectl get deploy,svc,hpa
kubectl top pod
kubectl describe hpa web-demo-hpa

6. 制造压力验证 HPA

我们启动一个临时压测 Pod,持续请求业务服务。

kubectl run load-generator \
  --image=busybox:1.35 \
  --restart=Never \
  -- /bin/sh -c "while true; do wget -q -O- http://web-demo; done"

然后观察:

kubectl get hpa web-demo-hpa -w
kubectl get pod -w

如果指标采集正常,几分钟内会看到副本数上升。


补一个更贴近生产的 Deployment 写法

只做 HPA 还不够,生产里至少建议加上:

  • readinessProbe
  • livenessProbe
  • rollingUpdate
  • PodDisruptionBudget
  • topologySpreadConstraints 或反亲和性

下面给一个增强版 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-demo
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: api-demo
  template:
    metadata:
      labels:
        app: api-demo
    spec:
      containers:
        - name: api-demo
          image: nginx:1.25
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 3
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: api-demo

对应的 PDB:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-demo-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api-demo

这两个配置很关键,因为:

  • 高可用不是只有控制平面要高可用
  • 业务工作负载自己也要具备“节点维护时不全挂”的能力

控制平面高可用的部署要点

如果你使用 kubeadm 部署高可用控制平面,重点关注这几件事。

1. API Server 入口必须稳定

所有节点上的 kubeletkubectl、控制器访问 API Server 时,不应该直接写死某一个 master IP。
应该统一走:

  • VIP
  • 负载均衡域名
  • 云负载均衡地址

否则你虽然部署了三个控制平面,但客户端都只打到其中一个,还是有单点风险。

2. 证书 SAN 要包含统一入口

很多高可用接入失败,不是 Kubernetes 本身的问题,而是证书里没把 LB 地址或域名加入 SAN。表现通常像这样:

Unable to connect to the server: x509: certificate is valid for ...

3. etcd 延迟比你想象中更重要

etcd 不需要很高 CPU,但对:

  • 磁盘延迟
  • fsync 性能
  • 网络稳定性

非常敏感。
我踩过的一个坑是把 etcd 放在普通云盘上,平时看着没问题,业务发布高峰时 API Server 延迟明显飙升,最后追到根因是存储抖动。


常见坑与排查

下面这部分是生产里非常常见的故障场景,我尽量用“现象 → 原因 → 怎么查”的方式讲。

坑一:HPA 不生效

现象:

  • kubectl get hpa 一直不扩
  • TARGETS 显示 <unknown>

常见原因:

  • Metrics Server 未安装
  • Metrics Server 采集异常
  • 容器未配置 requests,导致 HPA 无法正确计算利用率

排查命令:

kubectl top pod
kubectl get apiservices
kubectl describe hpa web-demo-hpa
kubectl logs -n kube-system deploy/metrics-server

经验建议:

  • 基于 CPU/内存做 HPA 时,务必设置 resources.requests
  • 没有 requests,很多“利用率”判断都不可靠

坑二:HPA 扩容了,但 Pod 一直 Pending

现象:

  • HPA 副本数已经增加
  • 新 Pod 状态是 Pending

常见原因:

  • 节点资源不足
  • requests 设置过大
  • 节点有污点,Pod 没有 toleration
  • 亲和/反亲和规则太严格

排查命令:

kubectl get pod
kubectl describe pod <pod-name>
kubectl get nodes
kubectl describe node <node-name>

重点看事件里有没有这些字样:

  • Insufficient cpu
  • Insufficient memory
  • node(s) had taint
  • node(s) didn't match Pod's node affinity

如果你已经接了 Cluster Autoscaler,还要继续看:

kubectl logs -n kube-system deployment/cluster-autoscaler

坑三:控制平面看起来是高可用,实际上 API 还是单点

现象:

  • 有 3 台 master
  • 但停掉其中一台后,大量组件访问异常

常见原因:

  • kubeconfig 里仍写某台 master 的固定地址
  • kubelet 启动参数直连某个控制平面节点
  • 前置 LB 没有健康检查或健康检查不准确

排查思路:

  1. 查所有 kubeconfig 中的 server
  2. 查 kubelet 实际连接的 API 地址
  3. 模拟下线某个控制平面节点
  4. 观察:
    • kubectl get nodes
    • 新 Pod 创建
    • leader 切换
    • ServiceAccount token 校验
    • Webhook 调用

坑四:etcd 正常,但 API Server 很慢

现象:

  • 集群不是完全不可用
  • kubectl get pod -A 很慢
  • 发布时卡顿明显

可能原因:

  • etcd 存储延迟高
  • 集群对象量过大
  • watch 压力大
  • API Server QPS/并发限制过低
  • CRD 控制器过多

建议排查:

kubectl get --raw='/readyz?verbose'
kubectl get --raw='/livez?verbose'
kubectl top pod -n kube-system

如果你有 Prometheus,建议重点看:

  • apiserver request duration
  • etcd request duration
  • etcd disk fsync duration
  • apiserver inflight requests

坑五:滚动升级时可用副本被打没了

现象:

  • 升级 Deployment 时业务闪断
  • 节点维护时服务副本骤减

原因:

  • 没有 PDB
  • maxUnavailable 设置过大
  • Readiness Probe 不准确
  • 副本本来就太少,还分布在同一节点

建议:

  • 核心服务副本数至少 2 起步
  • 配 PDB
  • 配反亲和或拓扑分散
  • Readiness 不要写成“进程启动就算健康”

安全/性能最佳实践

高可用和弹性不只是“能不能用”,还包括“用得是否稳、是否安全”。

1. 控制平面最佳实践

安全方面

  • API Server 统一走 TLS
  • 证书轮转要有计划
  • 关闭不必要的匿名访问
  • RBAC 最小权限
  • 审计日志开启并留存

性能方面

  • etcd 使用低延迟磁盘
  • 控制平面节点与 etcd 网络尽量稳定、低抖动
  • 避免在控制平面节点混跑重业务
  • 大集群中合理调整 API QPS/Burst

2. 工作负载弹性最佳实践

资源治理

  • 每个业务容器都配置 requests/limits
  • 不要把 requests 配得离谱,否则调度浪费严重
  • 关键业务优先设置 PriorityClass

扩缩策略

  • HPA 不要只看 CPU,必要时接入 QPS、队列长度、自定义指标
  • 为 HPA 设置合理的 minReplicas
  • 避免扩缩阈值过于敏感,减少抖动

可用性保障

  • 多副本
  • PDB
  • 反亲和 / 拓扑分散
  • 优雅终止:terminationGracePeriodSeconds
  • 配合 Ingress / Service 的连接摘除机制

3. 多节点池是非常值回票价的设计

把所有节点做成一个池,前期简单,后期很容易混乱。更推荐:

  • system-pool:系统组件
  • general-pool:常规业务
  • cpu-pool:计算密集
  • mem-pool:内存密集
  • spot-pool:可中断低成本任务

这样做的价值在于:

  • 扩容更有针对性
  • 成本更可控
  • 故障域更清晰
  • 调度策略更容易解释
flowchart TD
    A[业务请求增长] --> B{HPA 是否触发}
    B -->|是| C[增加 Pod 副本]
    C --> D{节点资源是否足够}
    D -->|足够| E[调度成功]
    D -->|不足| F[Cluster Autoscaler 扩节点池]
    F --> G[新节点加入]
    G --> E
    E --> H[业务容量提升]

    I[控制平面节点故障] --> J{API LB 健康检查}
    J -->|摘除异常节点| K[切换到健康 API Server]
    K --> L[控制链路保持可用]

一套推荐落地清单

如果你正在搭一个新生产集群,我建议按这个顺序推进,不容易乱。

第一步:先把控制平面做稳

  • 3 控制平面节点
  • API Server 前置 LB/VIP
  • etcd 3 节点
  • 定期备份 etcd
  • 验证单节点故障切换

第二步:把监控补齐

  • Metrics Server
  • Prometheus + Alertmanager
  • 控制平面关键指标看板
  • etcd 延迟与容量告警

第三步:业务工作负载规范化

  • requests/limits
  • readiness/liveness
  • PDB
  • 副本数下限
  • 节点分布策略

第四步:再上弹性扩缩

  • HPA 先从 CPU 开始
  • 核心业务逐步接入更贴近业务的指标
  • 再开启 Cluster Autoscaler
  • 做压测验证扩缩链路闭环

第五步:故障演练

至少做这几类:

  • 停 1 台控制平面节点
  • 停 1 台工作节点
  • 模拟节点池资源打满
  • 验证 HPA 扩容
  • 验证 CA 扩节点
  • 验证发布期间 PDB 生效

很多团队其实不是架构没设计,而是没演练。纸面高可用和真实高可用,差的往往就是这一步。


总结

回到文章开头那个核心问题:
Kubernetes 集群怎么从“能跑”走到“稳、弹、可控”?

答案可以浓缩成三句话:

  1. 控制平面高可用,解决的是集群“有没有大脑”的问题
  2. 工作负载弹性扩缩,解决的是业务“能不能扛住波峰”的问题
  3. 资源治理与调度策略,决定了高可用和弹性是否真的能落地

如果你现在要开始做,我建议优先级这样排:

  • 先做 3 控制平面 + 稳定 API 入口
  • 再做 requests/limits + 可观测性
  • 然后做 HPA + Cluster Autoscaler
  • 最后补上 PDB、拓扑分散、节点池分层

边界条件也很明确:

  • 小规模测试环境 没必要一开始就上复杂高可用
  • 关键生产环境 不要只做 HPA,不做节点扩容和故障演练
  • 大规模复杂场景 优先考虑托管控制平面,减少自维护成本

真正成熟的 Kubernetes 集群,不是组件堆得多,而是每一层设计都能回答一个问题:

控制面故障时还能不能管?
流量暴涨时还能不能扩?
扩了之后会不会把自己拖垮?

如果这三个问题你都能给出明确、可验证的答案,那这套集群架构就已经相当靠谱了。


分享到:

上一篇
《Web3 中级实战:基于智能合约与钱包登录构建可落地的去中心化会员积分系统》
下一篇
《区块链中智能合约安全审计实战:从常见漏洞识别到自动化检测流程搭建-330》