多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

OpenEBS LocalPV-ZFS 卷迁移(PV Migration)设计解析:从节点替换到池级拓扑标签的完整方案

OpenEBS LocalPV-ZFS 卷迁移(PV Migration)设计解析:从节点替换到池级拓扑标签的完整方案 云原生CLI【免费下载链接】openebsA popular widely deployed Open Source Container Native Storage platform for Stateful Persistent Applications on Kubernetes.项目地址https://gitcode.com/gh_mirrors/op/openebs点击查看免费下载导读本文基于 designs/local-pv/zfs/pv-migration.md 设计文档完整梳理 OpenEBS LocalPV-ZFS CSI Driver 在节点替换场景下的卷迁移方案当管理员将磁盘移至新节点并重新导入 ZFS 池时如何让应用 Pod 与持久化卷自动跟随调度到新节点。读完本文你将掌握问题根源PV 亲和性绑定节点名、现有openebs.io/nodeid方案的局限、基于guid.zfs.openebs.io/pool-guid池级拓扑标签的新提案以及 Migrator 如何同步更新 ZFSVolume 对象中的 PoolName 与 OwnerNodeID。背景LocalPV 的亲和性困境与节点替换难题LocalPV本地持久卷的核心特点是数据只存在于其被调度的那个节点上因此 OpenEBS 的本地 PV 驱动必须在 PV 对象上设置节点亲和性affinity让 k8s 调度器始终把使用该卷的 Pod 调度到数据所在节点。LocalPV-ZFS 驱动使用**节点名nodename**来设置亲和性。这在节点替换node replacement场景下会引发严重问题原节点如node-1宕机或退役管理员将其磁盘物理迁移到新节点新节点拥有不同的主机名即使磁盘和 ZFS 池已经就位PV 上的亲和性仍然指向旧节点名k8s 调度器找不到与新节点匹配的亲和性标签Pod 永远无法被调度到新节点上。也就是说数据已经搬过去了但调度器看不见新节点应用无法恢复。现有解决方案openebs.io/nodeid标签及其局限在引入本文的设计之前社区已有的解决办法是依赖节点上的openebs.io/nodeid标签管理员在替换节点时手动给新节点打上与旧节点相同的openebs.io/nodeid标签k8s 调度器看到 PV 亲和性匹配后会自动把旧 Pod 调度到这个新节点。这个方案的局限非常明显一个节点对于同一个标签键只能有一个值。对于集群中的任何已有节点openebs.io/nodeid早就被设置了它同时也是驱动为常驻该节点的卷提供拓扑能力所依赖的键如果为了承接迁移卷而把某已有节点的openebs.io/nodeid改成新值那么原本运行在该节点上的 Pod 反而会因为亲和性不匹配而无法再被调度回来因此这种方案只能用于替换成一个全新节点的场景无法把卷迁移到集群中任何一个已存在的节点。此外该方案还要求管理员手工维护标签容易遗漏且官方文档zfs-localpv 的 FAQ只覆盖了旧节点不可访问这一种场景。新提案以 ZFS 池为单位的拓扑键Keys Per ZPOOL核心思想把拓扑键从节点改为池设计文档提出的核心思路是为每一个 ZFS 池ZPOOL分配一个专属的拓扑键由 LocalPV-ZFS 驱动在池所在节点上自动设置对应标签格式为guid.zfs.openebs.io/pool-guidtrue其中pool-guid是 ZFS 池的全局唯一标识GUID即zpool get guid的输出。这样拓扑键与池绑定而不是与节点绑定池可以自由地在任意节点之间迁移——池在哪标签就在哪亲和性就跟着走。设计同时假设管理员单个节点上配置的 ZFS 池数量不会很多因此节点上不会累积过多此类标签。为什么用 Pool GUID 而不是 Pool 名称设计文档明确建议使用池的 GUID 而非池名。原因在于池名在集群内被要求全局一致LocalPV-ZFS 要求同名池在所有节点上保持一致因此当池迁移到已有节点时往往必须改名详见下文 Migrator 一节以名称作为键会在迁移过程中失效GUID 在磁盘层面唯一且随磁盘迁移zpool import后 GUID 不变天然适合作为持久、可迁移的标识。标签示例假设node-1上存在两个池pool1的 GUID 为14820954593456176137pool2的 GUID 为16291571091328403547则节点标签如下$ kubectl get node node-1 --show-labels NAME STATUS ROLES AGE VERSION LABELS node-1 Ready worker 351d v1.17.4 beta.kubernetes.io/archamd64,beta.kubernetes.io/oslinux,kubernetes.io/archamd64,kubernetes.io/hostnamenode-1,kubernetes.io/oslinux,node-role.kubernetes.io/workertrue,openebs.io/nodeidnode1,openebs.io/nodenamenode-1,guid.zfs.openebs.io/14820954593456176137true,guid.zfs.openebs.io/16291571091328403547true可以看到每个池对应一个独立的guid.zfs.openebs.io/pool-guidtrue标签与其他已有拓扑键openebs.io/nodeid、openebs.io/nodename并存。Migrator修正 ZFSVolume 对象的池名与归属节点为什么需要 MigratorLocalPV-ZFS 要求 ZFS 池名在集群所有节点上保持一致。当把池迁移到已有节点时若目标节点上已经存在同名池则必须以不同名称导入该池例如zpool import newguid newname。此时池名发生了变化但 PV 和 ZFSVolume 对象中记录的信息仍是旧的。设计文档特别强调不能通过编辑 PV 的 volumeAttributes 来写入新的池名因为 volumeAttributes 是不可变immutable字段。因此必须有一个独立的 Migrator 工作流来修正存储卷的元数据。Migrator 的工作内容Migrator 会遍历目标节点上所有池的所有卷找到与之对应的 ZFSVolume 自定义资源并更新两个关键字段PoolName更新为迁移后实际的池名OwnerNodeID更新为卷现在所在的节点标识。在仓库的代码实现中可以确认 ZFSVolume CR 的 spec 结构正是由这两个字段承载卷的归属信息ZfsVolSpec中的poolName注释为 Zpool hosting the volume与ownerNodeID注释为 Node having the zpool which hosts the volume对应实现见 plugin/src/cli_utils/localpv/zfs/volume/types.rs。迁移后用户可以借助该字段验证卷的新归属。迁移工作流总览完整流程可概括为管理员部署好所有节点并在每个节点上创建 ZFS 池LocalPV-ZFS CSI 驱动扫描节点上的全部池为每个池设置guid.zfs.openebs.io/pool-guidtrue标签迁移磁盘并导入池驱动比对标签与实际池位置从池已不在的节点上移除标签在池现在所在的节点上打上标签Migrator 更新所有相关 ZFSVolume 对象的 PoolName 与 OwnerNodeIDk8s 调度器看到新标签将使用该池的 Pod 调度到新节点。下图展示了该迁移工作流的整体步骤初始状态 → 替换节点 → 移动磁盘并导入池 → k8s 自动调度 Pod两种迁移场景的具体操作步骤场景一目标节点是全新节点fresh node这是最简单的情形磁盘迁移后无需考虑池名冲突在新节点上直接导入池zpool import然后重启该节点上的 LocalPV-ZFS 节点 DaemonSet让驱动感知新池并设置对应节点拓扑标签驱动发现guid.zfs.openebs.io/14820954593456176137true标签从池已不在的节点上移除该标签驱动在新节点上设置guid.zfs.openebs.io/14820954593456176137true标签Migrator 查找所有 ZFSVolume 资源将其 OwnerNodeID 更新为新节点 IDk8s 调度器看到新标签后将相关 Pod 调度到新节点迁移完成。由于池名未变此场景中 Migrator 只需要更新 OwnerNodeID无需修改 PoolName。场景二目标节点是已有节点且存在同名池这是设计文档重点覆盖的场景需要额外处理池名冲突在目标节点上以不同名称导入池此时池名与源节点不同然后重启该节点上的 LocalPV-ZFS 节点 DaemonSet让驱动感知新池并设置对应节点拓扑标签驱动发现guid.zfs.openebs.io/14820954593456176137true标签从池已不在的节点上移除该标签驱动在目标节点上设置guid.zfs.openebs.io/14820954593456176137true标签Migrator 查找所有 ZFSVolume 资源同时更新 PoolName 和 OwnerNodeID为迁移后的实际值k8s 调度器看到新标签后将相关 Pod 调度到新节点迁移完成。这个场景正是池级拓扑键 Migrator组合的价值所在既有节点不必改动openebs.io/nodeid标签不影响该节点上原有卷的调度Migrator 通过修正 CR 元数据弥补了 PV volumeAttributes 不可变的限制。升级兼容新旧拓扑键并存引入新特性后LocalPV-ZFS 驱动将开始使用新的拓扑键guid.zfs.openebs.io/pool-guidtrue设置 PV 亲和性。为了保证集群升级无缝、旧卷与旧 Pod 不受影响设计文档要求节点上继续保留旧标签已有卷依赖它们节点驱动继续支持旧的拓扑键与新的guid.zfs.openebs.io/pool-guidtrue并存即以下拓扑键都需被支持openebs.io/nodenameopenebs.io/nodeid其中openebs.io/nodename的值应与节点名nodename保持一致openebs.io/nodeid若用户已手动打过此标签则应保持该值不变若未设置则默认取节点名。这样升级过程中新旧卷可同时正常调度迁移能力逐步启用而不会破坏存量应用。实现计划与测试计划分阶段实现Phase 1实现迁移到全新节点的替换场景不依赖 Migrator 改名逻辑Phase 2实现迁移到已有节点的替换场景实现 Migrator。这种分阶段方式先把最简单的路径跑通验证拓扑标签机制本身再引入复杂的池改名与 CR 元数据修正逻辑降低一次性引入的风险。测试要点设计文档给出的测试计划覆盖以下关键行为将磁盘迁移到新节点并重启该节点上已运行的 ZFS 驱动节点 DaemonSet应用 Pod 应迁移到新节点将磁盘迁移到任何已有节点并重启该节点的节点 DaemonSet使用该 ZFS 池的 Pod 应迁移到目标节点节点上有 2 个池时只迁移其中 1 个池应只有使用该池的 Pod 迁移到其他节点验证标签的池级粒度验证池所在节点的标签是否正确设置guid.zfs.openebs.io/pool-guidtrue验证迁移完成后 ZFSVolume CR 中的 OwnerNodeID 与 ZFS Pool 信息已更新验证快照 CRZFSSnapshot中的 OwnerNodeID 与 ZFS Pool 信息同样已更新验证 PV 亲和性中包含guid.zfs.openebs.io/pool-guid键。其中2 个池只迁 1 个池的用例直观验证了池级拓扑键相比节点级标签的隔离能力。GA 标准当上述测试用例全部纳入 e2e 流水线并持续稳定通过后该特性即可发布为 GA。源码佐证CR 结构与可观测手段在当前仓库中可以找到与本文设计直接对应的实现证据ZFSVolume CRspec 包含poolName卷所在池与ownerNodeID承载该池的节点字段是 Migrator 要更新的两个目标见 plugin/src/cli_utils/localpv/zfs/volume/types.rsZFSNode CR每个节点通过Pools列表向集群通告其池信息每个池携带name、uuid、free、used字段——uuid正是池级拓扑键guid.zfs.openebs.io/pool-guid中 GUID 的来源见 plugin/src/cli_utils/localpv/zfs/node/types.rs可观测手段OpenEBS 的 kubectl 插件支持openebs get zfs volumes、openebs get zfs zpools等命令查看 ZFSVolume 与 ZFS 池资源支持按 node-id 过滤迁移前后可通过这些命令核对 PoolName 与节点归属入口见 plugin/src/cli_utils/localpv/zfs/mod.rs。支持性工具supportability dump还会将 ZFSNode、ZFSVolume、ZFSSnapshot、ZFSRestore、ZFSBackup 等资源导出为 yaml便于迁移后的审计与排障见 plugin/src/cli_utils/localpv/zfs/supportability.rs。小结LocalPV-ZFS 的卷迁移设计本质上把节点拓扑重构成了池拓扑通过guid.zfs.openebs.io/pool-guidtrue标签让亲和性跟随磁盘与 ZFS 池移动配合 Migrator 修正 ZFSVolume 的 PoolName 与 OwnerNodeID从而同时支持迁移到新节点与迁移到已有节点两类场景并保证升级期间新旧拓扑键并存、存量卷不受影响。相关设计文档还收录于 designs/local-pv/zfs/pv-migration.md同目录下的 designs/local-pv/zfs/poolpattern.md 则从池选择与调度角度进一步探讨了池级能力如按池根匹配、容量感知调度可作为延伸阅读。赞分享云原生CLI【免费下载链接】openebsA popular widely deployed Open Source Container Native Storage platform for Stateful Persistent Applications on Kubernetes.项目地址https://gitcode.com/gh_mirrors/op/openebs点击查看免费下载相关推荐解决Kubernetes存储痛点OpenEBS LocalPV-ZFS跨节点迁移全指南解决Kubernetes存储痛点OpenEBS LocalPV ZFS跨节点迁移全指南 你是否遇到过Kubernetes节点故障导致LocalPV存储卷无法访云原生CLIOLMo 项目中的 Efficiency Pentathlon 推理效率基准评测指南安装、评测场景、stdio 协议与效率指标全解析OLMo 项目中的 Efficiency Pentathlon 推理效率基准评测指南安装、评测场景、stdio 协议与效率指标全解析 导读 本文以 OLMo云原生CLIvue-material-admin性能优化技巧让你的管理系统运行如飞vue material admin性能优化技巧让你的管理系统运行如飞 vue material admin是基于Vue3、Vuetify、TypeScrip上一篇OpenReplay 网络代理库openreplay/network-proxy完全指南拦截 fetch、XHR 与 Beacon 实现网络请求追踪下一篇RouterSploit 实战使用 ftp_default_creds 模块对 Netsys 路由器 FTP 服务执行默认凭据字典攻击创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表