管理裸金属主机上的数据磁盘
使用 MachineInventory.spec.storage 管理已经附加到裸金属主机上的数据磁盘。存储声明属于长期存在的 MachineInventory,而不是临时的 Cluster API Machine,因此当节点被移除后,provider 可以保留文件系统和数据,并在之后复用同一个 inventory。
此功能不会创建、附加、分离、迁移、备份或复制物理磁盘或 SAN LUN。它只管理 spec.storage.volumes[] 中显式列出的设备。所有未列出的设备都会被观测到,但不会被管理。
InitializeIfBlank 可能会格式化磁盘
仅在你已经验证目标 inventory 上确切的稳定设备 ID、确认该设备是可丢弃的空白数据磁盘,并且已独立备份任何重要数据之后,才使用 InitializeIfBlank。切勿从其他主机复制设备 ID,也不要将 /dev/sdX、/dev/vdX、/dev/nvmeXnY 或 /dev/mapper/mpathX 作为持久标识。
目录
可用性与升级边界存储生命周期前提条件第 1 步:验证 inventory 和 observer第 2 步:定义受管 volume第 3 步:渲染并应用原子补丁第 4 步:等待 Prepare第 5 步:分配并验证激活第 6 步:scale down 并复用 inventory第 7 步:释放存储所有权失败操作与重试限制相关文档可用性与升级边界
受管存储需要来自兼容的 Bare Metal Storage 版本的全部三个组件:
- Bare Metal provider,包括其 storage controller 和 fail-closed 的
MachineInventoryadmission webhook。 - 匹配的
elemental-operatorCRD 和 observer API。 - 一个主机 OS 镜像,该镜像会安装并启用
elemental-storage-observer.service以及早期启动阶段的存储集成。
在启用受管存储之前,请从 Alauda 技术支持获取匹配的 base-image 和 base-image-iso。base-image 用于主机重新配置,base-image-iso 用于 SeedImage / live installation。这些镜像是目标版本的受支持配对;不要从其中一个镜像引用推导另一个镜像,也不要用独立构建的镜像替代。
仅在 global 集群上升级 provider 和 elemental-operator,不会在由旧 OS 镜像创建的主机上安装 observer 服务。
- 当
spec.storage仍然不存在或其volumes: []时,现有集群在管理侧升级后可以继续使用非受管存储。此路径不会创建 storage plan,也不会修改磁盘。 - 要在旧主机上启用受管存储,首先使用已批准且具备 observer 能力的镜像重新安装、重置或替换该主机。在添加任何非空存储声明之前,请先确认 observer 服务可用,并且存在新的
status.observedStorage报告。 - 不要向正在运行或已分配的 inventory 添加
spec.storage.volumes[]。只有在 inventory 未分配且所有受管 volume 都处于非活动状态时,才可以更改存储声明。
存储生命周期
删除 Machine 执行的是 Deactivate,不是 Release。因此,正常的 scale-down 会保留 inventory 的存储声明和数据,以便以后复用。
前提条件
- 安装包含 Storage 支持的 Bare Metal provider 版本,并等待其 manager deployment 和 admission webhook 变为 Ready。
- 从 Alauda 技术支持获取匹配的、具备 observer 能力的
base-image和base-image-iso。使用 ISO 镜像安装主机,并配置配对的 base image 以便后续重新配置。 - 在 Prepare 成功之前,将目标
MachineInventory保持在生产池之外。它必须是Ready=True、未分配,并且具有默认 plan Secret。 - 独立备份现有数据。存储保留不等同于应用一致性备份。
- 获取由完全相同的 provider revision 构建的
storagectl二进制文件。storagectl会复用 provider 的规范化、验证和 hash 代码;不要手工计算初始化批准 hash,也不要使用其他版本的二进制文件。 - 提交
InitializeIfBlank的身份必须被授权对虚拟的machineinventories/storageinitialize子资源执行update。纯Adopt声明不需要此额外权限。
设置操作相关变量:
验证管理组件和授权:
在该身份可以提交或更改初始化批准之前,最后一个命令必须返回 yes。仅将此权限授予被授权格式化磁盘的特定管理员用户或 ServiceAccount。
第 1 步:验证 inventory 和 observer
确认该 inventory 可用且当前没有所有者:
allocation 值必须为空或为 Available;所有 owner 值都必须为空。如果 inventory 已分配,请删除拥有它的 CAPI Machine,并等待正常的清理和 Deactivate 流程完成。不要手动移除 owner annotation 或 finalizer。
在主机上验证 observer:
这两个 state 命令都必须成功。在 global 集群上,检查观测水位线和设备事实:
仅使用报告是最新且其 systemRole 为 Data 的设备。
不要选择 system 或 Unknown 设备、Multipath 成员、只读或可移动设备,或具有意外分区表、文件系统、LVM、RAID、LUKS、swap、consumer 或挂载的设备。不要同时选择整盘和其某个分区。
第 2 步:定义受管 volume
创建存储声明。示例中故意使用占位符;请将每个设备 ID、UUID、容量和挂载路径替换为来自同一目标 inventory 的实际信息。删除任何不适用于该主机的 volume。
Storage v2 每个 inventory 最多支持 32 个 volume。第一个版本支持整设备 XFS 或 ext4、通过 Adopt 使用现有的 XFS/ext4 分区,以及整条 multipath 映射。它不会创建分区,也不会管理 LVM、mdraid、LUKS、swap、共享集群文件系统,或多主机读写访问。
required 默认值为 true。可选 volume 仍然会被准备和激活;变化的只是其失败到 Ready 的行为。/var/cpaas 始终必须是必需的。provider 会为受管挂载添加 nodev,nosuid,并使用 allowlist 验证每个额外的挂载选项。
在本地验证该声明:
第 3 步:渲染并应用原子补丁
始终从当前的 live object 开始,以便补丁包含最新的 UID 和 resourceVersion:
对于包含 InitializeIfBlank 的声明,请选择一个严格大于 status.storage.lastConsumedInitializationApprovalCounter 的正整数计数器,并渲染补丁:
生成的 merge patch 会将批准绑定到当前的 Inventory UID、规范化后的 storage hash、计数器和 resourceVersion。对于仅 Adopt 的声明,请省略 --counter。
运行 server-side dry-run,再次检查生成的 spec.storage、device ID、path 和批准,然后再应用:
如果 API 报告 resourceVersion 冲突,请再次获取 inventory,重新生成补丁,重复 server dry-run,然后再应用。切勿从生成的补丁中移除 resourceVersion。
第 4 步:等待 Prepare
监视存储状态:
在 inventory 可以被分配之前,预期结果是:
在此阶段,已初始化的 volume 具有文件系统 UUID,已采用的 volume 保留其原始 UUID,但业务挂载路径尚未激活。在 Prepare 完成之前,不要将该 inventory 加入生产 MachineInventoryPool。
第 5 步:分配并验证激活
将已准备好的 inventory 添加到目标 MachineInventoryPool,然后按照 在裸金属上创建集群 和 管理裸金属节点 中的说明创建或扩展 CAPI machine group。
在重新配置完成后,验证 machine 和 storage 状态:
预期结果为 BaremetalMachine.status.phase=Running、StorageReady=True/AllVolumesReady、MachineInventory.status.storage.phase=Active 和 StorageActive=True/AllRequiredVolumesActive。
在主机上,确认每个源 UUID、文件系统类型、挂载路径和挂载选项。所需的挂载单元必须在 kubelet 之前进入 active 状态:
第 6 步:scale down 并复用 inventory
通过正常的 scale-down 或替换工作流删除拥有该 inventory 的 CAPI Machine。不要删除 MachineInventory,也不要移除其 storage finalizer。
在 drain、clean 和 Deactivate 完成后,预期如下:
当同一个 inventory 再次被分配时,Activate 会复用现有的所有权记录和文件系统 UUID;它不会再次格式化该设备。通用 pool 分配并不保证替换的 Machine 会获得相同的 inventory。如果某个应用必须回到特定 inventory 上的主机本地数据,请先将该 inventory 放在受控的有序 pool 中,或使用专用 pool,并在依赖这些数据之前验证所选的 BaremetalMachine.status.machineInventoryRef。
第 7 步:释放存储所有权
仅当 inventory 未分配且处于非活动状态时,才释放 volume。移除 volume 是非破坏性的:它会删除 Storage v2 所有权和激活元数据,但会保留文件系统 UUID 和数据。
要释放所有 volume,请创建一个显式的空声明:
获取 live inventory,并在不使用初始化计数器的情况下渲染、dry-run 和应用补丁:
等待 phase=Unmanaged、StoragePrepared=True/NoManagedVolumes、空的 appliedVolumes[] 以及 operation=null。在需要时,通过只读挂载验证保留的数据。live inventory 上可能仍会保留 storage finalizer,以便后续对象删除仍按正确的清理顺序执行;不要手动移除它。
失败操作与重试
存储操作采用 fail-closed 策略。缺失、过期、繁忙、过小、降级、从未知来源挂载,或不再匹配其声明 UUID 的必需设备,都会阻止分配或 Machine 就绪。controller 不会自动选择替代磁盘。
在纠正 status.storage.operation.phase 为 Failed 的操作外部原因后,请在保持 volumes[] 不变的情况下递增 spec.storage.retryNonce,并使用 storagectl 渲染新的补丁。retryNonce 会为同一个逻辑操作创建另一次执行尝试。它不会授权首次格式化、绕过预检查,也不会允许不同的存储声明。
不要将重试用作未知或部分变更声明的恢复机制。当 pendingSpecHash 非空,或失败操作报告 mutationState=DurableStateChanged 或 Unknown 时,请保留原始声明并允许同一操作日志收敛。在考虑任何 break-glass finalizer 或所有权操作之前,请联系技术支持。
限制
- 当 inventory 已分配或任何受管 volume 处于活动状态时,
volumes[]不能更改。 - 已准备好的 volume 的
deviceID、文件系统策略/类型或名称不能原地修改。请先释放旧 volume,等待完成,然后再添加替换声明。 - Storage v2 不会在 inventory 之间移动数据。由 inventory 拥有的数据会保留在该 inventory 所标识的物理主机或 LUN 上。
- Multipath 支持仅管理聚合的
wwid:映射。它不会配置 multipath、SAN zoning、LUN masking、fencing,或多主机读写文件系统。 /var/lib/kubelet、/var/lib/containerd、/var/lib/etcd、/etc、/usr、/boot以及其他系统路径都受保护。请使用业务路径,例如/var/cpaas、/data/*、/srv/*或/mnt/*,它们不得与受保护路径重叠。- 不要通过
MachineInventory.spec.storage和 kubeadm/cloud-initdisk_setup、fs_setup、mounts、自定义 systemd 单元或主机脚本同时管理同一个设备或路径。