允许 Manila 共享直接附加到使用 libvirt 的实例

https://blueprints.launchpad.net/nova/+spec/libvirt-virtiofs-attach-manila-shares

Manila 是 OpenStack 共享文件系统服务。此规范将概述 Nova 中所需的 API、数据库、计算和 libvirt 驱动程序更改,以允许 Manila 提供的共享与实例关联并附加到实例。

问题描述

目前,用户必须手动连接到并挂载实例中由 Manila 提供的共享。因此,操作员需要确保 Manila 后端存储可以从客户机子网路由访问。

用例

  • 作为操作员,我希望 Manila 数据路径与任何租户可访问的网络分离。

  • 作为用户,我希望将 Manila 共享直接附加到我的实例,并拥有一个简单的界面来在实例中挂载它们。

  • 作为用户,我希望从我的实例分离直接附加的 Manila 共享。

  • 作为用户,我希望跟踪附加到我的实例的 Manila 共享。

提议的变更

此初始实现仅提供对附加共享到现有 SHUTOFF 实例的支持,以及稍后分离共享的支持。在实例的初始创建过程中表达附件的能力不在本规范的涵盖范围内。

一旦挂载了共享,移动操作的支持将不在本规范的覆盖范围内。任何请求冷迁移、撤离、实时迁移重建、调整大小、挂起、暂停或对带有挂载共享的实例进行卷快照的操作,在目前都会被拒绝,并返回 HTTP409 响应。

将在新的微版本下引入一个新的服务器 shares API。这将列出当前共享,显示其详细信息,并允许附加或分离共享。

将引入一个新的 share_mapping 数据库表和相关的 ShareMapping 版本化对象,以捕获共享附件的详细信息。将提供一个基础 ShareMapping 版本化对象,可以从中派生 virt 驱动程序和后端共享特定的对象,从而提供特定的共享附加和分离实现。

注意

需要注意的是,Nova 内部不会存储任何 Manila 状态,除了用于初始附加共享的导出详细信息。稍后在分离共享时将使用这些详细信息。如果共享随后重新附加,Nova 将从 Manila 请求新的导出详细信息,并在 Nova 中新的共享附件中存储这些信息。

libvirt 驱动程序将被扩展以支持上述功能,最初支持冷连接和断开。未来的工作将致力于添加实时连接和断开,因为它现在已被 libvirt 支持

此初始 libvirt 支持将针对 Manila 中的基本 NFS 和更复杂的 CephFS 后端。共享将通过 virtio-fs 映射到基础 libvirt 域。这需要计算主机上的 QEMU >=5.0 和 libvirt >= 6.2,以及实例客户机操作系统内的 >= 5.4 的内核版本。

此外,此初始实现需要关联的实例使用 文件支持的内存大页。这是 virtio-fs 的要求,因为 virtiofsd 服务使用 vhost-user 协议直接与基础客户机通信。(参考:vhost-user 文档

将引入两个新的计算能力特征和过滤器,以模拟计算对 virtio-fs 和文件支持内存的支持。在将共享关联到实例时,将检查运行该实例的主机是否支持

  • COMPUTE_STORAGE_VIRTIO_FS 特征

  • COMPUTE_MEM_BACKING_FILE 特征

或者

实例配置了 hw:mem_page_size 附加规格。

从操作员的角度来看,这意味着 COMPUTE_STORAGE_VIRTIO_FS 支持要求操作员必须将所有计算节点升级到支持使用 virtiofs 的版本的版本。

COMPUTE_MEM_BACKING_FILE 支持要求操作员配置一个或多个具有文件支持内存的主机。可以通过创建包含这些主机的 AZ 来确保实例将降落在其中一个主机上。然后指示用户将他们的实例部署到此 AZ。或者,操作员可以通过将 trait:COMPUTE_MEM_BACKING_FILE=required 作为附加规格或镜像属性添加到调度器来引导调度器选择合适的宿主机。

用户将使用挂载标签挂载附加的共享,这要么是 Manila 中的共享 UUID,要么是用户在其附加共享请求中提供的字符串。

user@instance $ mount -t virtiofs $tag /mnt/mount/path

最初的实现不会创建先前讨论的 os-share 库,但如果底层主机上挂载和跟踪共享所需的逻辑也由其他项目需要,则将来可以创建它。目前,libvirt 驱动程序中现有的代码 用于跟踪基于 remoteFS 的存储(例如 NFS、SMB 等)托管的卷使用的文件系统主机挂载,将尽可能地重用。

共享映射状态

                     +----------------------------------------------------+   Reboot VM
    Start VM         |                                                    | --------------+
    Share mounted    |                       active                       |               |
+------------------> |                                                    | <-------------+
|                    +----------------------------------------------------+
|                      |                   |             |
|                      | Stop VM           |             |
|                      | Fail to umount    |             |
|                      v                   |             |
|                    +------------------+  |             |
|                    |      error       | <+-------------+-------------------+
|                    +------------------+  |             |                   |
|                      |                   |             |                   |
|                      | Detach share or   |             |                   |
|                      | delete VM         | Delete VM   |                   |
|                      v                   |             |                   |
|                    +------------------+  |             |                   |
|    +-------------> | detaching --> φ  | <+             |                   | Start VM
|    |               +------------------+                |                   | Fail to mount
|    |                 |                                 |                   |
|    | Detach share    |                                 | Stop VM           |
|    | or delete VM    | Attach share                    | Share unmounted   |
|    |                 v                                 v                   |
|    |               +----------------------------------------------------+  |
|    +-------------- |          attaching --> inactive                    | -+
|                    +----------------------------------------------------+
|                      |
+----------------------+

φ 表示数据库中没有条目。共享和服务器之间没有关联。

附加共享

表示 POST /servers/{server_id}/shares

分离共享

表示 DELETE /servers/{server_id}/shares

此图描述了共享映射状态(nova),这与 Manila 共享的状态无关。

共享的挂载/卸载只能在 VM 状态为 STOPPEDERROR 时进行。

如果底层共享的挂载失败,或者共享不在非活动状态,则启动 VM 的操作可能会失败。

注意

在这种情况下,实例将被标记为 ERROR。后续尝试启动 VM 将需要用户进行硬重启,这符合此类情况的标准流程。这种错误处理将由计算主机集中管理。

如果共享未挂载到计算主机上,则将执行挂载操作。如果以前的共享已挂载到计算主机上用于另一个服务器,则将尝试挂载它,并记录警告,说明该共享已挂载。

卸载操作只有在共享已挂载且不再被另一个服务器使用时才会真正完成。

使用上述挂载和卸载操作,状态存储在内存中,不需要在数据库中查找。

共享将以读/写模式挂载到计算主机上。不支持只读,因为无法同时以只读和读/写模式挂载共享。如果用户想以只读模式挂载共享,则必须在 VM fstab 中执行此操作。

实例删除流程

标准删除

  • 在计算侧的正常删除过程中,将尝试卸载和删除 Manila 策略。

    • 如果这两个操作都成功,则相应的共享映射也会被删除。

    • 如果卸载或策略删除失败,实例本身将被删除,但共享映射记录可能仍然保留在数据库中。未来的增强功能将包括一个定期任务,旨在卸载、删除策略并清理任何泄漏的共享映射。

本地删除

  • 当 VM 在数据库中被标记为 DELETED,因为在删除请求期间计算资源不可用时,不会通过 API 进行卸载或 Manila 策略删除。

    • 一旦计算资源再次可用,它将识别那些已被标记为 DELETED 但尚未清理的实例。在实例初始化期间,计算资源将尝试完成删除过程,其中包括卸载共享和删除访问策略。

      • 如果这些操作成功,共享映射将被删除。

      • 如果任何操作失败,删除将保持不完整;但是,计算资源的启动过程将不受影响,并且错误仅会被记录。出于安全原因,不保留挂载至关重要,因此需要重试机制进行清理。这种情况与标准删除场景平行,需要类似的定期任务来解决。

Manila 共享删除问题

在 Zed 周期中发现了一个问题,用户可以删除被实例使用的共享。因此,实例将失去对数据的访问权限,并且可能导致删除丢失的共享和修复实例出现困难。

与 Manila 团队确定了一种解决方案,即在共享访问策略中附加元数据,这将锁定共享并防止其删除,直到取消锁定。

此解决方案已在 Antelope 周期中实施。此处的提案将在 Nova 中使用锁定机制。

实例元数据

在实例元数据中添加实例共享。扩展 DeviceMetadata,使其包含 ShareMetadata 对象,其中包含用于在实例上通过用户挂载 virtiofs 的 share_idtag。请参阅 其他终端用户影响

备选方案

唯一的替代方案是继续当前的情况,即用户必须手动在他们的实例中挂载共享。缺点是这些实例必须能够访问 Manila 后端使用的存储网络。

REST API 影响

将在新的微版本下引入一个新的服务器级别 shares API,其中包含以下方法

  • GET /servers/{server_id}/shares

列出附加到实例的所有共享。

返回代码:200、400、401、403、404

{
    "shares": [
        {
            "share_id": "48c16a1a-183f-4052-9dac-0e4fc1e498ad",
            "status": "active",
            "tag": "foo"
        },
        {
            "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
            "status": "active",
            "tag": "bar"
        }
    ]
}
  • GET /servers/{server_id}/shares/{share_id}

显示附加到实例的特定共享的详细信息。

返回代码:200、400、401、403、404

{
    "share": {
        "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
        "status": "active",
        "tag": "bar"
    }
}

PROJECT_ADMIN 能够查看存储在 Nova 中的附件 ID 和导出位置的详细信息

{
    "share": {
        "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
        "status": "active",
        "tag": "bar",
        "export_location": "server.com/nfs_mount,foo=bar"
    }
}
  • POST /servers/{server_id}/shares

将共享附加到实例。

先决条件:

  • 实例必须处于 SHUTOFF 状态。

  • 实例应具有启用 virtiofs 所需的功能(见上文)。

此 API 以异步方式运行。因此,share_mapping 被定义,并且其状态在数据库中标记为“attaching”。

在后台,计算节点将请求 Manila 授予对共享的访问权限并将其锁定用于 nova 使用。一旦此过程完成,共享状态将更改为非活动状态。重要的是要注意,锁定共享也会限制对用户的可见性,以防止任何意外暴露内部数据。

之后,当 VM 启动时,共享将被挂载到计算节点上,并指定为活动状态,前提是没有发生错误。相反,当 VM 关闭时,共享将从计算节点卸载并标记为非活动状态,同样,如果没有遇到错误。

返回代码:202、400、401、403、404、409

请求主体

注意

tag 将是请求体中的可选请求参数,如果未提供,它将始终如请求中提供的 share_id (UUID)。

tag 如果由用户提供,必须是最大长度为 64 字节的 ASCII 字符串。

{
    "share": {
        "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986"
    }
}

响应体

{
    "share": {
        "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
        "status": "active",
        "tag": "e8debdc0-447a-4376-a10a-4cd9122d7986"
    }
}
  • DELETE /servers/{server_id}/shares/{share_id}

将共享从实例分离。

先决条件:实例必须处于 SHUTOFFERROR 状态。

此 API 以异步方式运行,导致 share_mapping 状态标记为 detaching。

同时,计算系统会进行验证,以查看共享是否不再被另一个实例使用。如果发现未使用,它将请求 Manila 解锁共享并拒绝访问。

为了保持 NFS 和 CephFS 的一致逻辑,我们目前仅在所有计算系统中的最后一个用户卸载共享后才删除访问策略。虽然 NFS 理论上可以实现基于每个计算 IP 的访问策略,但 CephFS 当前采用特定于每个 Nova 用户的访问令牌。在未来,我们可能会探索使用特定于每个 Nova 实例的每个计算系统的 CephFS 用户/令牌。

需要进行两个检查

  • 为了卸载,重要的是要验证是否有其他虚拟机正在同一计算系统上使用共享。此机制已由驱动程序实现。

  • 为了删除访问策略,我们需要确保没有计算系统当前正在使用共享。一旦此过程完成,共享的关联将从数据库中删除。

返回代码:202、400、401、403、404、409

数据模型影响

将引入一个新的 share_mapping 数据库表。

  • id - 主键自动递增

  • uuid - 用于标识特定共享附件的唯一 UUID

  • instance_uuid - 共享将附加到的实例的 UUID

  • share_id - Manila 中的共享的 UUID

  • status - Nova 中共享挂载的状态 (attaching, detaching, active, inactive, error)

  • tag - 用户用于在实例中挂载共享的设备标签。

  • export_location - 用于将共享附加到基础主机的导出位置

  • share_proto - 共享文件系统协议(NFSCEPHFS

将引入一个新的基础 ShareMapping 版本化对象,以封装上述数据库条目,并用作特定 virt 驱动程序实现的父类。

数据库字段 statusshare_proto 的值将不会使用枚举强制执行,从而允许未来的更改并避免数据库迁移。但是,为了使代码更健壮,将在对象字段上定义枚举。

包含文本的字段将在数据库模式中使用 String 而不是 Text 类型,以限制列宽并将其内联存储在数据库中。

此基础 ShareMapping 对象将提供存根 attachdetach 方法,任何子对象都需要实现这些方法。

将引入新的 ShareMappingLibvirtShareMappingLibvirtNFSShareMappingLibvirtCephFS 对象作为 libvirt 实现的一部分。

安全影响

Manila 返回的用于将共享挂载到主机以及主机文件系统位置的 export_location JSON blob 不应被 Nova 记录,并且默认情况下只能通过 API 由管理员访问。

export_location 字段也将选择性地从通知中排除。

Nova 抽象与 Openstack SDK 需要更新,以便当用户请求 Nova 将 Manila 共享附加到其实例时,Nova 在与 Manila 通信时使用用户的 Keystone 令牌。这确保了 Manila 可以正确验证用户对请求的共享的访问权限。

通知影响

将添加新的通知

  • 一个用于添加共享附加和共享分离的新通知。

  • 一个用于使用共享映射信息扩展实例更新通知。

实例有效负载中的共享映射将是可选的,并通过通知配置参数 include_share_mapping 进行控制。默认情况下将禁用它。

附加和分离通知的建议有效负载与具有管理员权限的 show 命令返回的有效负载相同。

{
    "share": {
        "instance_uuid": "7754440a-1cb7-4d5b-b357-9b37151a4f2d",
        "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
        "status": "active",
        "tag": "bar",
    }
}

实例更新的建议有效负载将是附加到该实例的共享列表。

{
    "shares":
    [
        {
            "instance_uuid": "7754440a-1cb7-4d5b-b357-9b37151a4f2d",
            "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986",
            "status": "active",
            "tag": "bar",
        },
        {
            "instance_uuid": "7754440a-1cb7-4d5b-b357-9b37151a4f2d",
            "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7987",
            "status": "active",
            "tag": "baz",
        }
    ]
}

其他最终用户影响

用户需要使用返回的 tag 在他们的 guestOS 中挂载共享。

用户可以使用实例元数据来发现和自动挂载共享。

性能影响

通过使用 vhost-user virtio-fs 应该在 guestOS 中具有接近本地(已挂载)文件系统性能。虽然 VM 和主机之间将具有接近本地的性能,但实际性能将受到网络文件共享协议和硬件的网络性能的限制。

其他部署者影响

开发人员影响

升级影响

将引入一个新的计算服务版本和能力特征,以确保计算服务和基础 virt 堆栈足够新,才能在接受请求之前通过 virtio-fs 附加共享。

将引入一个新的 DB 迁移约束,以防止共享被附加超过一次。由于 share_mapping 表从未能够在生产中使用,因此建议删除该表,然后使用更新的约束重新构建它。这种方法将有助于标准化所有数据库系统中的流程,因为 sqlite 不允许更改表约束,需要重新创建表。

实现

负责人

主要负责人

uggla (rene.ribaud)

其他贡献者

lyarwood(初始贡献者)

功能联络人

功能联络人

uggla

工作项

  • 在 os-traits 中添加新的能力特征

  • 添加 libvirt 驱动程序对冷附加和分离的支持

  • 添加新的共享 API 和微版本

依赖项

测试

  • 功能 libvirt 驱动程序和 API 测试

  • 集成 Tempest 测试

文档影响

将提供详细的管理员和用户文档。

参考资料

历史

修订

发布名称

描述

瑜伽

引入

Zed

重新提出

Antelope

重新提出

Bobcat

重新提出

Caracal

重新提出

Dalmatian

已更新并重新提出

Epoxy

已更新并重新提出