RAID 配置

概述

Ironic 支持裸机节点的 RAID 配置。它允许操作员通过 OpenStackClient CLI 或 REST API 指定所需的 RAID 配置。所需的 RAID 配置将在手动清理期间应用于裸机。

此处描述的示例使用 OpenStackClient CLI;请参阅 REST API 参考,了解其相应的 REST API 请求。

先决条件

裸机节点需要使用支持 RAID 配置的硬件类型。RAID 接口可以通过带内或带外方式实现 RAID 配置。软件 RAID 在所有硬件上都受支持,但有一些注意事项 - 请参阅 软件 RAID 以了解详细信息。

带内 RAID 配置(包括软件 RAID)使用 Ironic Python Agent ramdisk 完成。对于带内硬件 RAID 配置,应将支持 RAID 的硬件管理器与 ramdisk 捆绑在一起。

可以使用 CLI 命令 baremetal node validate <node> 找到节点是否支持 RAID 配置。带内 RAID 通常由 agent RAID 接口实现。

支持 RAID 配置的构建代理 ramdisk

为了进行带内硬件 RAID 配置,Ironic 需要一个与 ramdisk 捆绑在一起的硬件管理器,该硬件管理器支持针对您的硬件的 RAID 配置。例如,对于 HPE Proliant 服务器,应使用 Proliant 硬件管理器 DIB 支持

注意

对于带内软件 RAID,代理 ramdisk 不需要与硬件管理器捆绑在一起,因为 Ironic Python Agent 中的通用硬件管理器已经提供了(基本的)软件 RAID 支持。

RAID 配置 JSON 格式

所需的 RAID 配置和当前的 RAID 配置以 JSON 格式表示。

目标 RAID 配置

这是裸机节点上所需的 RAID 配置。使用 OpenStackClient CLI(或 REST API),操作员设置节点的 target_raid_config 字段。目标 RAID 配置将在手动清理期间应用。

目标 RAID 配置是一个字典,其键为 logical_diskslogical_disks 的值是 JSON 字典列表。它看起来像

{
  "logical_disks": [
    {<desired properties of logical disk 1>},
    {<desired properties of logical disk 2>},
    ...
  ]
}

如果 target_raid_config 是一个空字典,则它将取消设置 target_raid_config 的值(如果该值以前使用先前的 RAID 配置设置在节点上)。

每个逻辑磁盘的字典包含硬件类型支持的逻辑磁盘的所需属性。可以通过以下方式发现这些属性

baremetal driver raid property list <driver name>

必需属性

必须为每个逻辑磁盘指定这些属性,并且没有默认值

  • size_gb - 要创建的逻辑磁盘的大小(以 GiB 为单位)。如果希望逻辑磁盘使用所有剩余可用空间,可以指定 MAX。仅当指定了后端物理磁盘时才能使用此选项(如下所示)。

  • raid_level - 逻辑磁盘的 RAID 等级。Ironic 支持以下 RAID 等级:0、1、2、5、6、1+0、5+0、6+0。

可选属性

这些属性具有默认值,并且可以覆盖在任何逻辑磁盘的规范中。这些选项都不受软件 RAID 的支持。

  • volume_name - 卷的名称。应在节点内唯一。如果未指定,则卷名称将自动生成。

  • is_root_volume - 如果这是根卷,则设置为 true。最多只能有一个逻辑磁盘将其设置为 true;其他逻辑磁盘必须将其设置为 false。如果 RAID 接口能够检索到它,则将保存 root device hint。默认值为 false

后端物理磁盘提示

为每个逻辑磁盘指定这些提示,以便 Ironic 找到用于 RAID 配置的所需磁盘。这是与机器无关的信息。这适用于操作员不想为每个裸机节点提供单独详细信息的情况。这些选项都不受软件 RAID 的支持。

  • share_physical_disks - 如果此逻辑磁盘可以与其他逻辑磁盘共享物理磁盘,则设置为 true。默认值为 false,软件 RAID 除外,软件 RAID 始终共享磁盘。

  • disk_type - hddssd。如果未指定此项,则磁盘类型将不会是查找后端物理磁盘的标准。

  • interface_type - satascsisas。如果未指定此项,则接口类型将不会是查找后端物理磁盘的标准。

  • number_of_physical_disks - 整数,用于逻辑磁盘的磁盘数量。默认值为特定 RAID 等级所需的磁盘的最小数量,软件 RAID 除外,软件 RAID 始终跨越所有磁盘。

后端物理磁盘

这些是实际的与机器相关的信息。这适用于操作员希望基于更广泛的属性(例如 S.M.A.R.T. 状态、物理位置)使用第三方工具自动选择物理磁盘的环境。这些属性的值取决于硬件。

  • controller - RAID 接口读取的控制器的名称。为了通过 Ironic Python Agent 触发软件 RAID 的设置,此属性的值需要设置为 software

  • physical_disks - RAID 接口读取的要用作物理磁盘的列表。

    对于软件 RAID,physical_disks 是与 指定部署的磁盘(根设备提示) 中使用的格式相同的设备提示列表。提供的提示数量必须与预期的后端设备数量匹配(如果需要,重复相同的提示)。

注意

如果同时指定了“后端物理磁盘提示”或“后端物理磁盘”的属性,则它们应相互一致。如果不一致,则 RAID 配置将失败(因为找不到合适的后端物理磁盘)。

target_raid_config 的示例

示例 1。具有 RAID 等级 5 的单个 RAID 磁盘,并使用所有可用空间。将此磁盘设为 Ironic 部署镜像的根卷

{
  "logical_disks": [
    {
      "size_gb": "MAX",
      "raid_level": "5",
      "is_root_volume": true
    }
  ]
}

示例 2。两个 RAID 磁盘。一个具有 RAID 等级 5 的 100 GiB,并将其设为根卷并使用 SSD。另一个具有 RAID 等级 1 的 500 GiB,并使用 HDD

{
  "logical_disks": [
    {
      "size_gb": 100,
      "raid_level": "5",
      "is_root_volume": true,
      "disk_type": "ssd"
    },
    {
      "size_gb": 500,
      "raid_level": "1",
      "disk_type": "hdd"
    }
  ]
}

示例 3。单个 RAID 磁盘。我知道要使用哪些磁盘和控制器

{
  "logical_disks": [
    {
      "size_gb": 100,
      "raid_level": "5",
      "controller": "Smart Array P822 in Slot 3",
      "physical_disks": ["6I:1:5", "6I:1:6", "6I:1:7"],
      "is_root_volume": true
    }
  ]
}

示例 4。使用后端物理磁盘

{
  "logical_disks": [
    {
      "size_gb": 50,
      "raid_level": "1+0",
      "controller": "RAID.Integrated.1-1",
      "volume_name": "root_volume",
      "is_root_volume": true,
      "physical_disks": [
        "Disk.Bay.0:Encl.Int.0-1:RAID.Integrated.1-1",
        "Disk.Bay.1:Encl.Int.0-1:RAID.Integrated.1-1"
      ]
    },
    {
      "size_gb": 100,
      "raid_level": "5",
      "controller": "RAID.Integrated.1-1",
      "volume_name": "data_volume",
      "physical_disks": [
        "Disk.Bay.2:Encl.Int.0-1:RAID.Integrated.1-1",
        "Disk.Bay.3:Encl.Int.0-1:RAID.Integrated.1-1",
        "Disk.Bay.4:Encl.Int.0-1:RAID.Integrated.1-1"
      ]
    }
  ]
}

示例 5。具有两个 RAID 设备的软件 RAID

{
  "logical_disks": [
    {
      "size_gb": 100,
      "raid_level": "1",
      "controller": "software"
    },
    {
      "size_gb": "MAX",
      "raid_level": "0",
      "controller": "software"
    }
  ]
}

示例 6。软件 RAID,限制后端块设备数量为正好两个设备,且大小超过 100 GiB

{
  "logical_disks": [
    {
      "size_gb": "MAX",
      "raid_level": "0",
      "controller": "software",
      "physical_disks": [
        {"size": "> 100"},
        {"size": "> 100"}
      ]
    }
  ]
}

当前的 RAID 配置

在目标 RAID 配置应用于裸机节点后,Ironic 会填充当前的 RAID 配置。这填充在 Ironic 节点的 raid_config 字段中。其中包含有关在裸机节点上创建的每个逻辑磁盘的详细信息。它包含有关使用的 RAID 控制器、使用的后端物理磁盘、每个逻辑磁盘的 WWN 等的信息。它还包含有关在裸机节点上找到的每个物理磁盘的信息。

要获取当前的 RAID 配置

baremetal node show <node-uuid-or-name>

工作流程

  • 操作员使用具有 RAIDInterface(不为 no-raid)的硬件类型配置裸机节点。例如,对于软件 RAID,这将是 agent

  • 对于带内 RAID 配置,操作员通过将硬件管理器与 ramdisk 捆绑在一起来构建支持 RAID 配置的代理 ramdisk。有关更多信息,请参阅 构建支持 RAID 配置的代理 ramdisk

  • 操作员准备所需的 target RAID 配置,如 目标 RAID 配置 中所述。目标 RAID 配置设置在 Ironic 节点上

    baremetal node set <node-uuid-or-name> \
       --target-raid-config <JSON file containing target RAID configuration>
    

    CLI 命令也可以接受来自标准输入的输入

    baremetal node set <node-uuid-or-name> \
       --target-raid-config -
    
  • 创建一个包含手动清理的 RAID 清理步骤的 JSON 文件。根据需要添加其他清理步骤

    [{
      "interface": "raid",
      "step": "delete_configuration"
    },
    {
      "interface": "raid",
      "step": "create_configuration"
    }]
    

    注意

    ‘create_configuration’ 不会删除现有的磁盘。建议在 ‘create_configuration’ 之前添加 ‘delete_configuration’,以确保在手动清理后系统中仅存在所需的逻辑磁盘。

  • 将节点置于 manageable 状态并执行 clean 操作以开始节点上的清理

    baremetal node clean <node-uuid-or-name> \
       --clean-steps <JSON file containing clean steps created above>
    
  • 在手动清理完成后,当前的 RAID 配置报告在运行 raid_config 字段中

    baremetal node show <node-uuid-or-name>
    

软件 RAID

从 Train 版本开始,支持通过 Ironic Python Agent ramdisk 进行带内 Linux 软件 RAID 构建。通过使用 agent RAID 接口和将所有控制器设置为 software 的 RAID 配置来请求。可以在 target_raid_config 的示例 中找到软件 RAID 配置示例。

有一些需要注意的限制

  • 目前仅支持 目标 RAID 配置 中的必需属性(以及必需的 controller 属性)。

  • 创建的软件 RAID 设备的数量必须为 1 或 2。如果只有一个软件 RAID 设备,则必须是 RAID-1。如果有两个,则第一个必须是 RAID-1,而第二个的 RAID 等级可以是 0、1、1+0、5 或 6。由于第一个 RAID 设备将是部署设备,因此强制使用 RAID-1 可降低磁盘故障导致节点无法启动的风险。

  • 如果目标磁盘已分区,则 RAID 构建将失败。在构建 RAID 之前,使用例如 erase_devices_metadata 清理步骤擦除磁盘

    [{
      "interface": "raid",
      "step": "delete_configuration"
    },
    {
      "interface": "deploy",
      "step": "erase_devices_metadata"
    },
    {
      "interface": "raid",
      "step": "create_configuration"
    }]
    
  • 最终的实例镜像必须安装 mdadm 实用程序,并且需要在启动时检测软件 RAID 设备(通常通过在镜像的 initrd 中嵌入 RAID 驱动程序来实现)。

  • 常规清理不会删除 RAID 配置(与硬件 RAID 类似)。要销毁 RAID,请运行 delete_configuration 手动清理步骤。

  • 不支持分区镜像,仅支持使用软件 RAID 的整个磁盘镜像。请参阅 将镜像添加到 Image 服务。这包括请求动态创建交换文件系统的 flavor。

  • 不建议使用 LVM 作为根文件系统的镜像。欢迎提供补丁以明确支持此功能。

  • 如果根文件系统 UUID 未通过元数据告知 Ironic,则磁盘镜像布局 必须 将第一个分区设为根文件系统。Ironic 不关心分区表是 DOS MBR 还是 GPT 分区。

    从 Ironic 14.0.0 (Ussuri) 开始,可以通过 Glance Image Service properties 子字段 rootfs_uuid 将根文件系统 UUID 设置并通过传递给要部署的镜像。

    从 Ironic 16.1.0 (Wallaby) 开始,可以通过裸机节点 instance_info 字段值 image_rootfs_uuid 提供类似的功能。有关独立使用方法的更多详细信息,请参阅 将 Bare Metal 服务用作独立服务,包括示例命令。

  • 在 UEFI 模式下,Ironic Python Agent 会为启动加载程序和启动配置(grub.cfg 或 grubenv)在所有持有设备上创建 EFI 系统分区 (ESP)。从部署的用户镜像中填充这些分区的的内容。根据分区的挂载方式,这些分区的内容可能会不同步,例如,当安装新内核或更新启动加载程序时,需要采取措施使这些分区保持同步。请注意,从 Victoria 版本开始,Ironic Python Agent 为 ESP 配置 RAID-1 镜像,因此不再需要采取额外的措施来确保 ESP 的一致性。

  • 在 BIOS 模式下,Ironic Python Agent 会将启动加载程序安装到所有磁盘上。虽然不需要内核或 grub 包更新,但重新安装一个磁盘上的启动加载程序,例如在磁盘更换期间,可能需要重新安装所有磁盘上的启动加载程序。否则,存在设备上存储的 grub 组件(即 MBR 中的 stage1/boot.img 和 MBR 间隙中的 stage1.5/core.img)与 /boot 中存储的组件不兼容的风险。这种不兼容性可能导致节点无法启动,因为选择了错误的磁盘进行启动。

  • Linux 内核设备命名对于 RAID 设备在重新启动之间不一致,并且可能以特定于发行版的模式编号。如果使用根设备提示,操作员需要注意这一点。一个典型的例子是,基于 Ubuntu 的 ramdisk 上的第一个“md0”设备可能从设备“md0”开始,而基于 Centos 或 Red Hat Enterprise Linux 的 ramdisk 可能从设备“md127”开始。在重新启动后,这些设备名称可能会完全更改。

    注意

    根设备提示 不应显式要求以使用软件 RAID。候选设备是通过排序可用设备列表来选择的,寻找最小的可用的设备,然后按名称排序。按名称的二次排序提高了匹配第一个初始化的块设备的几率。在软件 RAID 的情况下,由于元数据开销,它们通常比主块设备小,这有助于使它们成为最可能的候选设备。

镜像要求

由于 Ironic 在部署使用软件 RAID 的节点时需要执行额外的步骤,因此部署的镜像需要满足一些要求。直到 Train 版本为止,镜像需要将其根文件系统放在第一个分区上。从 Ussuri 版本开始,镜像还可以具有额外的元数据,以指向包含根文件系统的分区:为此,镜像需要设置 rootfs_uuid 属性,其中包含根文件系统的文件系统 UUID。从现有镜像中提取此 UUID 的一种方法是下载镜像,将其作为环回设备挂载,并使用 blkid

$ sudo losetup -f
$ sudo losetup /dev/loop0 /tmp/myimage.raw
$ sudo kpartx -a /dev/loop0
$ blkid

Ussuri 之前的做法,即根文件系统位于第一个分区上,作为一种回退机制保留,因此允许在 Ironic 无法访问任何镜像元数据(例如 Ironic 独立部署)的情况下进行软件 RAID 部署。

在 nova flavor 中使用 RAID 进行调度

操作员可以在 nova flavor 中指定 raid_level 功能,以选择要进行调度的节点

openstack flavor set my-baremetal-flavor --property capabilities:raid_level="1+0"

开发者文档

带内 RAID 配置使用 IPA ramdisk 完成。IPA ramdisk 支持可插拔的硬件管理器,可以使用 stevedore 插件来扩展 IPA ramdisk 提供的功能。有关更多信息,请参阅 Ironic Python Agent 硬件管理器 文档。

支持 RAID 配置的硬件管理器应执行以下操作

  1. 实现一个名为 create_configuration 的方法。此方法根据 target_raid_config 中给定的内容创建 RAID 配置。RAID 配置成功后,它将返回当前的 RAID 配置信息,Ironic 会使用该信息来设置 node.raid_config

  2. 实现一个名为 delete_configuration 的方法。此方法删除裸机上的所有 RAID 磁盘。

  3. 以优先级 0 的形式在 get_clean_steps 方法中返回这两个清理步骤。示例

    return [{'step': 'create_configuration',
             'interface': 'raid',
             'priority': 0},
            {'step': 'delete_configuration',
             'interface': 'raid',
             'priority': 0}]