使用 Neutron 的新端口绑定 API

在所有发生端口绑定的情况下,充分利用 Neutron 的新端口绑定 API。在迁移操作的特殊情况下,新的 API 将允许我们模拟源主机和目标主机都具有端口绑定,而这在今天的实时迁移中没有考虑到。

https://blueprints.launchpad.net/nova/+spec/neutron-new-port-binding-api

问题描述

该更改的主要动机是实时迁移方面的一些问题,特别是

  • 如果目标端的端口绑定失败,我们会在开始实时迁移之前知道。

  • 在许多情况下,源主机和目标主机需要非常不同的绑定,但这在今天是不可能的。特别是,macvtap 实时迁移通常需要在源主机和目标主机上使用不同的 libvirt XML。

  • 在 Mitaka 中,Neutron 引入了基于连接跟踪的安全组驱动程序,用于基于 ovs 的后端。在具有不同安全组驱动程序的主机之间进行实时迁移是更普遍的在不同的 ml2 驱动程序之间进行实时迁移的另一个激励用例,两者都需要在源主机和目标主机上使用不同的 libvirt XML 定义。

  • 为了尽快在源主机和目标主机之间切换,最好在开始迁移之前准备好大部分内容。我们添加了一个短期补丁 https://review.openstack.org/#/c/275073/ 用于 DVR,但让我们正确地执行它。

更多详细信息可以在 neutron spec 中找到:https://specs.openstack.org/openstack/neutron-specs/specs/pike/portbinding_information_for_nova.html

在考虑此规范时,我们应该明确端口绑定和

  • 端口绑定,Neutron 数据库中的记录,描述端口与哪个主机和实例关联以及其当前状态。

  • 插拔 VIF,将来自 Neutron 的信息传递给 OS-VIF(或旧版驱动程序),以便在主机上准备端口

  • 将实例附加到上述准备工作(通过 tap 设备或 PCI 直通等)

  • 活动绑定,流量应该发送到的主机,因为虚拟机实际上正在运行在那里

为了解决这个问题,我们需要考虑处理端口绑定的所有位置,以使用新的 API 流程。我们通常在移动虚拟机时更新端口绑定。需要考虑的主要 API 操作是

  • 将端口附加到实例,包括在生成实例期间

  • 将端口从实例分离

  • 实时迁移实例,包括在启动实时迁移之前在目标主机上设置 VIF,然后在完成实时迁移后从源主机上删除 VIF。

  • 迁移和调整大小与实时迁移非常相似

  • 撤离,我们知道旧主机已死,我们希望删除任何旧连接的记录,并在新主机上附加端口。

  • 休眠,我们希望端口在逻辑上仍然附加到实例,但我们需要在卸载实例时取消绑定端口。

在上述迁移操作中,当需要将流量切换到目标端时,Neutron 应该通过激活新的端口绑定得到通知。

用例

作为管理员,如果可以在预迁移期间检测到目标主机上的网络设置将无法工作,我希望实时迁移尽早失败。

作为用户,我希望在我的实例正在实时迁移时,网络停机时间最短。

作为操作员,我想开始使用新的 ML2 后端,但需要将现有的实例从不同的后端实时迁移,同时尽量减少网络停机时间。

作为操作员,我想利用新的安全组实现,并且需要能够将现有的实例从我的旧主机实时迁移。

提议的变更

部署者无需额外配置。多重绑定的使用将自动启用。我们决定使用新的还是旧的 API 流程,如果两个计算节点都支持此功能,并且基于可用的 Neutron API 扩展。我们以通常的方式缓存扩展支持,利用现有的 neutron_extensions_cache。

注意:新的 neutron API 扩展将在 ml2 插件层实现,在 ml2 驱动程序层之上,因此如果公开了扩展,它将支持所有 ml2 驱动程序。单体插件将不得不单独实现扩展,并且将继续使用旧的工作流程,直到其维护者支持新的 neutron 扩展。

当所有 neutron 后端都有足够的时间来支持此模型时,应该删除旧的交互模型,目标是在两个周期内完成此操作。我们应该在代码结构中记住这一点。考虑到我们也在研究删除 nova-network,我们应该看看是否可以将其添加为一组新的网络 API 调用,这些调用仅用于 neutron,从而使现有调用对于 Neutron 来说是无操作的。

跨混合软件版本迁移

如果存在旧的 neutron,则无论计算节点版本如何,都将遵循现有的工作流程。如果部署了支持此功能的新 neutron,将实现以下行为。

  • 如果两个计算节点都是 rocky 或更高版本。在这种情况下,将使用如下所述的新工作流程。

  • 在所有其他情况下,使用旧的工作流程

让我们考虑实时迁移以及对 neutron 的调用将是什么样子。

今天的工作流程记录在此处:https://docs.openstack.org/nova/latest/reference/live-migration.html

今后,工作流程将按如下方式更改

  • Conductor 对目标端和源端进行预检查,从而创建 migrate_data 对象。

  • Conductor 检查源端和目标端版本,以查看它们是否支持新的流程。

    • 如果足够新,Conductor 会调用目标计算节点上的一个新方法,以在目标主机上绑定端口。新方法将 POST 到 /v2.0/ports/{port_id}/bindings,仅传递目标 host_id

      {
        "binding": {
          "host_id": "target-host_id"
        }
      }
      
    • 如果失败,实时迁移任务可以忽略该主机并重新安排/重试另一个主机,因为这在我们向源端广播以启动超visor 上的实时迁移之前。

    • 如果成功,端口绑定结果将放入 migrate_data 对象中,该对象将发送到源 live_migration 方法,然后所有关心代码都会检查 migrate_data 对象中的新属性。

    • 新属性将由端口绑定响应的最小子集组成,并将编码在一个新的 nova 对象中

      fields = {
          'port_id': fields.StringField(),
          'host_id': fields.StringField(),
          'vnic_type': fields.StringField(),  # could be enum
          'vif_type': fields.StringField(),
          'vif_details': fields.DictOfStringsField(),
      }
      

      在实现过程中,我们将尝试将 vif_details 字段限制为 nova 生成更新的域 xml 和插拔 vif 所需的 vif_details 子集。这是为了避免随机的 ML2 后端特定数据改变我们版本化对象中的行为。将来,此对象将被 os-vif 定义的对象取代。

  • 在目标端的 pre_live_migration 中

    • 在从源主机上的 live_migration 到目标主机上的 pre_live_migration 的 RPC 调用之前,启动一个等待线程,等待来自 Neutron 的 vif 已插拔事件,类似于初始生成期间。

      注意

      此 vif 已插拔的更改可以作为错误修复或加固机会进行,而无需此蓝图。

    • 检查 migrate_data 是否包含新的 VIF 属性,如果是,则使用新的端口绑定在目标主机上插拔 vif,否则回退到旧的工作流程并使用旧的 vif 绑定插拔 vif。

  • 此时,可以安全地开始实时迁移实例。

    • 这涉及调用 virt 驱动程序以实时迁移实例,然后激活端口绑定。如果 migrate_data 包含新的目标主机端口绑定 VIF 属性,它将用于在超visor 上开始实际的实时迁移之前配置目标访客。如果目标主机上的 VIF 类型与源主机不同,则如此。

    • 对于 libvirt virt 驱动程序,我们将等待源主机上的 qemu 事件,名为 VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY,这样我们就会知道 libvirt 已经暂停了 VM,并标记新的端口绑定为活动状态。这在此处有更详细的描述:https://review.openstack.org/#/c/434870/

    • 对于其他 virt 驱动程序,激活端口绑定的决定留给它们。他们可以通过在迁移实例之前或之后立即串行化调用来激活端口绑定,或者如果超visor 允许他们减少网络停机时间,则可以并发等待事件,或者只是在 post_live_migration 中激活目标主机端口绑定。

  • 我们只应该在这里遇到错误,如果迁移超时。如果我们遇到任何其他错误,则没有回滚,我们只是将实例置于 ERROR 状态。如果超时,我们中止如下所述。

  • 在 post_live_migration 期间

    在源主机上清理 VIF 后,我们删除与源主机关联的旧端口绑定。如果操作被中断,绑定中包含足够的信息以确保可以手动清理。

中止

  • 如果管理员中止正在进行的实时迁移,回滚操作因我们当前处于迁移的哪个阶段而异。

  • 如果我们处于 pre_live_migration 阶段并且尚未开始迁移,我们只需删除目标端口绑定。

  • 如果我们在远程节点上启动了 VM 并插拔了接口,但尚未取消暂停实例,我们取消插拔实例,如果需要激活源绑定,然后删除目标绑定。

其他

我们可以遵循此模式,无论哪里存在两个主机上的 VIF,例如在调整大小和迁移期间。

撤离是一个特殊情况,我们删除旧主机上的端口绑定,而不知道它是否已删除 VIF,因为我们假设主机已死并且将永远不会恢复。

通过此更改,应该可以在具有不同 neutron 后端和/或安全组驱动程序的主机之间进行实时迁移。虽然此规范中没有明确描述,但此功能的实现不应阻止该工作或采用 oslo 版本化对象进行 nova / neutron 端口绑定协商的努力,但是,它也不依赖于任何活动的完成。

备选方案

我们可以让某些 Neutron 驱动程序的实时迁移中断。

注意:还有计划允许实时迁移用于在不同的 Neutron 插件之间切换,以及允许用于附加到 SR-IOV 的 macvtap 的实时迁移,但这不在本次更改的范围内。

我们可以支持混合计算节点之间的实时迁移。在这种情况下,假设 neutron 支持新的流程,将引入以下行为。

  • 旧的源计算节点和新的目标节点。以 libvirt 为例,由于迁移 XML 生成是由源节点完成的,如果新的目标计算节点检测到需要 XML 更改,它应该使迁移失败。这改变了现有的行为,其中实时迁移可能会成功完成,但会导致没有网络连接。

  • 新的源计算节点和旧的目标节点。在这种情况下,源节点可以创建端口绑定并更新 xml。关于在目标主机上激活绑定,有两个选项。源节点可以在开始实时迁移之前激活绑定,也可以在成功后激活绑定。在迁移失败的情况下,提前激活绑定会导致更多工作,而迁移成功后激活绑定可能会增加网络停机时间。选择的选项留给实现审查来定义,并将记录为对现有实时迁移 devref 的更新。

由于代码和测试的复杂性,这尚未得到支持。

数据模型影响

REST API 影响

安全影响

通知影响

其他最终用户影响

性能影响

有额外的 API 调用,但它应该对性能影响很小。

其他部署者影响

开发人员影响

升级影响

跨混合软件版本迁移 中所述,此更改将通过让 conductor 检查源端和目标端计算服务版本,以查看它们是否兼容使用新的端口绑定流程来解释滚动升级,否则将使用旧的工作流程。

实现

负责人

主要负责人

Matt Riedemann (mriedem)

其他贡献者

Sean Mooney (sean-k-mooney)

工作项

  • 在 conductor 中添加源/目标主机版本检查,以及在目标主机上创建端口绑定之前启动源主机上实时迁移的新计算 RPC API 方法。

  • 在与实时迁移相关的各种计算方法中检查新的 migrate_data 属性,以确定我们是旧流程还是新流程。

依赖项

测试

需要新路径的功能测试。

文档影响

需要更新开发人员文档,以包含有关 Nova 如何在实时迁移期间与 Neutron 交互的详细信息。

参考资料

历史

修订版

发布名称

描述

Queens

引入;已批准

Rocky

重新提出