news 2026/9/23 21:39:03

Rook Stretch Cluster(弹性集群)设计与实战:基于 Arbiter 仲裁节点的双可用区数据保护

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rook Stretch Cluster(弹性集群)设计与实战:基于 Arbiter 仲裁节点的双可用区数据保护
  • 云原生
  • 存储
  • 容器编排
  • 运维

【免费下载链接】rook

Storage Orchestration for Kubernetes

项目地址:https://gitcode.com/gh_mirrors/roo/rook
点击查看免费下载

本文以 design/ceph/ceph-stretch-cluster.md 设计文档为主体骨架,结合当前仓库中 CRD 类型定义、mon 编排源码、Ceph 客户端封装与部署示例,系统讲解 Rook 如何在只有两个可用数据失效域的环境中,借助 Ceph 的 stretch mode 与 arbiter 仲裁 mon,实现任意单个失效域故障后数据仍可读写的高可用能力。读者将掌握 stretch cluster 的架构原理、CephClusterCephBlockPool的完整配置方法、mon 故障切换与存储策略,以及底层 Rook 自动执行的 Ceph 命令序列。

1. 背景:当只有两个可用失效域时

生产环境通常期望拥有三个失效域(failure domain),每个失效域各存一份副本,任意一个失效域整体宕机,数据仍可在其余两个失效域中继续读写。但很多物理环境(如仅有双机房/双可用区的数据中心)只有两个可用于数据复制的失效域。此时要保证"丢失任意一个失效域后,数据在剩余失效域中依然完整可用",就需要特殊的集群形态。

Ceph 通过stretch cluster(弹性集群)+ arbiter mon(仲裁 mon)机制从上游支持了这一场景:数据在两个失效域中各放置多份副本,第三个仅运行单个 mon 的"仲裁区"负责在双区之间出现脑裂时做出裁决,仲裁区不存放数据。Rook 的目标则是:管理员只需在常规 Rook CRD 中声明需求,即可让 Rook 自动完成 stretch cluster 的全部编排与 Ceph 配置,无需手工执行底层命令。

本设计文档定位的目标版本为 Rook 1.5,而当前仓库中该能力已演进为正式功能,见 Documentation/CRDs/Cluster/stretch-cluster.md,并配套了可直接部署的示例清单 deploy/examples/cluster-stretched.yaml。

2. 架构设计

2.1 三个 Zone 的角色划分

基于 Ceph stretch 架构,Rook 要求集群拓扑中存在三个 zone

  • 数据区 A 与 B(data zones):运行所有类型的 Rook Pod。每个数据区运行2 个 mon,原因有二:
    • OSD 只能连接到本 zone 内的 mon,因此数据区内需要不止一个 mon 以提供冗余;
    • Ceph 判定"某个 zone 已宕机"的依据是该 zone 内的 mon 全部不可用,双 mon 确保判定依据可靠。
  • 仲裁区(arbiter zone):仅运行1 个 mon,即"tiebreaker"或"arbiter"(仲裁者),不运行任何其他 Rook 或 Ceph 守护进程

Rook Stretch Cluster 架构:两个数据区各运行 2 个 mon 并存放数据副本,仲裁区仅运行 1 个 tiebreaker mon。

仲裁区在实践中通常只包含单个节点,且该节点往往同时是 Kubernetes 的 master/control-plane 节点;当然仲裁区也可以包含更多节点。stretch cluster 使用的失效域类型最常见是 "zone",但可以配置为其他失效域(如 datacenter、region),只要该标签被 OSD 拓扑所支持。

2.2 延迟约束

分布式系统的关键组件间网络延迟会直接影响可用性。在 stretch cluster 场景下,最关键的延迟瓶颈是 Kubernetes 的 Etcd:K8s 仅支持最高约5ms(往返 10ms)的延迟;而 Ceph 组件对延迟的容忍度更高,Ceph mon 可支持高达700ms 往返的延迟。也就是说,stretch cluster 对网络延迟的要求实际上是由 K8s 侧的 Etcd 决定的,部署前应评估两数据区之间的网络 RTT 是否满足 Etcd 约束。

3. 失效域配置:节点拓扑标签

集群的拓扑结构由管理员在 Rook 之外决定,Rook 只负责检测已添加到节点上的拓扑标签,并据此推导失效域。

若目标失效域为 "zone",需要在节点上添加topology.kubernetes.io/zone标签。OSD 支持的任意拓扑标签(详见 Documentation/CRDs/Cluster/ceph-cluster-crd.md 中关于 OSD 拓扑的说明)都可使用。

最小配置为:每个数据区 2 个节点、仲裁区 1 个节点,共 5 个节点打上标签,例如:

topology.kubernetes.io/zone=a topology.kubernetes.io/zone=a topology.kubernetes.io/zone=b topology.kubernetes.io/zone=b topology.kubernetes.io/zone=arbiter

4. Rook 集群设计:mon 与 zone 的绑定

Rook 侧的核心改动是将 mon 与所需 zone 关联起来,具体约束为:

  • 必须创建5 个 mon,stretch cluster 不支持其他数量的 mon;
  • 1 个 mon 分配给仲裁区;
  • 两个数据区各分配 2 个 mon;
  • 同一 zone 内的两个 mon 之间配置节点反亲和(node antiaffinity),确保它们落在不同节点上。

新的配置位于spec.mon.stretchCluster下,必须列出全部三个 zone 并指明哪个是仲裁区:

mon: count: 5 allowMultiplePerNode: false stretchCluster: # 集群最常见的场景是跨 zone 拉伸,也可以使用 datacenter、region 等其他失效域, # 取值必须是 OSD 使用的标签之一,参考 ceph-cluster-crd 的 osd topology 文档。 failureDomainLabel: topology.kubernetes.io/zone zones: # 列表中必须恰好有三个 zone,且其中一个为 arbiter - name: arbiter arbiter: true - name: a - name: b

上述字段在 CRD 类型定义中有完整对应,见 pkg/apis/ceph.rook.io/v1/types.go:

  • MonSpec通过两条 CEL 校验规则约束合法性:zones数量必须小于等于count;若配置了stretchCluster,则其zones数量必须等于 3("stretchCluster zones must be equal to 3");
  • StretchClusterSpec包含failureDomainLabel(失效域标签,如 zone)、subFailureDomain(zone 内的次级失效域,默认host)、以及zones列表;
  • MonZoneSpec包含namearbiter(是否为仲裁区)、以及可选的volumeClaimTemplate(该 zone 独立的 PVC 模板)。

4.1 判定与 zone 分配

Rook 通过ClusterSpec.IsStretchCluster()判定是否启用 stretch 模式:只要stretchCluster.zones列表非空即视为 stretch cluster;若未列出任何 zone,则不作为 stretch cluster 处理;若 zone 数量不是 3,则视为配置错误,集群不会被配置成功。对应实现见 pkg/apis/ceph.rook.io/v1/cluster.go。

operator 会持续跟踪每个 mon 所属的 zone,zone 分配信息存放在rook-ceph-mon-endpointsConfigMap中,数据结构与带节点亲和(node affinity)的 mon 的主机分配一致。例如三个 zone 名为arbiterzone1zone2时,ConfigMap 内容形如:

data: data: a=10.99.109.200:6789,b=10.98.18.147:6789,c=10.96.86.248:6789,d=10.96.86.249:6789,e=10.96.86.250:6789 mapping: '{"node":{"a":"arbiter","b":"zone1","c":"zone1","d":"zone2","e":"zone2"}}' maxMonId: "4"

mon 的失效域标签取值逻辑在 pkg/operator/ceph/cluster/mon/spec.go 的GetFailureDomainLabel中:stretch 模式下优先取stretchCluster.failureDomainLabel,否则回退到 K8s 标准 zone 标签topology.kubernetes.io/zone。mon Pod 还会被打上zone标签(spec.go),供调度与服务发现使用。

4.2 Mon 故障切换(Mon Failover)

stretch cluster 中 mon 的故障切换遵循同 zone 替换原则:某个 mon 失效后,新 mon 会在原 mon 所在的 zone 内重建,从而始终保持"仲裁区 1 个 + 数据区各 2 个"的拓扑。

源码层面,pkg/operator/ceph/cluster/mon/health.go 的findExtraMonToRemoveFromStretchCluster会依据 stretch 拓扑收缩多余的 mon:仲裁区超过 1 个、或数据区超过 2 个时,多余 mon 会被移除;而 mon.go 的findAvailableZone则负责在故障切换时为 mon 找到仍缺额(如非仲裁区已有 1 个 mon、还差 1 个)的 zone。仲裁 mon 的身份会被记录在c.arbiterMon中,供后续 stretch 配置使用。

4.3 Mon 存储

stretch cluster 的 mon 与普通 Rook 集群一样,既可以用 hostPath 也可以用 PVC 作为后端存储。

以下示例让全部 5 个 mon 共享同一个 PVC 模板:

mon: count: 5 allowMultiplePerNode: false stretchCluster: zones: - name: arbiter arbiter: true - name: a - name: b volumeClaimTemplate: spec: storageClassName: gp2 resources: requests: storage: 10Gi

不同 zone 的 mon 也可能需要不同类型的存储。此时可在zone 级别指定volumeClaimTemplate,它将覆盖默认的全局存储设置。例如让仲裁区使用独立的存储后端:

mon: count: 5 allowMultiplePerNode: false stretchCluster: zones: - name: arbiter arbiter: true volumeClaimTemplate: spec: storageClassName: alternative-storage resources: requests: storage: 10Gi - name: a - name: b volumeClaimTemplate: spec: storageClassName: gp2 resources: requests: storage: 10Gi

实现上,pkg/operator/ceph/cluster/mon/mon.go 会先判断当前 mon 所属 zone 是否带有独立的volumeClaimTemplate,有则优先使用,否则回退到全局模板;PVC 的构建逻辑(AccessModes 固定为 ReadWriteOnce、存储请求缺省值等)见 pkg/operator/ceph/cluster/mon/spec.go。

设计文档遗留问题:是否存在一个 zone 的 mon 使用dataDirHostPath、而其他 zone 使用 PVC 的需求?目前的设计假定所有 mon 要么统一使用 PVC、要么统一使用 hostPath,不支持混用。

5. Rook 自动执行的 Ceph 配置

当管理员通过 CRD 请求 stretch cluster 后,Rook 会在 mon 编排阶段自动完成三件事(对应 pkg/operator/ceph/cluster/mon/mon.go 的configureStretchCluster):

  1. 切换 mon 选举策略为新的 "connectivity" 算法:
mon election default strategy: 3
  1. 为每个 mon 设置所在 zone,使 Ceph 将 mon 关联到正确的失效域(ceph mon set_location <mon> <zone>);
  2. 启用 stretch 模式
$ ceph mon enable_stretch_mode tiebreaker_mon <mon> new_crush_rule <rule> dividing_bucket zone

这些命令在 Rook 源码中有精确对应:

  • pkg/daemon/ceph/client/mon.go 的EnableStretchElectionStrategy执行mon set election_strategy connectivity。值得注意的是:Ceph Squid 及之后版本一旦启用 stretch 模式就拒绝再修改选举策略,因此 Rook 会先读取mon dump判断 stretch 模式是否已启用,未启用才设置选举策略;
  • 同文件的SetMonStretchTiebreaker(mon.go)执行mon enable_stretch_mode <arbiter> <default-stretch-rule> <bucketType>,并对"stretch mode is already engaged"的幂等错误做了兼容处理;SetNewTiebreaker(mon.go)用于故障切换后更换 tiebreaker mon;
  • CreateDefaultStretchCrushRule(mon.go)基于failureDomainsubFailureDomain创建默认的 stretch CRUSH 规则,默认规则会应用到所有池。

启用仲裁(ConfigureArbiter)的完整流程(mon.go)还包含严格的先后依赖:

  1. 检查当前mon dump:若 stretch 模式已启用且 tiebreaker 未变化则直接返回;若 tiebreaker 变了则先set_new_tiebreaker
  2. 轮询等待 CRUSH map 中出现至少两个目标失效域(OSD 完成初始化后),最多等待 2 分钟,超时后 operator 会重新入队再次尝试;
  3. 等待基于默认 stretch 规则创建的内置.mgr就绪(stretch 模式必须在至少一个 stretch 池存在后才能进入);
  4. 最后执行ceph mon enable_stretch_mode设置 tiebreaker mon。

此外,readyToConfigureArbiter 会等待 OSD Pod 全部 Running、校验 CRUSH 权重平衡:若检测到的失效域多于 2 个会直接报错(cannot configure stretch cluster with more than 2 failure domains);CRUSH 权重偏差受 Cephmon_stretch_max_bucket_weight_delta(默认 10%)约束,Ceph v20.2.2(即relaxedStretchCrushWeightCheckVersion,见 mon.go)起允许最多 10% 的权重差异。

6. 数据池配置:副本与 CRUSH 规则

为在 stretch cluster 中获得数据保护,所有池都应采用以下配置,包括 rbd 存储类对应的CephBlockPool、共享文件系统的CephFilesystem、对象存储的CephObjectStore所使用的池:

  • 副本数(Replica):4
  • 失效域(Failure domain):zone
  • 每个 zone 存放 2 份副本:通过replicasPerFailureDomain: 2指定,由一条专用 CRUSH 规则实现
apiVersion: ceph.rook.io/v1 kind: CephBlockPool metadata: name: stretchedreplica namespace: rook-ceph spec: failureDomain: zone replicated: size: 4 replicasPerFailureDomain: 2

replicasPerFailureDomain在 CRD 类型中的定义见 pkg/apis/ceph.rook.io/v1/types.go。Rook 在创建池前会做严格校验(pkg/operator/ceph/pool/validate.go):

  • size必须大于replicasPerFailureDomain
  • replicasPerFailureDomain必须是size因子size % replicasPerFailureDomain == 0)。

配套的单元测试覆盖了这些失败场景(如 size 与 replicasPerFailureDomain 相等、非因子关系等),见 pkg/operator/ceph/pool/validate_test.go。

当前 Ceph 的 stretch cluster 尚不支持纠删码(Erasure Coded)池,这是重要的选型限制。

7. 端到端示例:cluster-stretched.yaml

仓库提供了完整可部署的示例 deploy/examples/cluster-stretched.yaml,其中包含 CephCluster 与内置.mgr池两个资源,核心要点如下:

apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: name: rook-ceph namespace: rook-ceph spec: dataDirHostPath: /var/lib/rook mon: # stretch 模式必须创建 5 个 mon count: 5 allowMultiplePerNode: false stretchCluster: failureDomainLabel: topology.kubernetes.io/zone # subFailureDomain 是次级放置层级,默认 "host":每个 zone 至少需要两个节点; # 若设为 "osd",则同一 zone 内的 OSD 可以落在同一节点上; # 若设为 "rack" 等中间层级,则需在节点上额外打相应标签。 subFailureDomain: host zones: - name: a arbiter: true - name: b - name: c mgr: count: 2 cephVersion: image: quay.io/ceph/ceph:v20.2.4 allowUnsupported: true storage: useAllNodes: true useAllDevices: true deviceFilter: "" placement: # arbiter mon 可以拥有独立的 placement;未指定时与其他 mon 相同。 # 本例为仲裁 mon 添加容忍度,使其可调度到 control-plane 节点(k8s 1.24 及以后使用 # node-role.kubernetes.io/control-plane 污点,更早版本为 node-role.kubernetes.io/master)。 arbiter: tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule # OSD placement 期望只包含非仲裁 zone osd: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - b - c priorityClassNames: mon: system-node-critical osd: system-node-critical mgr: system-cluster-critical disruptionManagement: managePodBudgets: true --- apiVersion: ceph.rook.io/v1 kind: CephBlockPool metadata: name: builtin-mgr namespace: rook-ceph spec: name: .mgr failureDomain: zone replicated: size: 4 requireSafeReplicaSize: true replicasPerFailureDomain: 2 subFailureDomain: host

部署方式与普通 Rook 集群一致:

kubectl create -f deploy/examples/crds.yaml -f deploy/examples/common.yaml -f deploy/examples/operator.yaml kubectl create -f deploy/examples/cluster-stretched.yaml

注意该示例至少需要3 个节点(两个数据区 + 一个仲裁区)。示例中.mgr池也按 stretch 规则创建(size 4、replicasPerFailureDomain 2、failureDomain zone、subFailureDomain host),这正是第 5 节所述"启用 stretch 模式前必须等待基于默认 stretch 规则的内置池就绪"所对应的池,其规格与 Documentation/CRDs/Cluster/stretch-cluster.md 文档示例中的写法一致。

8. 限制与注意事项

综合设计文档与当前实现,使用 stretch cluster 前应明确以下边界:

  1. zone 数量固定为 3,mon 数量固定为 5,其他配置不会生效(CRD 校验直接拒绝,见 types.go);
  2. 纠删码池不受支持,所有池必须使用 4 副本 +replicasPerFailureDomain: 2的复制模式;
  3. 网络延迟受K8s Etcd 5ms(往返 10ms)上限约束,尽管 Ceph mon 可容忍 700ms 往返延迟;
  4. CRUSH map 中检测到超过 2 个数据失效域时会拒绝配置,且各失效域 CRUSH 权重偏差需满足 Ceph 的权重检查(v20.2.2 起允许最多 10% 偏差);
  5. stretch 模式下external mon IDs 配置会被忽略(见 pkg/operator/ceph/cluster/mon/health.go 中的警告日志逻辑);
  6. mon 的存储要么统一使用 PVC、要么统一使用 hostPath,暂不支持混用(设计文档明确标注的开放问题);
  7. OSD 的 placement 应显式限定在非仲裁 zone,仲裁区不应调度任何 OSD 或数据守护进程。

9. 进一步阅读

  • 本文主体设计文档:design/ceph/ceph-stretch-cluster.md
  • 用户文档(当前版本):Documentation/CRDs/Cluster/stretch-cluster.md
  • CRD 参考(OSD 拓扑标签说明):Documentation/CRDs/Cluster/ceph-cluster-crd.md
  • 部署示例:deploy/examples/cluster-stretched.yaml
  • CRD 类型定义:pkg/apis/ceph.rook.io/v1/types.go、pkg/apis/ceph.rook.io/v1/cluster.go
  • mon 编排实现:pkg/operator/ceph/cluster/mon/mon.go、pkg/operator/ceph/cluster/mon/health.go、pkg/operator/ceph/cluster/mon/spec.go
  • Ceph 命令封装:pkg/daemon/ceph/client/mon.go
  • 池校验逻辑:pkg/operator/ceph/pool/validate.go 及对应测试 pkg/operator/ceph/pool/validate_test.go
  • 云原生
  • 存储
  • 容器编排
  • 运维

【免费下载链接】rook

Storage Orchestration for Kubernetes

项目地址:https://gitcode.com/gh_mirrors/roo/rook
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

OpenClaw:跨越AI从聊天到执行的能力鸿沟

1. 从聊天到干活的AI进化论去年我在调试一个智能客服系统时&#xff0c;发现个有趣现象&#xff1a;当用户问"帮我查订单"时&#xff0c;AI能完美回答查询步骤&#xff0c;但当用户直接说"订单号XXXX&#xff0c;查物流"时&#xff0c;系统就卡壳了。这让我…

作者头像 李华
网站建设 2026/9/23 21:32:02

技术博文标题设计规范与输入完整性要求

我无法基于“2021-10-30”这一纯日期型标题生成符合要求的高质量博文。原因如下&#xff1a;该标题不具备可拆解的项目属性&#xff1a;无技术载体&#xff08;如软件、硬件、协议、工具&#xff09;、无明确动作&#xff08;如“搭建”“修复”“迁移”“优化”&#xff09;、…

作者头像 李华
网站建设 2026/9/23 21:31:14

主域控与辅助域控搭建及FSMO角色迁移全流程指南

简介&#xff1a;面向Windows Server 2003环境下需要搭建主/辅助域控并完成域控制器迁移的系统管理员与运维学习者&#xff0c;这份资料将搭建与迁移全过程整理成可直接跟做的操作笔记。内容先从主域控安装向导开始&#xff0c;涵盖DNS全名与NETBIOS名设置、目录还原密码等关键…

作者头像 李华
网站建设 2026/9/23 21:30:59

VMware精简置备虚拟磁盘越删越大?空间回收与VMDK瘦身实战

简介&#xff1a;一份面向VMware虚拟化运维与存储管理人员的实用技术文档&#xff0c;围绕精简置备&#xff08;Thin&#xff09;磁盘在vmfs5文件系统下无法自动回收空间的问题展开&#xff0c;系统梳理了两种成熟的回收方案。该文档为可编辑的docx格式&#xff0c;共1个文件&a…

作者头像 李华
网站建设 2026/9/23 21:29:13

论文写作流程怎么安排?一份从开题到提交的指南

论文写作流程怎么安排&#xff1f;一份从开题到提交的指南 工具不是越多越好&#xff0c;关键是放在正确环节。每位学弟学妹在撰写论文时&#xff0c;都会经历从选题、资料收集、写作到最终提交的各个阶段。在这些环节中&#xff0c;合理利用工具和方法&#xff0c;可以大大提…

作者头像 李华