Skip to content

第一部分 数千节点架构设计与容量规划

"一个 100 节点的集群可以靠经验运维,一个 5000 节点的集群只能靠架构运维。"

当集群规模跨过千节点门槛,曾经"能用"的默认配置会一个个变成定时炸弹:etcd 写延迟开始拖垮整个控制平面,kube-proxy 的 iptables 规则膨胀到数十万次匹配,一次大批量发版就能把镜像仓库打到拒绝服务。本部分的目标只有一个:在你按下安装命令之前,就把 5 年后会踩到的坑填平

适用版本:RKE2 v1.28+ / Kubernetes v1.28+。文中所有数据均标注前提,不确定处给出保守区间。

本部分导读

章节主题核心问题
第 1 章K8s 扩展性边界单集群到底能撑多大?
第 2 章总体架构设计控制平面和网络拓扑怎么画?
第 3 章etcd 大规模设计集群的"心脏"如何不先衰竭?
第 4 章网络架构选型CNI / kube-proxy / IP 规划怎么选?
第 5 章DNS 与镜像基础设施数千节点同时拉镜像、同时解析域名怎么办?
第 6 章容量规划方法论用数字说话,不用感觉说话
第 7 章分区与多集群方案单集群 5000 节点之外怎么走?
第 8 章常见面试题架构设计向 10 题(含答案要点)

第 1 章 大规模集群的挑战与 K8s 扩展性边界

1.1 为什么"大规模"是一个质变问题

小规模集群到大规模集群,不是"数量变多",而是统计规律开始生效

  • 100 节点时,节点故障是"小概率事件";5000 节点时,按单节点年故障率 2% 估算,平均每天都有节点处于故障或修复状态
  • 100 节点时,一次发版滚动更新几百个 Pod 是分钟级;5000 节点、10 万 Pod 时,同样的操作可能持续数小时,期间的镜像拉取、DNS 查询、调度决策都会形成"惊群"(thundering herd)。
  • 任何 O(n) 的组件行为(iptables 规则、Endpoints 对象、watch 广播)都会从"无感"变成"主瓶颈"。

注意事项:大规模集群的第一性原理——任何随节点数或 Pod 数线性增长的组件开销,都必须在大规模下被显式设计,不能依赖默认值。

1.2 K8s 官方扩展性数据与前提

Kubernetes 官方 Scalability SIG 给出的单集群支持上限(v1.28 时代依然沿用):

指标官方上限关键前提
节点数5000满足下列全部约束
Pod 总数150000平均每节点 ≤ 100 Pod(非硬性,见第 6 章)
容器总数300000
每节点 Pod 数100(推荐值,非硬上限)受 kubelet、CNI、IPAM 制约
Namespace 数10000
Service 数10000使用 kube-proxy iptables 模式时显著收缩
每 Service 后端 Pod 数5000Endpoints/EndpointSlice 广播开销

这些数字的隐藏前提必须记住:

  1. 这些上限互相耦合,不是"全部同时达到"。例如 5000 节点 + 每节点 100 Pod = 50 万 Pod,已超过 15 万上限——实际组合必须做取舍。
  2. 上限基于官方可扩展性测试环境(GCP 上控制平面高规格机型、万兆网络、本地 SSD etcd),裸金属 + 机械盘 etcd 的环境达不到
  3. 上限是在官方 SLI/SLO(见 1.3)被满足的前提下定义的,不是"集群不挂"的极限。

最佳实践:生产规划时按官方上限的 60%~70% 作为单集群设计容量(即约 3000~3500 节点、10 万 Pod),为突发增长和组件退化留出余量。这也是为什么本书以"数千节点"(而非 5000 整)为标题。

1.3 SLI/SLO:用指标定义"扛得住"

大规模集群的容量结论必须建立在 SLI/SLO 之上,否则"能不能撑住"永远是口水仗。

SLI(Service Level Indicator):可测量的服务水平指标。 SLO(Service Level Objective):SLI 的目标阈值。

K8s 官方定义的核心 SLI/SLO:

SLI官方 SLO说明
API 调用延迟(mutating,如 create/update)P99 ≤ 1s(单对象 ≤ 30 字节范围外的对象另行折算,实践中按 P99 ≤ 1s 记)不含 LIST/GET
API 调用延迟(资源无关的 LIST,如 kubectl get pods 集群级)P99 ≤ 30s大 LIST 允许慢
API 调用延迟(namespace 内 LIST)P99 ≤ 5s
Pod 启动延迟(无状态 Pod,从 create 到 Running,不含镜像拉取)P99 ≤ 5s前提:镜像已预热、无调度排队之外的人为等待

实测这些 SLI 的手段:

bash
# 1) 通过 apiserver 的 Prometheus 指标看 API 延迟
# P99 mutating latency(在任一 server 节点执行)
kubectl get --raw /metrics | grep -E 'apiserver_request_duration_seconds' | head

# 更实用的方式:查询 Prometheus
# histogram_quantile(0.99,
#   sum(rate(apiserver_request_duration_seconds_bucket{verb=~"POST|PUT|PATCH|DELETE"}[5m]))
#   by (le, resource))

# 2) 通过 kubelet 指标看 Pod 启动延迟
# histogram_quantile(0.99,
#   sum(rate(kubelet_pod_start_duration_seconds_bucket[5m])) by (le))

注意事项:RKE2 默认已将 apiserver、scheduler、controller-manager、etcd 以静态 Pod 形式暴露 metrics(注意 scheduler / controller-manager 在较新版本中只绑定在节点 127.0.0.1,需要通过 ServiceMonitor + 代理或修改 --bind-address 才能被集群内 Prometheus 抓取,改绑定地址务必配合 NetworkPolicy 限制访问来源)。

1.4 扩展性瓶颈全景图

大规模集群的瓶颈按"通常最先撞墙"的顺序排列:

                        ┌─────────────────────────────────────┐
                        │          用户 / CI / 控制器          │
                        └───────────────┬─────────────────────┘
                                        │ 全部 API 流量

        瓶颈② kube-apiserver ── CPU/内存/inflight 限流/watch 扇出
                                        │ 读写

        瓶颈① etcd ──────────── 磁盘 fsync 延迟 / DB 8GB / watch 压力

        ┌───────────────────────────────┼───────────────────────┐
        │                               │                       │
  瓶颈③ kube-scheduler            瓶颈④ kubelet × N          瓶颈⑥ CoreDNS
  调度吞吐 ~数百 Pod/s            单节点 Pod 密度/PLEG      查询 QPS 爆炸

                                  瓶颈⑤ 网络
                          iptables 规则膨胀 / conntrack / CNI IPAM
瓶颈典型症状根因本书章节
etcdapply request took too long、leader 切换频繁磁盘 fdatasync 慢、DB 膨胀、compaction 风暴第 3 章
apiserver429(TooManyRequests)、Timeout or aborted while handlinginflight 限流、watch 扇出、大 LIST第 2、6 章
schedulerPod 长时间 Pending 但资源充足调度吞吐不足、调度器插件退化第 6 章
kubeletPLEG is not healthy、容器启动慢单节点 Pod 过密、磁盘/容器运行时压力第 6 章
网络Service 变更生效慢、conntrack 表满iptables 线性匹配、规则爆炸第 4 章
DNS解析超时、CoreDNS OOM每节点 QPS 过高、上游级联第 5 章
镜像大批量发版时拉取超时registry 带宽/连接数打满第 5 章

最佳实践:大规模集群排障的第一张图就画上面这张——先定位瓶颈在哪一层,再决定优化动作。不要凭直觉先调 etcd 参数。

1.5 单一大集群 vs 多集群(舰队):决策框架

这是数千节点规模下最重要的一个架构决策,必须在动工前拍板。

维度单一大集群(3000~5000 节点)多集群舰队(如 10 × 500 节点)
资源利用率高(大池子碎片少,装箱率高)较低(每集群需独立预留 buffer)
爆炸半径大(etcd/apiserver 故障影响全部业务)小(故障域隔离)
运维对象数1 套控制平面N 套控制平面 + 1 套管理层
跨集群服务发现/网络不需要需要(Submariner / ServiceExport / 全局 Ingress 等)
调度复杂度单调度域,亲和性简单需联邦调度(Karmada 等)或应用层路由
升级风险一次升级牵动全局,灰度难可逐集群灰度
团队/多租户隔离依赖 Namespace + RBAC(软隔离)物理级硬隔离
扩展性天花板官方 5000 节点,实际建议 ≤3500理论无上限
镜像/DNS/监控基础设施一套(压力集中)每集群一套或分层共享

决策框架(按优先级回答 4 个问题)

  1. 是否有硬隔离需求?(合规、强多租户、不同安全等级)→ 有则多集群,争论结束。
  2. 单一故障域能否接受全局停摆? → 不能接受则多集群。
  3. 业务是否需要跨地域部署? → 跨地域必然多集群(etcd 对 RTT 敏感,跨 AZ 单集群要求 RTT ≤ ~10ms 才稳妥,见第 3 章)。
  4. 规模是否超过 ~3500 节点? → 超过则多集群。

4 个问题都答"否"(同机房、同安全域、强资源共享诉求、3000 节点以内),单一大集群才是合理选择。

注意事项:不要落入"为做多集群而做多集群"的陷阱。多集群把单集群的容量问题换成了管理问题——需要舰队管理平台(Rancher / Karmada / Fleet)、统一的观测面、跨集群发布流水线。第 7 章详述。

1.6 本章小结

  • 记住三个数:5000 节点 / 15 万 Pod / 30 万容器是官方天花板,生产按 6~7 折规划。
  • 用官方 SLI/SLO(API P99、Pod 启动 P99)作为容量验收标准。
  • 瓶颈全景图:etcd → apiserver → scheduler/kubelet → 网络/DNS,排障按图索骥。
  • 单集群 vs 多集群用 4 问决策框架,先有结论再画架构。

第 2 章 数千节点总体架构设计

2.1 控制平面拓扑:3 / 5 / 7 节点 etcd 仲裁

etcd 基于 Raft,成员数为奇数以优化仲裁(quorum)。容忍故障数 = (n-1)/2:

成员数仲裁数容忍同时故障写延迟适用规模建议
321最低≤ 1500 节点小规模起步可选
532略增1500~5000 节点数千节点生产推荐
743明显增大超大规模/跨 AZ仅在需要跨 3 AZ 各部署多成员时考虑

为什么不是"越多越好":Raft 每次写都要仲裁多数确认,成员越多:

  • 写延迟越高(等待更多节点 fsync 返回);
  • leader 选举更慢、消息扇出更大;
  • 运维面(备份、升级、扩容)更复杂。

最佳实践:数千节点单机房集群用 5 成员 etcd;跨 3 AZ 且每 AZ 都要容灾时用 7(2+2+3 分布)。永远不要为"安全感"上 9 节点。

2.2 独立 etcd 节点 vs 混合部署

RKE2 原生把 etcd 与 server(控制平面组件)部署在一起,但通过 --disable-apiserver --disable-controller-manager --disable-scheduler 可以构造纯 etcd 节点,实现角色分离:

方案优点缺点适用
混合部署(etcd + apiserver 同机)省机器、拓扑简单、RKE2 默认路径故障耦合:一台机器挂=两份控制平面容量同时损失;apiserver CPU 尖峰会拖慢 etcd 磁盘 I/O 调度≤ 数百节点
独立 etcd 节点(推荐)etcd 独占 NVMe 与内存,性能可预测;apiserver 可独立水平扩缩;故障域清晰多 2 台机器(3+2 vs 3);RKE2 需拆分 server 角色部署数千节点必选

独立 etcd 的 RKE2 部署要点:

yaml
# /etc/rancher/rke2/config.yaml —— 纯 etcd 节点(共 5 台)
disable-apiserver: true
disable-controller-manager: true
disable-scheduler: true
node-name: etcd-01
node-ip: 10.10.0.11
yaml
# /etc/rancher/rke2/config.yaml —— 纯控制平面节点(共 3~5 台,无 etcd)
disable-etcd: true
server: https://etcd-01:9345
node-name: cp-01
node-ip: 10.10.0.21

注意事项:拆分角色后,首个引导节点必须是 etcd 节点(cluster-init: true 或作为首个 server);加入顺序与 token 约定与常规多 server 一致。disable-etcd 的控制平面节点仍需能直连所有 etcd 节点的 2379 端口,防火墙策略不要照搬默认文档。

2.3 apiserver 水平扩展与负载均衡

2.3.1 apiserver 是无状态的,但客户端连接不是

apiserver 本身无状态(状态全在 etcd),可以任意水平扩缩。

  • kubelet、controller 与 apiserver 之间是长连接 + watch,HTTP/2 多路复用下单个 TCP 连接承载大量请求;
  • LB 只在连接建立时做负载均衡决策,连接一旦建立就不再迁移
  • 结果:节点重启、证书轮换、LB 漂移都会造成"全部连接挤在某一台 apiserver 上"。

缓解手段:

  1. 客户端侧:kubelet 设置 rotateCertificates(RKE2 默认启用)之外,更关键的是让客户端定期重连——kubelet 无此配置,但 apiserver 侧可用 --goaway-chance 主动断开:
yaml
# /etc/rancher/rke2/config.yaml(控制平面节点)
kube-apiserver-arg:
  - "goaway-chance=0.001"        # 每个请求约 0.1% 概率收到 GOAWAY,促使客户端重连扩散
  - "max-requests-inflight=800"  # 按规格调整,见第 6 章
  - "max-mutating-requests-inflight=400"
  1. LB 侧:使用支持"最小连接数"调度的 LB,而不是轮询(RR 对长连接毫无意义)。

2.3.2 LB 选型对比

方案原理优点缺点大规模适用性
硬件 LB(F5/NetScaler)专用设备 L4 转发性能极高、企业已有、运维成熟贵、配置在 K8s 体系外大型企业首选
HAProxy + Keepalived软件 L4 + VRRP 漂移 VIP免费、灵活、可观测(stats 页)需自运维;VIP 漂移有秒级中断数千节点主流选择
kube-vip节点内 VIP/BGP 宣告无需外部设备、云原生ARP 模式二层受限;BGP 模式依赖交换机中小规模、无外部 LB 环境
云厂商 LB(SLB/NLB)托管免运维仅云上公有云场景

HAProxy + Keepalived 参考配置(6443 端口):

# /etc/haproxy/haproxy.cfg(两台 LB 各一份,Keepalived 负责 VIP 漂移)
global
    log /dev/log local0
    maxconn 100000

defaults
    mode tcp
    timeout connect 5s
    timeout client  300s        # watch 长连接,client/server 超时要足够长
    timeout server  300s

frontend k8s-api
    bind 10.10.0.100:6443
    default_backend k8s-api-backend

backend k8s-api-backend
    balance leastconn            # 关键:长连接场景用最少连接,不用 roundrobin
    option tcp-check
    tcp-check connect port 6443
    # RKE2 apiserver 健康检查端点:/livez(或 /healthz),需忽略自签证书
    tcp-check send "GET /livez HTTP/1.1\r\nHost:\ 10.10.0.100\r\nConnection:\ close\r\n\r\n"
    tcp-check expect rstring "200 OK"
    server cp-01 10.10.0.21:6443 check inter 3s fall 2 rise 2
    server cp-02 10.10.0.22:6443 check inter 3s fall 2 rise 2
    server cp-03 10.10.0.23:6443 check inter 3s fall 2 rise 2

注意事项

  1. 健康检查必须查 /livez(进程存活)而非仅 TCP 通——但要意识到 apiserver 过载时 /livez 也可能变慢,可加 verbose 参数或用 /readyz 做更严格的摘流。实践中推荐:LB 用 /livez 保活,/readyz 由监控系统报警,避免过载时 LB 摘流引发雪崩(把流量全压到剩下的实例上)。
  2. RKE2 的 agent 加入走的是 server: https://<VIP>:9345(supervisor 端口),9345 也需要挂 LB 或指向任一 server;生产建议 6443 与 9345 都过 VIP。
  3. timeout client/server 一定要 ≥ 最长 watch 周期,否则 watch 被 LB 静默掐断,表现为客户端周期性重连风暴。

2.4 故障域设计与拓扑标签

数千节点集群必须显式建模故障域,否则 scheduler 的打散能力形同虚设。

故障域层级(典型三层)

Region(地域)
 └── Zone / AZ(机房/可用区)—— 故障域:供电、制冷、核心网络
      └── Rack(机架)          —— 故障域:ToR 交换机、PDU
           └── Host(节点)

K8s 内置拓扑标签:

标签含义用途
topology.kubernetes.io/region地域多地域集群、PV 拓扑感知
topology.kubernetes.io/zone可用区/机房Pod 反亲和打散、拓扑感知路由
kubernetes.io/hostname主机默认可用

机架级不是内置标签,RKE2 注册节点时自定义:

yaml
# /etc/rancher/rke2/config.yaml(agent 节点)
node-label:
  - "topology.kubernetes.io/zone=az1"
  - "failure-domain.kubernetes.io/rack=rack-a07"
  - "node-role.kubernetes.io/ingress=true"

应用侧用 topologySpreadConstraints 跨机架/机房打散:

yaml
spec:
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: ScheduleAnyway   # 大规模下建议软约束,硬约束易引发 Pending
      labelSelector:
        matchLabels: { app: payment }
    - maxSkew: 2
      topologyKey: failure-domain.kubernetes.io/rack
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels: { app: payment }

最佳实践:大规模集群里 whenUnsatisfiable: ScheduleAnyway 优于 DoNotSchedule——硬约束在节点故障潮(rack 断电后重启几十个节点)时会制造大量 Pending Pod,软约束+监控 skew 更稳。

2.5 参考架构图:生产级数千节点 RKE2 集群

下图为一个 ~3000 节点、三网分离(管理网/业务网/存储网)、独立 etcd 的生产参考架构:

                          ┌──────────────────────────────┐
                          │   运维入口: Rancher Manager  │
                          │   (独立小集群, 见第 7 章)     │
                          └──────────────┬───────────────┘
                                         │ 管理网 10.10.0.0/16
        ┌────────────────────────────────┼────────────────────────────────┐
        │                                ▼                                │
        │                    ┌──────────────────────┐                     │
        │                    │  VIP 10.10.0.100     │  ← Keepalived VRRP │
        │                    │  HAProxy-1  HAProxy-2│    (2 台 LB)       │
        │                    └──────────┬───────────┘                     │
        │              6443/9345        │ leastconn                       │
        │        ┌───────────┬──────────┼──────────┬───────────┐          │
        │        ▼           ▼          ▼          ▼           ▼          │
        │   ┌────────┐ ┌────────┐ ┌────────┐                          │
        │   │ cp-01  │ │ cp-02  │ │ cp-03  │   纯控制平面节点            │
        │   │apiserver│ │apiserver│ │apiserver│  (disable-etcd)         │
        │   │sched/cm│ │sched/cm│ │sched/cm│   16C32G ×3~5            │
        │   └───┬────┘ └───┬────┘ └───┬────┘                          │
        │       │ etcd client 2379    │                               │
        │  ┌────┴─────────┬──┴───────┬┴───────────┬───────────┐       │
        │  ▼              ▼          ▼            ▼           ▼       │
        │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐          │
        │ │etcd-01│ │etcd-02│ │etcd-03│ │etcd-04│ │etcd-05│  独立 etcd│
        │ │ NVMe  │ │ NVMe  │ │ NVMe  │ │ NVMe  │ │ NVMe  │  8C16G   │
        │ │ 跨rack│ │ 跨rack│ │ 跨rack│ │ 跨rack│ │ 跨rack│  跨机架  │
        │ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘          │
        │        2380 peer (Raft) 全网状互联, 延迟 < 10ms             │
        │════════════════════ 管理网 / 控制平面 ════════════════════│
        │                                                           │
        │  ┌─────────────────────────────────────────────────┐     │
        │  │            业务网 10.20.0.0/16 (25G×2 bond)      │     │
        │  │  ┌─────────┐ ┌─────────┐        ┌─────────┐     │     │
        │  │  │worker ×N│ │worker ×N│  ...   │worker ×N│     │     │
        │  │  │ Calico  │ │ Calico  │        │ Calico  │     │     │
        │  │  │kube-proxy│ │kube-proxy│      │kube-proxy│     │     │
        │  │  │NodeLocal│ │NodeLocal│        │NodeLocal│     │     │
        │  │  │ DNSCache│ │ DNSCache│        │ DNSCache│     │     │
        │  │  └────┬────┘ └────┬────┘        └────┬────┘     │     │
        │  └───────┼───────────┼──────────────────┼──────────┘     │
        │          │  Pod 流量 (BGP/VXLAN)        │                │
        │  ┌───────▼───────────▼──────────────────▼──────────┐     │
        │  │   CoreDNS ×8~12    Ingress GW ×6    MetalLB     │     │
        │  └─────────────────────────────────────────────────┘     │
        │                                                           │
        │  ┌─────────────────────────────────────────────────┐     │
        │  │   存储网 10.30.0.0/16 (独立物理网, Ceph/NFS)     │     │
        │  │   worker 第三块网卡直连, 与业务网物理隔离         │     │
        │  └─────────────────────────────────────────────────┘     │
        │                                                           │
        │  ┌───────────── 共享基础设施 ─────────────┐              │
        │  │ Harbor HA ×2 (+Dragonfly P2P 见第5章) │              │
        │  │ Prometheus(分片)/Loki/Alertmanager    │              │
        │  │ NTP / 外部 DNS / 堡垒机               │              │
        │  └───────────────────────────────────────┘              │
        └───────────────────────────────────────────────────────────┘

三网分离要点

网络承载流量网卡建议理由
管理网apiserver/etcd/SSH/监控采集10Getcd 与 apiserver 通信延迟敏感
业务网Pod/Service/Ingress 南北东西流量25G×2 bond业务带宽主体
存储网Ceph/Longhorn/NFS 数据面25G 独立 VLAN 或物理网存储 I/O 尖峰不挤占业务

RKE2 侧配合:node-ip 指定管理网 IP(apiserver/etcd 通信用),advertise-address 同理;CNI(Calico)的 IP_AUTODETECTION_METHOD 指向业务网卡,存储网卡不进 K8s 路由表。

2.6 本章小结

  • etcd 5 成员、独立部署、跨机架放置,是数千节点的控制平面基线。
  • LB 用 HAProxy+Keepalived(或企业现有 F5),leastconn + /livez + 长超时三件套。
  • apiserver 配 goaway-chance 解决长连接不均。
  • 故障域标签 + 软约束 topologySpreadConstraints,让打散在故障潮下依然成立。
  • 三网分离:管理/业务/存储各走各的网卡。

2.7 注意事项 / 最佳实践速查

  • ✅ 控制平面节点全部打上 node-role.kubernetes.io/control-plane 污点(RKE2 默认),业务 Pod 绝不调度上去。
  • ✅ etcd 节点、cp 节点分散在 ≥3 个机架、≥2 路供电。
  • ❌ 不要把 9345 只指向单台 server——新增 agent 加入时该 server 宕机就全员卡住。
  • ❌ 不要在 LB 上对 6443 做 TLS 终止再转发(apiserver 证书体系不允许中间人,除非重新签发并配置 tls-san 与 SNI 透传——直接 TCP 透传最省事)。

第 3 章 etcd 大规模设计

3.1 etcd 性能模型:它为什么会成为第一瓶颈

etcd 是强一致的 Raft KV 存储。每个写请求的路径:

client → leader 接收 → 写 WAL (fsync 到盘) → 广播给 follower
       → 多数派各自写 WAL (fsync) 并应答 → leader 提交
       → 应用到 boltdb (周期性 fsync) → 响应 client

关键结论:

  1. 写延迟 ≈ 磁盘 fsync 延迟 + 网络 RTT 中的较大者。任何一环退化,整个集群的所有写操作(创建 Pod、更新 Endpoint、节点心跳 Lease……)全部变慢。
  2. etcd 是单线程应用 MVCC 数据到 boltdb 的,读可以并发、写串行化,因此 CPU 核数超过 ~8 后收益骤减,单核性能与磁盘性能远比核数重要

etcd 自身暴露的关键指标(etcd_debugging_mvcc_db_total_size_in_bytesetcd_disk_wal_fsync_duration_secondsetcd_network_peer_round_trip_time_seconds)是大规模集群必采指标。

3.2 硬件要求:fdatasync 延迟是金标准

etcd 官方用 fdatasync 的 P99 延迟作为磁盘是否合格的判据:

磁盘类型典型 fdatasync P99是否适合 etcd
机械盘 (HDD)10~100ms+❌ 禁止
SATA SSD1~10ms⚠️ 仅限小规模
企业级 NVMe SSD0.1~1ms数千节点必选
公有云 gp3/io2 等保证 IOPS 的云盘0.5~2ms✅ 云上可用

用 fio 自测(采购验收时必须跑):

bash
# 安装 fio 后,模拟 etcd 的写模式测 99 分位 fdatasync 延迟
fio --rw=write --ioengine=sync --fdatasync=1 \
    --directory=/var/lib/rancher/rke2/server/db \
    --size=100m --bs=2300 --name=etcdbench

# 关注输出中 clat 的 99.00th 分位:
#   < 10ms  → 勉强可用(< 数百节点)
#   < 2ms   → 可用于千节点级
#   < 1ms   → 数千节点理想

同时通过 etcd 指标在线监控:

promql
# WAL fsync P99(应 < 10ms,告警阈值常用 50ms)
histogram_quantile(0.99,
  sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket[5m])) by (le, instance))

# raft 提交延迟
histogram_quantile(0.99,
  sum(rate(etcd_disk_backend_commit_duration_seconds_bucket[5m])) by (le, instance))

# 成员间 RTT(同机房应 < 10ms)
histogram_quantile(0.99,
  sum(rate(etcd_network_peer_round_trip_time_seconds_bucket[5m])) by (le, To))

3.3 DB 大小、quota 与碎片整理

3.3.1 8GB 上限与 quota-backend-bytes

  • etcd 默认 DB quota 为 2GB,官方支持的最大值为 8GB(超过 8GB 官方明确不保证可靠性)。
  • K8s 场景下 DB 大小 ≈ 所有对象总大小 × (1 + 碎片率)。数千节点、10 万 Pod 的集群,etcd DB 常见 2~4GB(含碎片)。
  • 大规模集群建议把 quota 提到 8GB 上限,为突发对象增长留缓冲:
yaml
# /etc/rancher/rke2/config.yaml(etcd 节点)
etcd-arg:
  - "quota-backend-bytes=8589934592"        # 8GB
  - "auto-compaction-mode=periodic"
  - "auto-compaction-retention=8h"          # 见 3.3.2

超过 quota 的症状:apiserver 返回 etcdserver: mvcc: database space exceeded集群只读(可删不可写),这是大规模集群最经典的故障之一。

3.3.2 compaction 与 defrag:一对必须理解的组合拳

概念作用触发方式影响
Compaction(压缩)丢弃旧版本 key,释放逻辑空间RKE2 由 apiserver 周期性触发(默认每 5 分钟 compact 到最近的周期点);etcd 侧 auto-compaction 兜底过程有 I/O 开销;compact 期间延迟毛刺
Defrag(碎片整理)重建 boltdb 文件,释放物理磁盘空间必须手动/定时任务执行(etcdctl defrag),不会自动发生defrag 期间该成员阻塞读写(秒级~十秒级),必须逐成员滚动执行

关键认知:compact 不缩盘,只有 defrag 缩盘。K8s 删除 10 万个 Pod 后,etcd DB 文件不会变小,只是内部出现空洞。

滚动 defrag 脚本(先 follower 后 leader):

bash
#!/bin/bash
# defrag-etcd.sh —— 对 RKE2 嵌入式 etcd 逐成员碎片整理
ETCDCTL="etcdctl --cacert=/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
  --cert=/var/lib/rancher/rke2/server/tls/etcd/client.crt \
  --key=/var/lib/rancher/rke2/server/tls/etcd/client.key \
  --endpoints=https://127.0.0.1:2379"

# 1. 找出当前 leader,最后处理
LEADER=$($ETCDCTL endpoint status --write-out=json \
  | jq -r '.[] | select(.Status.header.member_id == .Status.leader) | .Endpoint')

# 2. 逐成员 defrag(注意:RKE2 嵌入式 etcd 每成员需在各自节点上执行,
#    或用 --endpoints 指向对应成员;生产建议做成 cron + 分布式锁)
for EP in $($ETCDCTL endpoint status --write-out=json | jq -r '.[].Endpoint'); do
  [ "$EP" = "$LEADER" ] && continue
  echo "defrag $EP"
  etcdctl --endpoints="$EP" --cacert=... --cert=... --key=... defrag
  sleep 60   # 等该成员追上 raft 日志
done
echo "defrag leader $LEADER last"

注意事项:defrag 期间该成员停止响应,5 成员集群滚动执行是安全的;3 成员集群 defrag 会短暂只剩 2 成员(恰好等于 quorum,再抖一下就丢仲裁),3 成员集群的 defrag 要放在业务低峰并加强监控

3.3.3 事件历史与 watch 压力

  • K8s 的 watch 机制依赖 etcd 的 revision 历史。compaction 间隔决定"客户端最多能回看多久的历史"。
  • apiserver 默认每 5 分钟 compact 一次。后果:watch 断线超过 compact 窗口的客户端会收到 410 Gone(too old resource version),被迫全量 relist
  • 大规模集群里,一个失控控制器(informer 配置错误、网络分区恢复)发起的全量 relist 风暴是 apiserver 过载的常见原因。

缓解:

yaml
# apiserver 侧:限制 LIST 的分页,强制大 LIST 走分页
kube-apiserver-arg:
  - "default-watch-cache-size=1000"   # 大集群可适度调大 watch cache
# 客户端侧(自研控制器):informer 必须设置 ResourceVersion 续传、
#   避免全量 List;巧用 metadata-only informer 降低对象体积

监控 watch 压力:

promql
# 各资源类型的 watch cache 大小与 watch 连接数
sum(apiserver_watch_events_total) by (resource)
sum(apiserver_current_inflight_requests) by (request_kind)
# relist 风暴信号:LIST 请求 QPS 突增
sum(rate(apiserver_request_total{verb="LIST"}[5m])) by (resource)

3.4 备份策略

RKE2 内置 etcd 快照,开箱即用但默认参数不适合大规模:

yaml
# /etc/rancher/rke2/config.yaml(etcd 节点)
etcd-snapshot-schedule-cron: "0 */2 * * *"   # 每 2 小时(默认 12 小时太稀疏)
etcd-snapshot-retention: 12                  # 保留 24 小时窗口
etcd-s3: true                                # 快照自动上传 S3 兼容存储
etcd-s3-endpoint: "minio.infra.local:9000"
etcd-s3-bucket: "rke2-etcd-snapshots"
etcd-s3-access-key: "xxx"
etcd-s3-secret-key: "xxx"

手动快照与校验:

bash
# 立即打快照
rke2 etcd-snapshot save --name manual-$(date +%F-%H%M)

# 列出快照
rke2 etcd-snapshot list

# 恢复演练(每季度必做!在隔离环境)
rke2 server --cluster-reset \
  --cluster-reset-restore-path=/var/lib/rancher/rke2/server/db/snapshots/<快照名>

备份策略矩阵:

层级手段RPO说明
L1RKE2 定时快照(本地)2h快速回滚,防误操作
L2快照同步到 S3/MinIO(异地)2h防机房级灾难
L3声明式备份(GitOps 全量 manifest)提交时集群可重建的最终保障

最佳实践:etcd 快照恢复的是"数据",恢复不了"信任"——大规模集群恢复演练要包含 LB、证书、node 重新加入的完整剧本。没演练过的备份等于没有备份。

3.5 本章小结

  • etcd 写延迟 = max(磁盘 fsync, 网络 RTT);NVMe 是硬门槛,fio 验收 P99 < 1~2ms。
  • quota 提到 8GB;compact(逻辑)与 defrag(物理)分工记牢,defrag 滚动执行。
  • watch/relist 风暴是大规模特有杀手,监控 LIST QPS。
  • 快照 2h 一次 + S3 异地 + 季度恢复演练。

第 4 章 网络架构选型

4.1 CNI 在数千节点下的选型对比

RKE2 内置支持 Canal(默认)、Calico、Cilium、Multus 等。大规模下的核心差异在于转发路径状态同步机制

CNI数据面控制面状态同步数千节点适用性说明
Canal(Flannel VXLAN + Calico Policy)VXLAN(内核 flannel.1)每个节点 watch 全量 Node/Pod 元数据⚠️ 可用但非最优RKE2 默认;VXLAN 封包有 ~50B 开销与 MTU 损失
Calico VXLANVXLAN同上,Calico 可用 Typha 做 fanout 代理✅ 可用(必须开 Typha)兼容性好,排障简单
Calico BGP纯路由(无封装)BGP 路由反射器(Route Reflector)裸金属数千节点主流无 overlay 开销;需交换机/RR 配合
Cilium(eBPF)eBPF(native routing 或 VXLAN/Geneve)内置 kvstore 或 CRD 模式 + 可替代 kube-proxy性能上限最高NetworkPolicy/可观测性最强;内核要求 ≥ 4.19,建议 5.x
Flannel host-gw静态路由简单⚠️ 二层受限仅适合扁平二层网络
kube-OVNOVN/OpenFlowOVN 南北向 DB✅ 可用功能全(VPC/QoS),复杂度也高

关键扩展性机制——状态扇出

默认模式下,每个节点的 CNI agent 都直连 apiserver watch 全量 Node/Pod 信息。3000 节点 = 3000 条 watch 长连接扇出全量事件,apiserver 压力巨大。两派的解法:

  • Calico → Typha:apiserver ← Typha(3~5 副本)← 所有 calico-node。Typha 把扇出收敛到个位数连接。超过 ~100 节点就应启用。
yaml
# Calico 启用 Typha(HelmChartConfig 方式,RKE2 体系内)
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: rke2-calico
  namespace: kube-system
spec:
  valuesContent: |-
    typha:
      enabled: true
      replicas: 3        # 每 ~200 节点 1 副本,上限 20 副本
  • Cilium → 无此问题:CRD 模式下状态对象化 + eBPF map 本地决策;且可用 --kube-proxy-replacement=strict 彻底移除 kube-proxy(见 4.3)。

BGP 模式的路由反射器拓扑(Calico 大规模标配):

        ┌─────────────┐   ┌─────────────┐
        │  RR-1 (ToR  │   │  RR-2 (独立  │     RR = BGP Route Reflector
        │   交换机)   │   │   服务器)    │     每个 node 只与 RR 建 BGP 会话
        └──────┬──────┘   └──────┬──────┘     避免 3000×3000 全互联
               │   iBGP          │
   ┌───────────┼─────────────────┼───────────┐
   ▼           ▼                 ▼           ▼
 node-1      node-2   ......  node-2999   node-3000
 (每节点宣告自己的 Pod CIDR /26 或 /27 路由)

4.2 Pod CIDR 与 IPAM 规划

数千节点 × 每节点数十~上百 Pod,IP 地址规划错误是最痛且最难改的架构失误(改 cluster-cidr 约等于重建集群)。

4.2.1 规划原则

  1. 容量按终态规划:节点数终值 × 每节点 Pod 上限 × 1.5(冗余)。
  2. 避开现有网段10.0.0.0/8172.16.0.0/12192.168.0.0/16 与企业内网、云上 VPC、IDC 网段的冲突要逐一排查,包括未来可能互联的网络。
  3. Service CIDR 独立:service-cidr 不需要太大(/16 给 6.5 万 Service 绰绰有余),但同样不能重叠。

4.2.2 计算案例(3000 节点终态)

参数取值计算
节点终值3000(规划到 4096)
每节点 Pod 上限128见第 6 章
Pod IP 总需求4096 × 128 = 524,288≈ 52 万
单节点掩码/25(128 地址,126 可用)每节点一个 /25
节点块总数4096 × /25 = /13
cluster-cidr 选择10.12.0.0/13(524,288 地址)刚好用尽;保守用 /12(如 10.64.0.0/12 含 104 万)
service-cidr10.13.0.0/16(示例小集群值;大集群建议避开 10.12.0.0/13 所在范围)6.5 万 Service

RKE2 配置:

yaml
# /etc/rancher/rke2/config.yaml
cluster-cidr: 10.64.0.0/12          # 给终态留 2 倍余量
service-cidr: 10.96.0.0/16
cluster-dns: 10.96.0.10
yaml
# Calico 侧:节点块大小(IPPool blockSize)
# blockSize=25 → 每节点 /25,126 个 Pod IP
# 注意:blockSize 越小,BGP 宣告的路由条数越多(每节点一条)
#       /25 → 4096 条节点路由,对 RR 无压力;/27 → 路由表更碎

注意事项

  • Cilium/Calico 原生 routing 模式下 Pod IP 直接从底层可达,Pod CIDR 不能与企业内任何需要访问 Pod 的网段重叠;VXLAN 模式下可放宽(外部看到的是节点 IP)。
  • 规划文档必须沉淀(IPAM 登记表),数千节点集群后期合并/互联时,CIDR 冲突是头号拦路虎。

4.3 kube-proxy:iptables / IPVS / eBPF

这是大规模集群教科书级的瓶颈点(本仓库 metaLB/ 目录有专题深挖,此处给结论)。

4.3.1 iptables 模式为什么在大规模下失效

kube-proxy iptables 模式把每个 Service 的每个后端翻译成若干条 iptables 规则,包转发是线性匹配

规模规则条数(估算)后果
1000 Service × 平均 3 后端~1~2 万条无感
5000 Service × 平均 5 后端5~10 万条首包延迟显著、规则更新(Endpoints 变化)整表重建耗时秒级~十秒级、更新期间转发抖动
大 Endpoints 频繁变动规则重写 QPS 高conntrack 抖动、CPU softirq 飙高

更糟的是:每条规则同步是全量重写(iptables-save/restore),Service 越多每次越慢,越慢期间 Pod 增删越多——恶性循环。

4.3.2 IPVS 模式

IPVS 用哈希表存 Service→后端映射,查找 O(1),规则增量更新:

yaml
# /etc/rancher/rke2/config.yaml(本仓库 rke2/ 目录实测配置)
kube-proxy-arg:
  - "proxy-mode=ipvs"
  - "ipvs-scheduler=lc"        # least-connection,长连接业务友好;默认 rr

节点内核需加载模块(RKE2 会自动加载大部分,建议固化):

bash
cat > /etc/modules-load.d/ipvs.conf <<EOF
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
ip_vs_lc
nf_conntrack
EOF

IPVS 大规模下的残留问题:conntrack 表压力依旧存在(iptables/IPVS 都依赖 conntrack),需要调大并监控:

bash
# 当前用量与上限
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
# 数千节点 + 高密度节点建议 nf_conntrack_max ≥ 2000000,并缩短非活跃 UDP 超时
sysctl -w net.netfilter.nf_conntrack_max=2097152

4.3.3 eBPF(Cilium kube-proxy replacement)

  • Service 查找、负载均衡、conntrack 全部在 eBPF map 中完成,完全绕过 iptables/conntrack 主路径
  • 支持 Maglev 一致性哈希(连接保持)、DSR(直接服务端返回)、XDP 加速;
  • 代价:学习曲线陡、内核版本要求高(建议 ≥ 5.10 LTS 内核,Rocky 9 默认 5.14 可用)、排障工具链换成 cilium CLI 与 Hubble。

选型结论表

集群规模推荐数据面备注
< 500 节点任意(Canal+iptables 也能跑)简单优先
500~3000 节点Calico(VXLAN 或 BGP) + Typha + IPVS稳妥主流
3000~5000 节点或高密度 ServiceCilium eBPF(替代 kube-proxy) 或 Calico BGP + IPVS性能上限优先

4.4 NetworkPolicy 在大规模下的考量

  • 策略本身也是 CNI 数据面的状态:数千节点 × 数千条策略,Calico 会编译成每个节点的 iptables/ipset(注意又回到 iptables 匹配问题——但 policy 规则通常远少于 Service 规则);Cilium 则在 eBPF map 中,膨胀代价低得多。
  • 全集群默认拒绝 + 按需放行是安全基线,但默认拒绝规则会作用到每个 Pod,注意 DNS(kube-dns)、NodeLocal DNSCache(169.254.20.10 与上游 10.96.0.10)必须显式放行,否则大面积解析故障。
  • 策略变更的传播延迟随节点数增长,Calico 开 Typha 后约秒级;变更后务必有自动化拨测验证。
yaml
# 大规模集群 NetworkPolicy 基线示例:default ns 默认拒绝,放行 DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector:
            matchLabels: { kubernetes.io/metadata.name: kube-system }
      ports:
        - { protocol: UDP, port: 53 }
        - { protocol: TCP, port: 53 }

4.5 Service 与 Endpoints 的数量上限

  • 官方上限 10000 Service;使用 IPVS/eBPF 后可以突破,但 Endpoints 扇出成为新瓶颈:每个 Endpoints 对象变化要推给所有节点的 kube-proxy watch。
  • K8s v1.21+ 的 EndpointSlice(默认开启)把大 Service 的后端切成 ≤100 个/片,扇出量按片计算,是大规模必须依赖的机制——确认没有老旧组件直接消费 Endpoints API。
  • 超大 Service(>5000 后端)尽量避免;业务上改用分片 Service + 客户端选择。

4.6 本章小结

  • CNI 二选一:稳妥选 Calico(+Typha,裸金属优先 BGP),性能上限选 Cilium eBPF。
  • IP 规划按终态 ×1.5~2 预留,/12 起步不丢人,CIDR 冲突才丢人。
  • 超过千节点 Service 规模,kube-proxy 用 IPVS 或直接 eBPF 替代;conntrack 上限同步调大。
  • NetworkPolicy 全默认拒绝基线 + DNS 放行;EndpointSlice 必须全程生效。

第 5 章 DNS 与镜像基础设施

5.1 CoreDNS 水平扩展

默认 2 副本 CoreDNS 在数千节点集群里是裸奔。容量估算经验值(保守):

  • 每 Pod 平均 DNS QPS 按 2~5 估算,10 万 Pod ≈ 20 万~50 万 QPS 集群总查询量
  • 单副本 CoreDNS(2C 限值)实测约 2~5 万 QPS(取决于响应大小、缓存命中率);
  • → 需要 8~20 副本,跨节点反亲和部署。
yaml
# CoreDNS 扩副本(RKE2 通过 HelmChartConfig 或直接改 deployment)
kubectl -n kube-system scale deployment rke2-coredns-rke2-coredns --replicas=12

注意三件事:

  1. autoscaler 模式:大规模建议用 cluster-proportional-autoscaler(按节点数线性扩副本):
yaml
# ladder 模式:每 64 节点 1 副本,最低 8,最高 24
data:
  ladder: |-
    {
      "coresToReplicas": [],
      "nodesToReplicas":
      [
        [1, 8],
        [512, 10],
        [1024, 12],
        [2048, 16],
        [4096, 24]
      ]
    }
  1. CoreDNS Service 只有少量 ClusterIP:kube-dns Service 后端 12 个 Pod,IPVS/eBPF 会把单节点 DNS 请求均衡到全部副本,没问题;但要确认 ndots:5 带来的搜索域展开(每个外部域名先查 5 次集群内域)——大规模集群可引导业务镜像用 FQDN 尾点(example.com.)或调 dnsConfig.ndots

  2. 反亲和与 PDB:12 副本必须跨节点、跨机架打散,并配 PodDisruptionBudget(minAvailable: 50%),否则一次节点维护窗口可能同时带走多个 DNS 副本引发解析雪崩。

5.2 NodeLocal DNSCache:大规模下的必选项

即使有 20 副本 CoreDNS,仍然存在结构性问题:

  • DNS 默认走 UDP + conntrack:每个节点的 DNS 查询都占 conntrack 条目,高密度节点上 DNS 是 conntrack 打满的头号元凶之一;
  • 跨节点网络跳转增加延迟与故障面;
  • CoreDNS 副本重启/调度期间,部分节点解析抖动。

NodeLocal DNSCache 以 DaemonSet 在每节点起本地缓存(监听 169.254.20.10),Pod 的 DNS 查询优先命中本节点:

优化前:Pod ──(conntrack/跨节点)──▶ CoreDNS ──▶ 上游
优化后:Pod ──▶ 本节点 nodelocaldns (169.254.20.10)
                    │ 缓存未命中
                    ▼ (TCP 向上游,规避 conntrack UDP 抖动)
                CoreDNS ──▶ 上游

部署要点(RKE2 环境):

bash
# 官方 manifest 模板渲染(关键变量):
#   __PILLAR__DNS__SERVER__     = kube-dns ClusterIP(如 10.96.0.10)
#   __PILLAR__LOCAL__DNS__      = 169.254.20.10
#   __PILLAR__DNS__DOMAIN__     = cluster.local
kubectl apply -f nodelocaldns.yaml

# kubelet 需指向本地 DNS(RKE2 config.yaml,所有节点):
# cluster-dns: 169.254.20.10
# 注意:修改 cluster-dns 需要滚动重启节点或重建 Pod 才全量生效

收益(经验值,视业务 DNS 密度而定):

指标优化前优化后
集群内域名解析 P995~30ms<1ms(本地缓存命中)
CoreDNS 副本数需求NN/3 ~ N/5(缓存吸收大部分 QPS)
conntrack UDP 条目显著下降(nodelocaldns 向上游用 TCP)

注意事项:NodeLocal DNSCache 与 NetworkPolicy 的交互是经典坑——默认拒绝策略会阻断 Pod 到 169.254.20.10 的流量(它不在任何 namespace 内)。Cilium/Calico 需用 CIDR 型 egress 规则放行 169.254.20.10/32 的 53 端口。

5.3 镜像仓库架构:扛住数千节点同时拉镜像

场景量化:一次大版本滚动更新 3000 节点,假设镜像层 1.5GB、窗口 10 分钟 → 需要聚合带宽 3000×1.5GB/600s = 7.5 GB/s = 60 Gbps。单 registry 无论如何扛不住。必须分层架构:

                    ┌──────────────────────┐
                    │   Harbor 主站 (HA×2)  │  ← 推送/CI 写入、元数据、漏洞扫描
                    │   对象存储后端 (S3)   │
                    └──────────┬───────────┘
                               │ 预分发/同步
              ┌────────────────┼────────────────┐
              ▼                ▼                ▼
        ┌───────────┐   ┌───────────┐    ┌────────────┐
        │ Harbor 副本│   │ Harbor 副本│    │ Dragonfly  │  ← P2P 层
        │ (机房A)    │   │ (机房B)    │    │ 超级节点 ×3 │
        └─────┬─────┘   └─────┬─────┘    └─────┬──────┘
              │               │                │ P2P 分发
        ┌─────┴───────────────┴────────────────┴──────┐
        │     3000 worker:containerd 拉取             │
        │     - 配置 registry mirror(就近副本)        │
        │     - 或运行 dfdaemon,P2P 互传镜像层         │
        └─────────────────────────────────────────────┘

5.3.1 Harbor 高可用要点

  • 无状态组件(core/registry/portal)×2 挂 LB;PostgreSQL/Redis 外置高可用;registry 存储用 S3 兼容对象存储(不要用本地盘,否则副本间还要同步镜像数据);
  • 开启 镜像代理缓存项目(proxy cache)缓存上游(Docker Hub 等),避免数千节点穿透到公网;
  • GC 与漏洞扫描任务错开业务高峰——大规模仓库的 Trivy 全量扫描能把 DB 打满。

5.3.2 P2P 分发:Dragonfly / Kraken

方案现状特点
Dragonfly(CNCF Graduated)活跃,推荐dfdaemon 驻节点做 P2P;超级节点(seed peer)做回源与种子;支持 containerd 集成
Kraken(Uber 开源)维护趋缓类似架构,tracker+agent

Dragonfly 与 RKE2(containerd)集成思路:containerd 的 registry 配置把 Harbor 指向本机 dfdaemon 代理端口,dfdaemon 负责 P2P 拉取与回源:

toml
# /etc/rancher/rke2/registries.yaml(RKE2 私有 registry 配置)
mirrors:
  harbor.infra.local:
    endpoint:
      - "http://127.0.0.1:65001"        # dfdaemon 代理端口
      - "https://harbor.infra.local"    # P2P 不可用时回退直连
configs:
  harbor.infra.local:
    auth:
      username: xxx
      password: xxx

收益:热点镜像层由节点间互传,回源流量与节点数近似解耦(从 O(n) 降到 O(1)~O(log n)),60Gbps 的洪峰可压到源站 <5Gbps。

5.3.3 不用 P2P 的保守替代

  • Harbor 副本分层(每机房/每故障域一套代理缓存项目),RKE2 registries.yaml 的 mirror endpoint 按节点所在机房配置就近副本;
  • 配合镜像预热(DaemonSet 预拉取大镜像)和滚动更新限速(maxUnavailable 调小),把瞬时带宽需求摊平。

最佳实践:无论用不用 P2P,发布系统必须实现"镜像预分发后再滚动"的两阶段发布;imagePullPolicy: IfNotPresent + 明确的镜像 tag(禁用 :latest)。

5.4 本章小结

  • CoreDNS 按节点数线性扩(autoscaler),12~24 副本 + 反亲和 + PDB。
  • NodeLocal DNSCache 在千节点以上视为必选,注意 NetworkPolicy 放行 169.254.20.10。
  • 镜像面:Harbor HA(S3 后端)+ 分层 mirror,洪峰场景上 Dragonfly P2P;发布侧两阶段预分发。

第 6 章 容量规划方法论

6.1 控制平面规格估算表

基于官方可扩展性测试数据与社区生产经验(前提:NVMe etcd、万兆网、对象大小中位数 ~1KB 级别、无失控控制器),给出保守估算:

节点规模apiserver 实例单实例 CPU/内存etcd 成员etcd 单实例 CPU/内存/盘说明
≤ 50034C / 8~16GB32~4C / 8GB / 50GB NVMe可混合部署
500~150038C / 16~32GB3~54C / 16GB / 100GB NVMe建议 etcd 独立
1500~30003~516C / 32~64GB54~8C / 16~32GB / 200GB NVMe角色全分离
3000~5000532C / 64~128GB58C / 32GB / 500GB NVMe需精细化调优

apiserver 内存的经验公式(粗算,供预留用):

apiserver 内存 ≈ 基数(2GB) + watch cache 对象总大小 × 1.5~2
              ≈ 2GB + (对象数 × 对象平均大小) × 1.7

例:15 万 Pod × 3KB + 其它对象 ≈ 0.7GB 原始 → watch cache ≈ 1.2GB
    再加 inflight 请求缓冲、序列化开销、波动余量 → 单实例 16~32GB 合理

调整 apiserver 限流与缓存:

yaml
# /etc/rancher/rke2/config.yaml(3000 节点参考值)
kube-apiserver-arg:
  - "max-requests-inflight=800"          # 默认 400
  - "max-mutating-requests-inflight=400" # 默认 200
  - "default-watch-cache-size=2000"      # 大集群调大 watch cache
  - "goaway-chance=0.001"
  - "event-ttl=2h"                       # 大规模集群 Event 是 etcd 体积大户

注意事项max-requests-inflight 不是越大越好——它的意义是在 apiserver 过载时快速失败(429)保护 etcd,调太大等于拆掉了保险丝。配套手段是 APF(API Priority and Fairness,v1.20+ 默认 Beta 并启用),用 FlowSchema 给系统组件(kubelet、scheduler)保留独立队列,防止某个失控控制器饿死节点心跳。

6.2 节点密度规划:110 Pod 上限的改与不改

kubelet 默认 maxPods: 110。RKE2 同样默认 110。改不改?

每节点 Pod 数前提风险
≤ 110(默认)最稳妥,官方测试基线
110~150CNI IPAM 块匹配(/25=126)、kubelet 资源充足、镜像预热PLEG 延迟上升,需监控
> 200官方无测试背书;IP 块 /24;事件/watch/iptables 全链路放大不推荐,除非有专项压测

RKE2 调整:

yaml
# /etc/rancher/rke2/config.yaml(worker)
kubelet-arg:
  - "max-pods=128"
  - "kube-api-qps=50"        # 大集群每个 kubelet 的 QPS 要控制(默认 5/10 已偏小,
  - "kube-api-burst=100"     #   但无限制上调会让 3000 个 kubelet 打爆 apiserver)

关键乘数效应:3000 节点 × kube-api-qps=50 理论上限 = 15 万 QPS 打向 apiserver——所以 kubelet QPS 宁小勿大,节点 Ready 抖动时(如雷暴断电后批量恢复)心跳风暴是真实事故场景。默认值(QPS 5/burst 10)在大多数场景足够,节点 Lease 心跳间隔由 --node-status-update-frequency(默认 10s)与 Lease 续约(默认 40s)控制,与 QPS 共同决定心跳总量。

单节点 kubelet 压力点清单

资源默认/常见值大规模建议
maxPods110≤ 128~150,配合 CNI 块
容器运行时containerd限制 max_concurrent_downloads(默认 3,批量调度时保护磁盘)
镜像 GCimageGCHighThreshold 85%高密度节点降到 70~75%,留缓冲
日志容器日志按 10Mi×5严控 stdout 洪峰业务(logrotate 风暴会拖死节点磁盘 IO)
系统预留system-reserved/kube-reserved生产必配,防止 Pod 把节点资源吃干导致 kubelet/SSHD 失联
yaml
kubelet-arg:
  - "max-pods=128"
  - "system-reserved=cpu=500m,memory=1Gi"
  - "kube-reserved=cpu=500m,memory=2Gi"
  - "eviction-hard=memory.available<500Mi,nodefs.available<10%"
  - "image-gc-high-threshold=75"
  - "image-gc-low-threshold=65"
  - "container-log-max-size=10Mi"
  - "container-log-max-files=3"

6.3 增长预留原则

  • 控制平面:按 18 个月终态规模 × 1.3 预留(etcd 盘、apiserver 内存可纵向扩,但机房机位不一定能加)。
  • 网络/IP:CIDR 按终态 × 1.5~2(见 4.2),这是唯一不可事后扩容的维度,给最足。
  • 业务容量:集群可分配资源(allocatable)利用率日常控制在 60~70%,保留故障转移空间——一个 rack(~40 节点)宕机时,其负载要能塞进剩余节点。
  • N+1 机架冗余:按"任意一个机架整体丢失,集群仍满足 SLO"做容量验算。

6.4 完整测算案例:3000 节点集群

输入条件:终态 3000 worker;平均每节点 100 Pod(30 万上限内取 30 万的一半以下,实际 10 万 Pod 业务基线 + 5 万峰值余量);裸金属,单机房 3 个供电分区,每分区 8 个机架。

6.4.1 控制平面测算

取值依据
etcd5 成员,8C/32GB/500GB NVMe×2(RAID1),跨 3 供电分区 5 机架6.1 表;fdatasync P99 < 1ms 采购验收
控制平面5 台,32C/64GB,disable-etcdLB leastconn 均匀分担
LB2 台 HAProxy+Keepalived,4C/8GB,10G纯 L4 转发,CPU 余量 10 倍
apiserver 参数inflight 800/400,watch cache 20006.1
etcd quota8GB;快照 2h/次 × 12 份 + S33.3、3.4

6.4.2 网络与 IP 测算

取值计算
Pod IP 需求3000 × 128 = 384,000maxPods=128
cluster-cidr10.64.0.0/12(1,048,576 地址)需求 × 2.7,富余
节点块/25(126 可用)× 3000 块Calico blockSize=25
service-cidr10.96.0.0/166.5 万 Service
Service 数上限规划 ≤ 8000官方 1 万的 80%
CNICalico BGP + Typha×6 + 2 台 RR每 500 节点 1 Typha 副本
kube-proxyIPVS,conntrack_max=2M4.3
DNSNodeLocal + CoreDNS 16 副本5.1、5.2

6.4.3 节点与机架测算

取值
worker 规格32C/256GB(通用池)+ 128C/1TB(大数据池,单独节点池/标签)
机架分布3000 / 24 机架 = 125 台/机架,每机架 ≤ 40% 单机柜功率
N+1 验算丢 1 机架 = 丢 125 节点(4.2%)→ 业务 requests 利用率需 ≤ 65%,✅
同时维护上限每窗口 ≤ 1 机架(PDB + ClusterAutoscaler/人工节奏控制)

6.4.4 基础设施测算

取值
Harbor2 站点 HA + S3 后端;发布峰值按 3000 节点 × 1.5GB / 30min = 2.5GB/s 镜像拉取预算 → Dragonfly P2P 兜底
监控Prometheus 分片(按 namespace 哈希)+ 长周期存储(VictoriaMetrics/Thanos);节点 exporter 3000 个 target,采集间隔 30s
日志每节点 100 Pod × 1MB/s 峰值 → 集群峰值 ~100GB/s 级别不现实,必须在应用侧限流 + 采样,采集侧 Loki/ES 按热点业务配额制

6.4.5 验收 SLI 清单(上线前压测)

bash
# 用 perf-tests/clusterloader2 做官方密度压测(规模缩减到预算内)
git clone https://github.com/kubernetes/perf-tests
# 例:300 节点抽样的 density 测试,外推 SLI 余量
SLI目标验收方式
API mutating P99≤ 1sPrometheus histogram
Namespace LIST P99≤ 5s同上
Pod 启动 P99≤ 5s(镜像预热)kubelet 指标
etcd WAL fsync P99≤ 10ms(目标 ≤ 2ms)etcd 指标
DNS 解析 P99≤ 10msnodelocaldns 指标 + 拨测

6.5 本章小结

  • 容量规划 = 查表(6.1)→ 定密度(6.2)→ 乘冗余(6.3)→ 案例验算(6.4)→ SLI 验收(6.4.5)。
  • 三个不可事后补救的决策:CIDR、etcd 磁盘选型、故障域标签体系——动工前冻结。
  • kubelet 参数有乘数效应,任何 per-node QPS 调整都要 × 节点数重新审视。

第 7 章 分区与多集群方案

7.1 单集群之外的出路:什么时候必须拆分

回顾 1.5 的决策框架,当以下任一成立时进入多集群设计:

  • 规模 > ~3500 节点(生产保守线);
  • 跨地域/跨机房且 RTT > 10ms(etcd 无法跨地域延展);
  • 硬隔离(安全合规、租户、环境:生产/预发/测试天然分集群);
  • 爆炸半径管控(金融级业务按业务线拆分集群)。

拆分维度(可组合):

维度示例优点代价
按地域北京/上海/深圳各一集群就近接入、故障域隔离跨地域服务发现
按业务线交易/搜索/推荐分集群爆炸半径小、权责清晰共享中间件需跨集群
按环境prod/staging/dev变更隔离环境漂移风险
按硬件代际GPU 集群独立驱动/内核版本解耦池子变小

7.2 多集群管理技术选型速览

方案类型定位与 RKE2 的契合度
Rancher Manager + Fleet管理面 + GitOps集群生命周期管理 + 多集群应用分发★★★★★(RKE2 同门)
Karmada(CNCF)联邦调度跨集群工作负载编排、故障转移★★★★(与发行版无关)
Clusternet(CNCF Sandbox)应用分发侧重子集群应用下发、访客集群免凭据★★★
Open Cluster Management (OCM)管理面Red Hat 系多集群管理★★★
vCluster 等虚拟集群租户隔离在宿主集群内开虚拟控制平面隔离粒度介于 ns 与集群之间

注意 kubefed(Federation v2)已归档,新选型不要入坑。Karmada 是其事实继任者。

7.3 Rancher Fleet 管理多 RKE2 集群

Rancher 体系下,Fleet 是内置的多集群 GitOps 引擎(持续交付),与 RKE2 集群注册(cluster registration/agent)天然集成:

        ┌────────────────────────────────────┐
        │        Rancher Manager (HA)        │
        │  ┌──────────┐   ┌───────────────┐  │
        │  │ Cluster  │   │ Fleet         │  │
        │  │ Manager  │   │ Controller    │  │
        │  └────┬─────┘   └───────┬───────┘  │
        └───────┼─────────────────┼──────────┘
                │ 注册隧道(agent)  │ GitOps 下发
     ┌──────────┼────────┐       │
     ▼          ▼        ▼       ▼
 ┌───────┐  ┌───────┐  ┌───────┐
 │RKE2-01│  │RKE2-02│  │RKE2-03│  ... 数十~数百个下游集群
 │(prod) │  │(prod) │  │(edge) │
 └───────┘  └───────┘  └───────┘

Fleet 的 GitRepo 按 label 匹配集群组(ClusterGroup),典型用法:

yaml
# fleet.yaml(Git 仓库中,描述"这批配置下发到哪些集群")
targetCustomizations:
  - name: prod-large
    clusterSelector:
      matchLabels:
        env: prod
        scale: large
    helm:
      values:
        corednsReplicas: 16
  - name: edge
    clusterSelector:
      matchLabels:
        env: edge
    helm:
      values:
        corednsReplicas: 2

用 Fleet 管理什么(建议边界):

  • ✅ CNI/CoreDNS/NodeLocal DNS/监控 agent/安全基线等"集群级底座组件"——全部 GitOps 化;
  • ✅ NetworkPolicy 基线、PSA 标签、ResourceQuota 模板;
  • ⚠️ 业务应用:业务团队有自己的 CD 流水线时,Fleet 只负责底座,避免两套发布系统打架。

7.4 Rancher Manager 自身的大规模部署

管理数百个下游 RKE2 集群时,Rancher Manager 自己就是瓶颈:

建议
部署位置独立的专用小集群(3 server RKE2/k3s,绝不与管理对象同集群——管理面挂了不能连自救入口都没有)
规格每节点 8C/32GB 起步;下游集群 > 100 或节点总数 > 5 万时 16C/64GB,并拆分多个 Rancher 实例按域分管
etcd独立 NVMe;Rancher 把大量 CRD(Cluster、Catalog、Token 等)写入 etcd,watch 数量随下游集群数暴涨
数据库注意Rancher 无外部 DB,一切在 etcd——Rancher 集群的 etcd 快照策略与第 3 章同标准执行
网络下游 agent 与 Manager 之间是出站长连接(WebSocket 隧道),出口带宽按 下游集群数 × ~1Mbps 余量规划
升级先升 Manager 再分批升下游;用 Fleet/节点池分批控制节奏

最佳实践:Rancher 管理面遵循"三个分离"——与业务集群分离部署、与业务账号体系分离(独立 IdP 组)、与业务变更窗口分离。

7.5 多集群下必须补齐的能力清单

单集群拥有的能力,多集群都要回答"跨集群怎么办":

能力单集群多集群方案
服务发现Service/DNS全局 DNS(如按集群子域 svc.cluster-01.global)、mcs-api(ServiceExport/Import)、或服务网格多集群
流量入口Ingress ×1全局负载(GSLB/Anycast)+ 每集群本地 Ingress
身份RBAC统一 IdP(OIDC/LDAP)+ 各集群 RoleBinding 模板化下发
观测一套 Prometheus分层:每集群本地 Prometheus → 全局 Thanos/VictoriaMetrics 汇聚
发布helm/kustomizeFleet/ArgoCD ApplicationSet/Karmada
策略NetworkPolicy/OPAGatekeeper + Fleet 统一下发,审计汇聚

7.6 本章小结

  • 拆分先定维度(地域/业务/环境),再选管理面(RKE2 生态首选 Rancher + Fleet)。
  • Rancher Manager 部署在独立小集群,自身按第 3 章标准做 etcd 保障。
  • 多集群 = 单集群能力 × N + 全局层(发现/入口/身份/观测/策略)——预算表里别漏掉全局层成本。

第 8 章 常见面试题(架构设计向)

以下 10 题覆盖数千节点 RKE2/K8s 架构面试的高频考点,每题给出考察意图与答案要点。

Q1:K8s 单集群的官方扩展性上限是多少?生产上你会按多少规划,为什么?

考察点:是否知道上限的前提条件,而非背数字。 答案要点:5000 节点 / 15 万 Pod / 30 万容器 / 1 万 Service / 每节点 100 Pod(推荐)。前提:高规格控制平面、NVMe etcd、低 RTT、官方 SLI/SLO 达标。生产按 60~70%(约 3000~3500 节点)规划,为突发增长、组件退化、故障转移留余量;且各上限互相耦合不能同时打满。

Q2:设计一个 3000 节点的 RKE2 集群,控制平面怎么部署?

考察点:拓扑决策能力。 答案要点:etcd 5 成员独立部署(disable-apiserver 等三参数构造纯 etcd 节点),跨 3 个供电分区/5 个机架,NVMe(fdatasync P99 < 1~2ms 验收),quota 8GB;apiserver 3~5 台 disable-etcd 节点,前端 HAProxy+Keepalived VIP(leastconn + /livez 检查 + 长超时),apiserver 配 goaway-chance 解决长连接不均;9345/6443 都挂 LB。

Q3:为什么 kube-proxy 的 iptables 模式在大规模下会失效?怎么解决?

考察点:对转发面复杂度的理解。 答案要点:Service 规则线性匹配 O(n),5000 Service 时规则 5~10 万条;Endpoints 变化触发全量规则重写,重写耗时随规则数增长,期间转发抖动;conntrack 压力同步放大。解决:IPVS(哈希 O(1) + 增量更新,本仓库 rke2/ 目录即 proxy-mode=ipvs 实测配置),或 Cilium eBPF 完全替代 kube-proxy;同时调大 nf_conntrack_max 并监控。

Q4:一次大版本发布,3000 节点同时拉镜像,镜像仓库被打爆,架构上怎么预防?

考察点:分发链路设计。 答案要点:① Harbor HA(S3 后端)+ 多机房代理缓存副本分层;② 大规模洪峰上 P2P(Dragonfly,dfdaemon 节点互传,回源流量与节点数解耦);③ 发布流程两阶段:先 DaemonSet 预分发镜像,再限速滚动(控制 maxUnavailable);④ 禁用 :latestIfNotPresent;⑤ RKE2 registries.yaml 配置就近 mirror endpoint。

Q5:etcd DB 到了 8GB 上限怎么办?compact 和 defrag 的区别是什么?

考察点:etcd 运维深度。 答案要点:compact 丢弃旧版本 key 释放逻辑空间(apiserver 每 5 分钟周期触发),不缩物理文件;defrag 重建 boltdb 释放磁盘空间,需手动滚动执行(先 follower 后 leader),期间该成员阻塞读写。达到 quota 后集群只读(database space exceeded):应急→手动 compact + defrag + 确认无超限后 etcdctl alarm disarm;预防→quota 提 8GB、控制 Event 留存(event-ttl)、监控 etcd_mvcc_db_total_size 在 50% 告警。

Q6:NodeLocal DNSCache 解决了什么问题?为什么大规模集群几乎是必选?

考察点:DNS 链路的结构性瓶颈。 答案要点:解决三个问题——① UDP DNS 查询占用 conntrack 条目,高密度节点 conntrack 打满的头号来源;② 跨节点解析的延迟与故障面;③ CoreDNS 副本抖动的影响面。机制:DaemonSet 本地缓存(169.254.20.10),向上游走 TCP。注意坑:NetworkPolicy 需放行该 link-local 地址;修改 cluster-dns 需重建 Pod 生效。

Q7:3000 节点集群,apiserver 收到大量 429,你的排查与处置思路?

考察点:控制平面保护机制(inflight 限流 + APF)。 答案要点:先定位来源——apiserver_current_inflight_requests 看读写占用、apiserver_request_total 按 user/verb/resource 维度找出大户(常见:失控控制器 relist 风暴、批量 Job、节点批量恢复心跳);短期处置:确认 max-requests-inflight 保险丝未被盲目调大,用 APF FlowSchema 保障系统组件(kubelet lease、scheduler)队列优先;根治:修复失控客户端(informer 续传、退避)、大 LIST 改分页/watch-cache、必要时横向扩 apiserver 实例。

Q8:单集群到 5000 节点之后怎么走?对比联邦与"管理面 + 多集群"两条路线。

考察点:多集群视野。 答案要点:联邦路线(Karmada):跨集群调度与故障转移能力强,适合"同一业务跨集群弹性"场景,但引入新的控制面与调度语义。管理面路线(Rancher + Fleet):集群间不强耦合,按地域/业务/环境拆分,GitOps 统一下发底座,全局层补齐服务发现(GSLB/mcs-api)、观测汇聚、统一身份。实践中以管理面路线为主,仅在确有跨集群编排诉求时叠加 Karmada。kubefed 已归档,不选型。

Q9:给你一块新采购的服务器做 etcd,如何验证它是否合格?

考察点:是否知道 etcd 的性能判据。 答案要点:核心指标是 fdatasync P99 延迟(官方明确以 99 分位 fsync 延迟作为磁盘适配标准)。用 fio 模拟 etcd 写模式(--rw=write --ioengine=sync --fdatasync=1 --bs=2300),P99 < 1ms 理想、< 2ms 可用、> 10ms 拒绝;同时验证:NVMe 企业级(掉电保护)、独立盘不与业务混部、上线后用 etcd_disk_wal_fsync_duration_seconds_bucket 持续监控 P99,50ms 触发告警。

Q10:设计集群的故障域与打散策略,机架断电这种场景如何保证业务 SLO?

考察点:容量规划与拓扑调度的结合。 答案要点:① 节点注册时打全拓扑标签(zone/rack/hostname,RKE2 node-label);② 工作负载用 topologySpreadConstraints 跨 zone 和 rack 打散,大规模下用 ScheduleAnyway 软约束避免故障潮时大面积 Pending;③ 容量上做 N+1 机架冗余验算——任意一机架(如 125 节点)整体丢失,剩余节点能承接其负载,日常 requests 利用率 ≤ 65%;④ 控制平面组件(etcd 5 成员、CoreDNS、Typha)自身跨机架反亲和 + PDB;⑤ 维护窗口限定单窗口 ≤ 1 机架。


附录 A:本部分关键默认值与推荐值速查

参数默认值数千节点推荐值位置
etcd quota-backend-bytes2GB8GBetcd-arg
etcd 快照12h × 5 份2h × 12 份 + S3etcd-snapshot-*
kubelet max-pods110≤ 128~150kubelet-arg
apiserver inflight400 / 200(mutating)800 / 400(配合 APF)kube-apiserver-arg
goaway-chance00.001kube-apiserver-arg
kube-proxy 模式iptablesipvs / eBPF 替代kube-proxy-arg
nf_conntrack_max内核默认(常 26 万级)≥ 200 万sysctl
CoreDNS 副本2按节点数 8~24 + NodeLocalHelmChartConfig
Calico Typha开,每 ~200 节点 1 副本HelmChartConfig

附录 B:参考检查清单(架构评审用)

  • [ ] 单集群 vs 多集群决策已用 4 问框架评审并留档
  • [ ] etcd 独立部署、5 成员、跨 3 供电分区、NVMe fio 验收报告
  • [ ] LB:leastconn + /livez + client/server 超时 ≥ 300s
  • [ ] cluster-cidr / service-cidr 与企业全部现存及规划网段无冲突(IPAM 登记表)
  • [ ] CNI 选型含状态扇出方案(Typha 或 Cilium)
  • [ ] kube-proxy:ipvs 或 eBPF;conntrack 上限与监控
  • [ ] NodeLocal DNSCache + NetworkPolicy 放行 169.254.20.10
  • [ ] Harbor HA(S3 后端)+ mirror 分层 + P2P 预案 + 两阶段发布
  • [ ] 故障域标签 + topologySpreadConstraints 软约束 + N+1 机架验算
  • [ ] SLI/SLO 验收指标全部接入监控并演练过告警
  • [ ] etcd 快照恢复季度演练记录

下一部分预告:第二部分《安装与配置:从单机到数千节点的 RKE2 工程化落地》将基于本仓库 rke2/ 目录的真实脚本与配置,讲解自动化装机、配置管理、证书轮换与离线部署。