Rook Ceph 与 Multus 多网络集成设计解析:从 CRD selectors 到 Whereabouts IPAM 的完整实现路径
2026/9/23 5:42:26 网站建设 项目流程
  • 云原生
  • 存储
  • 容器编排
  • 运维

【免费下载链接】rook

Storage Orchestration for Kubernetes

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

本文以 Rook 仓库中的设计文档 design/ceph/multus-network.md 为主线,深入剖析 Rook 如何借助 Multus 为 Ceph 集群引入多宿主网络(multi-homed networking),涵盖 CRD 网络配置的演进、IPAM 方案的取舍(Whereabouts 采纳、DHCP 否决)、各 Ceph 守护进程(mon/OSD/RGW/MDS/CSI)的接入挑战,以及最终在仓库源码中的落地印证。读完本文,你将理解 Rook 中network.provider: multus的完整设计动机、selectors的语义与校验规则、为何最终选择 Whereabouts 作为 IPAM,以及如何用仓库自带的验证工具提前检验你的 Multus 网络环境是否适合承载 Ceph。

说明:该设计文档标题注明"not finalized yet and subject to update"(尚未最终定稿、内容可能更新),属于设计阶段的早期决策记录。但其中的核心结论(采用 whereabouts、否决 DHCP、selectors 双键设计)已在当前仓库的 API 类型定义、CRD 文档与示例配置中落地,本文会一并给出对应源码与配置路径作为佐证。

一、为什么 Ceph 需要 Multus:多宿主网络的动机

文档开篇即声明:多宿主网络本身的收益已在另一份设计文档 design/common/multi-net-multus.md 中探讨过,本文不再复述,只聚焦 Ceph 后端的实现。

真正驱动 Rook 集成 Multus 的原因在于HostNetworking模式的两大缺陷:

  • 暴露全部网络接口:使用HostNetworking会把宿主的所有网络接口(整个网络协议栈)暴露进容器,而 Multus 允许你只挑选需要的那一个接口/网络;
  • 特权容器依赖HostNetworking通常要求特权容器,Multus 方案可以显著减少这种特权需求。

因此,Multus 的目标是在获得与HostNetworking相近的性能收益(绕过软件定义网络的额外延迟与带宽争抢)的同时,提升安全性(Kubernetes 应用与 Ceph 守护进程实现网络隔离)。

理解这一点还需要 Ceph 自身的双网络模型作铺垫:Ceph 守护进程最多可运行在两张独立网络上——public 网络(面向客户端的读写流量,Ceph-CSI、客户端 Pod 均走该网络)与cluster 网络(可选,隔离 OSD 间复制、数据恢复等内部流量)。若未指定 cluster 网络,则内部流量回落到 public 网络。这一模型是后文public/cluster两个 selector 键存在的根本原因。

二、CRD 网络配置的演进:selectors 的双键扩展

2.1 既有 network 属性

设计文档指出,CephCluster的 CRD 中已经存在network属性,其原始形态为:

network: provider: selectors:

2.2 新增的 public / cluster 两个硬编码键

设计文档提出的扩展方案是:在selectors下加入两个硬编码的键:

selectors: public: cluster:

每个 selector 的值对应 Multus 中的一个NetworkAttachmentDefinition(NAD)对象。规则如下:

  • 至少提供一个selector;
  • public:数据守护进程的 public 网络,绑定 Ceph 的public_network配置;
  • cluster:数据守护进程的 cluster 网络,绑定 Ceph 的cluster_network配置;
  • 默认行为:如果只设置了public,则cluster自动取public的值。

2.3 源码中的落地印证

这一设计在当前仓库的 API 类型中已经完整实现,见 pkg/apis/ceph.rook.io/v1/types.go:

  • NetworkSpec.Provider取值由NetworkProviderType枚举约束,合法值为""hostmultus(对应常量NetworkProviderDefaultNetworkProviderHostNetworkProviderMultus);
  • Selectors的类型为map[CephNetworkType]string,而CephNetworkType的定义刻意"允许任意字符串"(注释说明是为了兼容历史遗留的过度指定集群),但常量只有两个:CephNetworkPublic = "public"CephNetworkCluster = "cluster"——正是设计文档中的两个硬编码键;
  • 代码注释中还给出了与设计文档一致的示例:
selectors: public: "default/cluster-fast-net" cluster: "rook-ceph/ceph-backend-net"

即 public 网络可以选用 default 命名空间下、面向 Kubernetes 全局应用的网络,cluster 网络可以选用 rook-ceph 命名空间下、Ceph 专用的后端网络。

校验逻辑:至少一个 selector、格式合法

设计文档要求"至少提供一个 selector",这一约束在 pkg/apis/ceph.rook.io/v1/network.go 的ValidateNetworkSpec中严格执行:

if spec.IsMultus() { if len(spec.Selectors) == 0 { return errors.Errorf("at least one network selector must be specified when using the %q network provider", NetworkProviderMultus) } if _, err := spec.GetNetworkSelection(clusterNamespace, CephNetworkPublic); err != nil { return errors.Wrap(err, "ceph public network selector provided for multus is invalid") } if _, err := spec.GetNetworkSelection(clusterNamespace, CephNetworkCluster); err != nil { return errors.Wrap(err, "ceph cluster network selector provided for multus is invalid") } }

此外还有几点值得注意的细节:

  • GetNetworkSelection(network.go)会通过 NAD 工具库nadutils.ParseNetworkAnnotation解析 selector 字符串;为兼容旧版本用户,若 selector 是单个 JSON 对象(以{开头、}结尾)会自动包装成单元素列表再解析,且每个网络只允许一个 selection,多选会直接报错;
  • CRD 层还叠加了 OpenAPI 的XValidation规则(见 types.go),在 API Server 侧就拦截"使用 multus 但 selectors 为空"与"legacy hostNetwork 与其他 provider 混用"两种非法组合;
  • ValidateNetworkSpecUpdate(network.go)禁止在运行中变更 provider(host 与空值之间的切换除外),保证网络方案的稳定性。

三、Multus 支持的配置面:接口类型与 IPAM 取舍

3.1 接口类型(Interface type)

作为 CNI 规范的一部分,Multus 支持多种接口类型。设计文档指出:Rook 天然支持其中任意一种,因为它们不会从根本上改变 Rook 的工作行为——文档本身并未对接口类型做强制限制。

3.2 IPAM 类型:本设计的核心分歧点

相比接口类型,IPAM(IP 地址分配)才是复杂所在。当时(设计文档撰写时点)主流的三种 IPAM 方案中,有两种被明确判定为"不合适的候选":

IPAM 类型机制被否决的原因
host-local维护本机 IP 分配数据库,仅按主机维度工作不适用于分布式环境——各节点各自分配,必然导致IP 冲突。whereabouts 项目(dougbtv/whereabouts)看起来能修复此问题,但当时并非官方支持
static为容器分配静态 IPv4/IPv6 地址,适合调试无法规模化——需要为所有守护进程预先手工分配 IP
DHCP由 DHCP 服务器按范围分发 IP见下文"被否决的方案"章节

文档同时提示,更详细的分析见文档末尾的"被否决的方案"章节(本文第六节会完整覆盖)。

四、各 Ceph 守护进程的实现挑战

设计文档按守护进程类型逐一拆解了接入 Multus 的网络需求与难点:

4.1 Monitors 与 OSDs

  • Monitors(mon):只需要访问 public 网络;
  • OSDs:需要同时访问 public 与 cluster 两张网络(OSD 既要服务客户端读写,又要承担复制与恢复流量)。

mon 的额外硬性需求有两条:

  • 可预测的 IP 地址(Predictable IP addresses);
  • 整个部署生命周期内 IP 保持不变——IP 必须能在 Pod 重启后幸存(survive a restart)。

这两条需求直接决定了后文对 IPAM 方案的取舍,也是 mon 引导(bootstrap)流程面临的最大难题。

4.2 RGW 实现

  • 只需要访问 public 网络;
  • 但 RGW 使用 Service IP + LoadBalancer 对外暴露,需要格外小心——多网络环境下 Service IP 与 Multus 附加网络之间的交互是设计难点。

4.3 MDS / RBD-MIRROR / NFS

  • 都只需要访问 public 网络;
  • 由于它们不使用 Service IP,无需特殊处理

4.4 CSI Pods:一个必须修复的已知问题

设计文档引用了一个 Rook 的已知问题(对应 GitHub issue 8085),核心现象是:

当使用 Ceph CSI 挂载了 CephFS/RBD 卷的 Pod 运行期间,如果 CSI CephFS/RBD 插件 Pod 被重启或终止(例如重启或删除其 DaemonSet),则该卷上的所有操作都会卡死,即使随后重启 CSI Pod 也无法恢复。唯一的临时解决办法是重启承载 CSI 插件 Pod 的节点。

该问题的根源在于:挂载点(mount)与 CSI 插件进程所在网络命名空间绑定,CSI 插件被强杀后,挂载点的网络上下文随之失效。

为此,设计文档提出的缓解方案是:当部署配置了 multus 网络的 CephCluster 时,为所有将运行 CSI 插件 Pod 的节点,在宿主网络命名空间(host network namespace)中附加一个 multus 网络接口。这样 CSI Pod 可以继续使用宿主网络运行,同时仍然能够访问 Ceph 的 public multus 网络。

具体实现设计为:新增一个 DaemonSet 来"拥有"所有 CephFS 挂载点及 RBD 映射设备对应的网络,而现有的csi-{cephfs,rbd}pluginDaemonSet 保持不动。通过把网络"所有权"从 CSI 插件 Pod 中剥离出来,避免插件重启导致挂载失联。

五、已采纳的方案:Whereabouts IPAM

经过调研,Rook 团队最终决定采用 whereabouts 作为 IPAM 插件。它的定位是:

一个集群级(cluster-wide)的 IP 地址管理 CNI 插件。如果你喜欢 host-local 的工作方式,但需要它跨越集群中的所有节点(host-local 只知道给本机 Pod 分配 IP),那么 whereabouts 正是你要找的工具。

关键能力:

  • 支持 IPv4 与 IPv6 双栈寻址;
  • 跨集群静态 IP 地址分配
  • 分配的IP 在部署重启后依然存活(满足 mon 的需求);
  • 分配动作由 whereabouts 完成,而非 Rook——Rook 无需自己维护 IP 数据库。

不过设计文档也明确标注了一个/!\警告:

唯一尚未解决的问题是:如何为即将启动的 monitor 预测 IP?我们可能需要小幅重构 mon 的引导方式,使其不再需要预先知道 IP。

这是当时设计状态下唯一悬而未决的技术债,也是 mon 引导流程后续演进的重点方向。

从当前仓库的最终状态看,whereabouts 已被官方文档确认为推荐方案:Documentation/CRDs/Cluster/network-providers.md 中的推荐 NAD 示例即使用"type": "whereabouts"配合range指定地址段(详见本文第七节),并注明"whereabouts 确保每个 Pod 获得集群内唯一的 IP,无需 DHCP 服务器"。

六、被否决的方案:DHCP 及其变体

文档保留了两个被否决的方案,目的是可追溯性与知识沉淀

6.1 IPAM 类型 'DHCP'

在该场景下,由 DHCP 服务器按给定范围向 Pod 分发 IP 地址。

优点:

  • Pod 在物理网络接口上获得专用 IP;
  • Ceph 侧无需任何改动——Rook 通过NetworkAttachmentDefinition探测 CIDR,然后填充 Ceph 的public_networkcluster_network配置即可。

缺点:

  • IP 分配不可预测——在 Pod 启动完成前无法得知 IP,因此探测必须发生在 monitor 容器运行内部(类似于今天 OSD 代码的做法);
  • 需要对 mon 引导代码做大幅改动
  • 需要在集群的每个节点上部署DHCP 守护进程,这被证明是麻烦的来源。

假设走这条路,mon 的引导流程需要重构成如下步骤:

  1. 让第一个 monitor 基于某个接口自行发现自己的 IP
  2. 第一个 mon 引导完成后,将其 IP 注册进一个ConfigMap,同时填充 clusterInfo;
  3. 启动第二个 mon,从 clusterInfo 中查找 initial member(即使操作中途崩溃也不用担心——每次启动时都会基于该 ConfigMap 执行CreateOrLoadClusterInfo());
  4. 以此类推,逐个启动剩余 monitor。

文档还在该方案旁标注了TBT(有待验证):Pod 重启后能否保持相同 IP。

6.2 IPAM 类型 'DHCP' + Service IP

这是一个"纯理论"的变体:使用带 DHCP 的 IPAM 并结合 Service IP。它要求与Kube-proxy 交互,而当时(乃至现在)并不存在这样的特性。即便存在,团队已经决定不走 DHCP 路线,因此该方案不再具有现实意义。

否决结论归纳:DHCP 系列方案被否的核心原因是 IP 不可预测 + 引导流程重构成本高 + 每节点 DHCP 守护进程运维负担大。这从反面印证了 mon"可预测且持久 IP"需求对方案选择的决定性影响。

七、从设计到落地:仓库中的实现与配套工具

设计文档描述的蓝图最终在仓库中体现为 API 类型、示例配置、官方文档与验证工具四个层面。

7.1 完整的 CephCluster Multus 示例

仓库中的 deploy/examples/cluster-multus-test.yaml 提供了一个可直接对照的最小化示例,其网络段为:

apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: name: my-cluster namespace: rook-ceph # namespace:cluster spec: # ... 省略其他配置 ... network: provider: multus selectors: public: public-net cluster: cluster-net

注意这里 selector 的值直接使用 NAD 名称(public-net/cluster-net),未带命名空间前缀——Rook 会自动以 CephCluster 所在的命名空间(rook-ceph)解析,即等价于rook-ceph/public-net。若 NAD 位于其他命名空间,则需要写成namespace/name的形式。

7.2 NAD 定义与 addressRanges 兜底

Documentation/CRDs/Cluster/network-providers.md 给出了推荐的 NAD 定义模板(macvlan + whereabouts):

apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: ceph-multus-net spec: config: '{ "cniVersion": "0.3.1", "type": "macvlan", "master": "eth0", "mode": "bridge", "ipam": { "type": "whereabouts", "range": "192.168.200.0/24" } }'

该文档还强调了几条与设计文档呼应的实操要点:

  • master必须匹配各宿主上要使用的网络接口,且所有宿主必须一致
  • CNI 类型推荐 macvlan——相比传统 Linux bridge 配置,CPU 与内存开销更低;
  • IPAM 推荐 whereabouts——确保 Pod 获得集群内唯一 IP;若网络中已有 DHCP 服务器,务必确保 IP 范围不与其重叠;
  • selectorsaddressRanges配合:Rook 会尝试自动探测所选网络的 CIDR,但该过程不保证成功,且每次 CephCluster reconcile 都会获取一次新的网络租约。若自动探测失败、探测结果不正确、或底层网络不支持复用旧 IP,则应在network.addressRanges中手工指定 CIDR:
network: provider: multus selectors: public: default/kube-multus-net cluster: rook-ceph/ceph-multus-net # addressRanges: # public: # - "192.168.100.0/24" # - "192.168.101.0/24" # cluster: # - "192.168.200.0/24"

这一兜底机制的合法性同样由 network.go 的校验保障:addressRanges只能配合hostmultusprovider 使用,且 multus 下指定 public/cluster 地址范围的前提是存在对应的 selector;每个 CIDR 都会经过net.ParseCIDR严格校验。

此外,官方文档也如实记录了当前 Multus 方案的已知限制:依赖 Kubernetes Service IP 的守护进程(mon、mgr、RGW)并不会直接监听selectors指定的 NAD,而是监听默认网络,NAD 仅作为附加网络挂载到容器中供其通信——该问题的修复工作正在进行中(multus-service 项目),何时支持尚不明确。这与设计文档中 RGW"使用 Service IP 需小心"的预警完全对应。

7.3 Multus 配置验证工具

Multus 网络环境是否真正适合承载 Ceph,官方文档强烈建议在安装 CephCluster 之前先行验证(network-providers.md)。验证工具的 CLI 入口在 cmd/rook/userfacing/multus/multus.go 中注册,核心实现位于 pkg/daemon/multus 目录(含validation.goresources.gostatemachine.gotemplates.goconfig.go等)。

使用步骤:

  1. 进入 Rook operator Pod:

    kubectl --namespace rook-ceph exec -it deploy/rook-ceph-operator -- bash
  2. 查看验证工具帮助:

    rook multus validation run --help
  3. 使用配置文件做高级配置(可生成带注释说明的模板):

    rook multus validation config --help
  4. 运行验证;若失败,工具会给出可能的原因排查建议,并请求相关日志与输出用于定位问题。

从源码看,该验证工具是一个有状态的状态机(statemachine.go 配合validation.go中定义的一系列状态),会在目标节点上拉起多类探针 Pod 来模拟 Ceph 守护进程的网络拓扑:

  • Web Server Pod:同时挂载 public 与 cluster 网络(模拟 OSD 的落点),并对外提供地址信息;
  • Image Pull DaemonSet:预拉取镜像,同时探测 DaemonSet 在各节点的调度能力;
  • Host Checker DaemonSet:验证宿主能否路由到 public 网络(对应设计文档中"host 到 Pod"方向的路由要求);
  • Client DaemonSet:模拟两类 Ceph 守护进程——OSD(同时连接 public + cluster 网络)与非 OSD(仅连接 public 网络),每节点数量由配置的osdsPerNode/otherDaemonsPerNode决定。

配置项定义见 pkg/daemon/multus/config.go,其中PublicNetwork/ClusterNetwork分别对应设计文档的 public/cluster 选择器,默认每节点 3 个 OSD、16 个非 OSD 守护进程、资源超时 3 分钟、网络抖动阈值 30 秒。验证结果会附带针对性的调试建议(如 macvlan 对交换机 MAC 学习数量的限制、Promiscuous 模式、防火墙策略等),参见validation.go中的unableToProvideAddressSuggestions等常量。

工具还支持hostCheckOnly模式(只做宿主侧检查)以及 OpenShift 等安全受限环境的专用示例 deploy/examples/multus-validation-test-openshift.yaml。

7.4 端到端测试脚本

仓库 tests/scripts/multus 目录下提供了完整的端到端验证脚本族,与设计文档的各个关注点一一对应:

  • setup-multus.sh:搭建 Multus 测试环境;
  • test-110-cli.sh:验证rook multus validationCLI;
  • test-200-stretch-label-nodes.sh 与 test-200-stretch-taint-nodes.sh:stretch 集群场景的节点标签/污点准备;
  • test-210-stretch-overlap.sh:验证仅 public / 仅 cluster / public+cluster 分离等网络配置组合(对应设计文档中"只设 public 时 cluster 继承 public"及双网络并存的行为);
  • test-220-stretch-pub-and-cluster.sh、test-230-stretch-pub-only.sh、test-240-stretch-cluster-only.sh:分别覆盖"双网络""仅 public""仅 cluster"三种部署形态。

这些脚本从测试角度印证了设计文档中"至少提供一个 selector"以及"public 与 cluster 可独立配置"的语义边界。

八、总结:设计决策回顾与现状对照

设计议题设计文档结论仓库现状印证
网络模型Ceph 双网络(public/cluster),selectors 双键,cluster 可回退到 publicCephNetworkType仅 public/cluster 两常量,示例配置cluster-multus-test.yaml
IPAM 主方案采纳 whereabouts(集群级静态 IP、重启存活、由 whereabouts 分配)官方文档 NAD 模板默认 whereabouts,并推荐之
IPAM 否决host-local(IP 冲突)、static(不可扩展)、DHCP(IP 不可预测 + 引导重构 + 每节点 DHCP 守护进程)官方文档无 DHCP 推荐场景,仅作为示例之一保留
mon 特殊需求可预测、持久 IP;引导流程或需重构当前 mon 仍属已知限制(依赖 Service IP 的守护进程不直接监听 NAD)
CSI 问题新增 DaemonSet 拥有挂载网络,CSI 插件 DaemonSet 不动设计层面落地于 CRD/网络附加逻辑(详见 pkg/operator/k8sutil/network.go)
验证手段无(设计阶段)官方提供rook multus validation工具与完整测试脚本族

整体来看,Rook 的 Multus 集成遵循了"收益明确、取舍清晰、先验证后上线"的工程路线:通过双 selector 的设计把 Ceph 的双网络模型平移到 Kubernetes 多网络模型上,通过 whereabouts 解决 IP 分配的集群级一致性与持久性问题,并用专门的验证工具把"网络环境是否合格"这一风险前置到 CephCluster 安装之前。对于计划在生产环境使用 Multus 承载 Ceph 的读者,建议按本文第七节的流程先运行验证工具,再依据 Documentation/CRDs/Cluster/network-providers.md 中的 macvlan + whereabouts 模板设计 NAD,最后在selectors无法可靠自动探测 CIDR 时使用addressRanges手工兜底。

  • 云原生
  • 存储
  • 容器编排
  • 运维

【免费下载链接】rook

Storage Orchestration for Kubernetes

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

相关推荐

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询