Nova 中的块设备映射¶
Nova 具有可以暴露给云实例的块设备概念。实例可以拥有多种类型的块设备(我们将在本文档的后续部分详细介绍),可用的设备取决于特定的部署以及为租户和用户设置的使用限制。块设备映射是一种组织和保存实例拥有的所有块设备信息的方式。
当我们谈论块设备映射时,通常指的是以下两种情况之一
用于指定实例启动请求的块设备的 API/CLI 结构和语法
Nova 内部的数据结构,用于记录和保存,最终持久化在 block_device_mapping 表中。然而,Nova 内部有几种“略有”不同的格式来表示相同的数据。所有这些都在代码中记录,或者由一组不同的类呈现,但不知道它们的存在可能会让阅读代码的人感到困惑。因此,除了镜像数据库模式的 BlockDeviceMapping [1] 对象之外,我们还有
2.1 API 格式 - 这是从 API 客户端接收到的原始键值对集合,几乎立即转换为对象;但是,使用此格式会进行一些验证。从现在开始,我们将把此格式称为“API BDM”。
2.2 virt 驱动程序格式 - 这是
nova.virt.block_device中的类定义的格式。该格式由各种 virt 驱动程序中的代码使用和期望。这些类除了暴露不同的格式(模仿 Python dict 接口)之外,还提供了一个用于捆绑某些类型的块设备通用的功能的地方(例如,附加卷,必须与 Cinder 和 virt 驱动程序代码交互)。从现在开始,我们将把此格式称为“Driver BDM”。有关更多详细信息,请参阅 驱动程序 BDM 数据结构 参考文档。
注意
允许附加到单个服务器的磁盘设备的最大数量可以通过选项 compute.max_disk_devices_to_attach 进行配置。
API BDM 数据格式及其历史¶
在 Nova 的早期阶段,块设备映射的总体结构紧密模仿了 EC2 API。在 Nova 的 Havana 版本中,块设备处理代码,进而块设备映射结构,进行了改进通用性和实用性的工作。这些改进包括在 API 中暴露更多详细信息和功能。为了便于此,向 v2 API 添加了一个名为 BlockDeviceMappingV2Boot [2] 的新扩展,该扩展在实例启动 API 请求中添加了一个额外的 block_device_mapping_v2 字段。
块设备映射 v1(又名遗留)¶
这是原始格式,仅支持 cinder 卷(类似于 EC2 块设备仅支持 EBS 卷)。每个条目都以设备名称为键(我们稍后在本页的单独部分讨论为什么这有问题),并且只能接受
Cinder 卷或快照的 UUID
类型字段 - 仅用于区分卷和 Cinder 卷快照
可选大小字段
可选
delete_on_termination标志
虽然 Nova 内部的所有代码仅使用和存储新的数据结构,但我们仍然需要处理使用遗留格式的 API 请求。Nova API 服务在每个请求上都会处理此问题。正如我们稍后将看到的那样,由于块设备映射信息也可以存储在 Glance 的图像元数据中,因此这是我们需要处理 v1 格式的另一个地方。处理遗留转换的代码是 nova.block_device 模块的一部分。
插曲 - 设备名称的问题¶
将设备名称作为每个实例的主要标识符并将其暴露在 API 中,对于 Nova 来说是有问题的,主要是因为 Nova 支持的几个超visor 无法保证 guest OS 分配的设备名称是用户从 Nova 请求的名称。在 Nova 的公共 API 中暴露这样的细节显然不是理想的,但为了向后兼容性,它需要保留。它也需要用于一些(略微晦涩)的功能,例如在启动实例时重载 Glance 图像中的块设备 [3]。
解决此问题的计划是允许用户不指定块设备的设备名称,Nova 将确定它(在 virt 驱动程序的帮助下),以便仍然可以通过 API 发现它并在必要时使用它,就像上述功能一样(最好仅在当时)。
指定设备名称的另一个用途是允许“从卷启动”功能,通过指定与实例的根设备名称匹配的设备名称(通常为 /dev/vda)。
目前(Liberty 中期),我们不鼓励用户为所有需要或允许块设备映射的调用指定设备名称,除非尝试覆盖实例启动时的图像块设备映射,并且未来可能仍然如此。Libvirt 设备驱动程序将直接覆盖使用其自身值传递的任何设备名称。
块设备映射 v2¶
引入新格式是为了解决上述讨论的原始块设备映射格式中的问题,并允许更多灵活性和添加以前无法实现的特性。
新的块设备映射是包含以下字段的字典列表(除了已经存在的字段)
source_type - 这可以是以下值之一
imagevolumesnapshotblank
destination_type - 这可以是以下值之一
localvolume
guest_format - 告诉 Nova 如何/是否在附加设备之前格式化设备,应仅与空白本地图像一起使用。如果值为
swap,则表示交换磁盘。device_name - 请参阅上一节以获取更深入的说明 - 目前最好留空(未指定),除非用户想覆盖图像元数据中指定的现有设备。对于 Libvirt 而言,即使在以覆盖现有图像元数据的目的传递,实例的最终设备名称集仍然可能被驱动程序更改。
disk_bus 和 device_type - 一些超visor(当前仅限 libvirt)可能支持的低级细节。一些示例 disk_bus 值可以是:
ide、usb、virtio、scsi,而 device_type 可以是disk、cdrom、floppy、lun。这并非详尽无遗的列表,因为它取决于虚拟化驱动程序,并且随着添加更多支持可能会发生变化。将这些留空是最常见的事情。boot_index - 定义超visor 在尝试从存储启动 guest 时尝试设备的顺序。每个能够用作启动设备的设备都应从 0 开始按升序分配唯一的启动索引。一些超visor 可能不支持从多个设备启动,因此只会考虑启动索引为 0 的设备。一些超visor 将支持从多个设备启动,但前提是它们是不同的类型 - 例如磁盘和 CD-ROM。将负值或 None 设置为指示不应将设备用于启动。最简单的用法是将它设置为 0 以用于启动设备,并将其保留为 None 以用于任何其他设备。
volume_type - 添加到服务器创建 API 的微版本 2.67 中,以支持在启动实例时指定卷类型。当快照卷支持的服务器时,block_device_mapping_v2 图像元数据将包含 BDM 记录中的 volume_type,因此,如果用户然后从该快照创建另一个服务器,nova 从该快照创建的卷将使用相同的 volume_type。如果用户希望更改图像元数据中的 volume_type,可以通过图像 API 来执行此操作。
有效的源/目标组合¶
source_type 和 destination_type 的组合将定义该条目所指的块设备类型。支持以下组合
image->local- 这仅当前用于引用实例正在启动的 Glance 图像的条目(它也应标记为启动设备)。值得注意的是,指定此内容的 API 请求还必须提供与启动请求的image_ref参数相同的 Glance uuid(这是为了向后兼容性,将来可能会更改)。此功能可能会扩展到指定附加到实例启动后的其他 Glance 图像(类似于内核/ramdisk 图像),但当前任何驱动程序都不支持此功能。volume->volume- 这只是要附加到实例的 Cinder 卷。它可以标记为启动设备。snapshot->volume- 这与传递type=snap的效果完全相同。它将从 Cinder 卷快照创建一个卷,并将该卷附加到实例。可以标记为可启动。image->volume- 顾名思义,这将从 Glance 图像下载到 cinder 卷并将其附加到实例。也可以标记为可启动。这实际上只是在启动实例之前从图像创建卷的快捷方式。blank->volume- 创建一个空白的 Cinder 卷并将其附加。这将还需要设置卷大小。blank->local- 根据 guest_format 字段(参见下文),这将是超visor 本地存储上的一个临时空白磁盘,或者一个交换磁盘(实例只能有一个)。
Nova 不允许在单个请求中混合 BDMv1 和 BDMv2,并且将执行基本验证以确保请求的块设备映射有效,然后再接受启动请求。
常见问题解答¶
是否可以配置 nova 以自动使用 cinder 为所有根磁盘提供卷支持?
否,Nova 中没有自动机制可以将非-从卷启动 请求转换为将图像转换为根卷。已经讨论过一段时间的几个想法,这些想法都包含在 基于卷的风味 规范中。但是,如果您希望强制用户始终创建基于卷的服务器,则可以通过将
max_local_block_devices设置为 0 来配置 API 服务。这将导致任何非从卷启动的服务器创建请求失败并返回 400 响应。