为 Nova 实时迁移提供端口绑定信息¶
https://bugs.launchpad.net/neutron/+bug/1580880
Nova 实时迁移包含 3 个阶段
pre_live_migration - 在迁移开始前执行;迁移目标已知,但实例仍驻留在源主机上。
live_migration_operation - 迁移本身,包含 2 个子阶段
在虚拟机在迁移目标计算主机上运行之前。
虚拟机在目标计算主机上运行之后,但迁移仍在进行中(后复制迁移)。
post_live_migration - 在迁移完成后执行;源虚拟机不再存在。用于完成迁移。
目前,端口绑定发生在迁移期间的目标计算主机上,被认为是 post_live_migration 阶段。不幸的是,这在流程中太晚了,因为在某些情况下,Nova 在 pre_live_migration 阶段需要此信息。我们无法将端口绑定移动到 pre_live_migration 阶段,因为原始端口绑定将被删除,由于实例仍在原始主机上处于活动状态,这将导致问题。更多详细信息包含在“替代方案”部分。
问题描述¶
为了改进实时迁移,需要 Neutron 在 pre_live_migration 阶段允许在目标计算主机上进行端口绑定,而无需删除源计算主机上的原始端口绑定。
该方案是在源主机和目标主机上都具有端口绑定,其中只有一个端口绑定处于活动状态。在实例迁移完成后,目标端口绑定将被激活,源端口绑定将被停用,但不会删除。源计算主机上的原始端口绑定将保留,以便可能将实例移回源主机,并且仅在 post_live_migration 阶段删除。
这些问题可以分为 2 类
#1 如果目标上的端口绑定失败,则保持源实例运行
端口绑定失败时实例错误状态
目前,端口绑定在迁移完成后在 post_live_migration 阶段触发。如果端口绑定失败,则实例将陷入错误状态。
解决方案是将端口绑定移动到 pre_live_migration 阶段,在那里可以更早地失败端口绑定。这将防止实例在迁移完成后陷入错误状态,并在 pre_live_migration 阶段失败迁移。
将端口绑定移动到 pre_live_migration 阶段的问题是,某些驱动程序即使实例仍处于活动状态,也会关闭源计算主机上的端口绑定。为了实现更干净的迁移解决方案,需要修改 Neutron 以允许源主机和目标主机上的端口绑定处于活动/非活动状态。
#2 处理主机之间端口绑定细节的差异
在运行不同 l2 代理的主机之间进行实时迁移
使用 MacVTap 代理进行实时迁移,当使用不同的 physnet 映射时
MacVTap 在某些情况下对实时迁移存在限制 [1],并且需要在开始迁移之前更新实例定义(libvirt domain.xml)。
更新实例定义发生在 live_migration_operation 阶段,在实例在目标计算主机上运行之前。为了使此操作成功,需要两个端口绑定,一个在源主机上处于活动状态,一个在目标主机上处于非活动状态。
提议的变更¶
对于迁移,Nova 需要在 pre_live_migration 阶段从目标计算主机获取端口绑定信息。可以通过允许计算端口绑定到迁移源和迁移目标主机来实现。
可以通过以下步骤实现
#1 扩展端口下的现有 API 实体,允许 CRUD 绑定。
#2 更新 ML2 以支持更改。
#3 更新数据库以支持更改。
Nova 的使用¶
Nova 将利用扩展的 API,潜在流程如下
pre_live_migration:创建目标主机的非活动绑定。
live_migration_operation:使用从非活动绑定收集的信息修改实例定义。
live_migration_operation:一旦实例处于活动状态,将非活动绑定设置为活动状态,并将先前的活动绑定设置为非活动状态。
post_live_migration:删除源计算主机上的非活动绑定。
如果在实例在目标上处于活动状态后执行回滚:从 Neutron 的角度来看,如果绑定在目标主机上处于活动状态,Nova 需要将源绑定设置回活动状态
PUT /v2.0/ports/{port_id}/bindings/{host_id}/activate
有关 Nova 实现的更多详细信息,请参阅相关的 Nova Blueprint [3] 及其 Spec [4]。Neutron 不会决定 Nova 实时迁移实现的 capabilities,并将支持任何一种路径,无论是回滚还是不回滚。
端口的绑定 API 扩展¶
列出绑定¶
GET /v2.0/ports/{port_id}/bindings
{
"bindings": [
{
"host_id": "source-host_id",
"vif_type": "ovs",
"vif_details": {
"port_filter": true,
"ovs_hybrid_plug": true
},
"profile": {},
"vnic_type": "normal",
"status": "active"
},
{
"host_id": "target-host_id",
"vif_type": "bridge",
"vif_details": {
"port_filter": true,
},
"profile": {},
"vnic_type": "normal",
"status": "inactive"
},
]
}
参数 |
风格 |
类型 |
描述 |
|---|---|---|---|
bindings |
plain |
xsd:list |
一个 binding 对象列表 |
更多参数请参见 显示绑定
列出绑定的重要关键特性
计算绑定将当前列出,对不受支持的绑定的请求将返回“NotImplemented”,直到引入该 capability 为止。
所有绑定都将被列出,并且当返回许多绑定时将使用分页。
显示绑定¶
GET /v2.0/ports/{port_id}/bindings/{host_id}
参数 |
风格 |
类型 |
描述 |
|---|---|---|---|
binding |
plain |
xsd:dict |
一个 binding 对象 |
host_id |
plain |
xsd:string |
分配端口的主机名。 |
vif_type |
plain |
xsd:string |
在此端口绑定期间确定的 VIF 类型 |
vif_details |
plain |
xsd:dict |
包含此特定绑定的其他详细信息的字典。详细信息由机制驱动程序设置。 |
vnic_type |
plain |
xsd:string |
此端口绑定的 VNIC 类型。 |
profile |
plain |
xsd:dict |
包含 vif 配置文件。 |
status |
plain |
xsd:String |
绑定的状态 状态用法 |
{
"binding": {
"host_id": "target-host_id",
"vif_type": "target-vif-type",
"vif_details": {
"port_filter": true,
},
"vnic_type": 'NORMAL',
"profile": {},
"status": "active"
}
}
显示绑定的重要关键特性
DVR 端口在此资源中显示,将显示分布式端口的实际 vif_type,如它们存储在 DistributedPortBindings 中,即 ovs。
创建绑定¶
POST /v2.0/ports/{port_id}/bindings
参数 |
风格 |
类型 |
描述 |
|---|---|---|---|
binding |
plain |
xsd:dict |
一个 binding 对象 |
host_id(必需) |
plain |
xsd:string |
分配端口的主机名。 |
vnic_type(可选,默认 = ‘normal’) |
plain |
xsd:string |
此端口绑定的 VNIC 类型。 |
profile(可选) |
plain |
xsd:dict |
包含 vif 配置文件。 |
{
"binding": {
"host_id": "target-host_id"
}
}
响应参数
参见 列出绑定
{
"binding": {
"host_id": "target-host_id",
"vif_type": "ovs",
"vif_details": {
"port_filter": true,
"ovs_hybrid_plug": true
},
"vnic_type": 'NORMAL',
"profile": {},
"status": "active"
}
}
如果绑定失败,应返回新的 4xx 或 5xx 返回代码。这与今天不同,失败的绑定返回 2xx 响应代码,并且 vif_type 设置为“binding_failed”。
更新/创建绑定的重要关键特性
默认情况下,创建端口绑定时状态将为活动状态。如果创建绑定,不存在,并且已经存在活动绑定,则绑定将默认为非活动状态,需要操作员激活新的绑定。
如果正在添加的绑定已经存在,将返回 4xx。
计算端口一次只能有一个活动绑定。这不是 Neutron 的强制执行,而是 PortBinding 周围操作的结果。此功能扩展了具有多个绑定的 capability,但仅允许计算端口有一个活动绑定。
此时,创建绑定将限制为计算端口。
现有 API 未受影响,将返回 host_id:{host_id} 作为当前活动绑定。
激活非活动计算绑定将停用当前活动绑定。
更新绑定¶
PUT /v2.0/ports/{port_id}/bindings/{host_id}
参数 |
风格 |
类型 |
描述 |
|---|---|---|---|
binding |
plain |
xsd:dict |
一个 binding 对象 |
所有创建参数都适用于更新。参见 创建绑定。
{
"binding": {
"vnic_type": 'NORMAL',
"profile": {}
}
}
响应参数
参见 显示绑定
{
"binding": {
"host_id": "target-host_id",
"vif_type": "ovs",
"vif_details": {
"port_filter": true,
"ovs_hybrid_plug": true
},
"vnic_type": 'NORMAL',
"profile": {"foo": "bar"},
"status": "active"
}
}
绑定失败时,应返回 4xx 或 5xx 返回代码。
激活非活动绑定¶
PUT /v2.0/ports/{port_id}/bindings/{host_id}/activate
响应参数
参见 显示绑定
{
"binding": {
"host_id": "target-host_id",
"vif_type": "ovs",
"vif_details": {
"port_filter": true,
"ovs_hybrid_plug": true
},
"vnic_type": 'NORMAL',
"profile": {"foo":"bar"},
"status": "active"
}
}
激活绑定的重要关键特性
激活处于非活动状态的计算绑定将停用现有的活动绑定,因为计算端口一次只能有一个绑定处于活动状态。
操作将限制为计算端口。
尝试激活现有的活动绑定将返回 4xx。
激活绑定失败时返回 5xx。
删除绑定¶
DELETE /v2.0/ports/{port_id}/bindings/{host_id}
此操作不接受请求体,也不返回响应体。
删除绑定的重要关键特性
可以删除活动/非活动绑定。
删除活动计算端口绑定,其中存在非活动绑定,不会激活绑定。操作员需要显式激活绑定。
现有 API 与新 API 的重叠¶
现有 API 的所有功能都包含在新 API 中。本节描述了重叠。
现有 API |
新的 API |
显示具有活动绑定的端口 |
n/a |
创建端口:直接使用活动绑定 |
n/a |
更新端口:添加 host_id(添加活动绑定) |
添加绑定 |
创建端口:没有绑定 |
n/a |
更新端口:更改 host_id(重新触发另一个主机的端口绑定) |
更新绑定 |
更新端口:将 host_id 设置为‘’(删除活动绑定) |
删除活动绑定 |
删除端口:删除所有绑定的端口 |
n/a |
现有 API 的影响¶
对现有 API 的轻微调整
显示端口将仍然像今天一样显示绑定。对于计算端口,它只会显示活动绑定。
创建端口将创建未绑定的绑定,状态为活动状态。
使用 host_id 更新端口将仍然重新触发主机的端口绑定。update_port() 的区别将仅对活动绑定采取行动。
通过现有端口绑定扩展触发绑定时,端口绑定失败时 vif_type 设置为“binding_failed”,并且仍然使用 http 代码 2xx。
API 可见性¶
普通用户不应能够触发任何创建/更新/删除/激活操作。这应该只能通过一些特殊的服务用户或管理员角色来完成。
子资源扩展¶
Neutron ports 将使用子资源 bindings 扩展,具有成员名称 port 以保留 portbindings 和 ports 扩展。新的子资源扩展将是 portbindings_extended.py,并且具有父资源 ports。
以下方法将添加到新创建的服务插件 bindings_plugin.py
get_port_bindings()
get_port_binding()
create_port_binding()
update_port_binding()
delete_port_binding()
update_port_binding_activate()
ML2 更改¶
现有方法 create_port() 和 update_port() 需要更新以支持仅对状态为 active 的绑定采取行动。此外,将在 neutron-lib 中引入一个新的状态 inactive 用于 PortBinding。
状态用法¶
PortBinding 中的状态列将存储一个额外的状态“inactive”,其中当前状态为“active”和“down”。Neutron-lib 只需要添加 PORT_BINDING_STATUS_ACTIVE 和 PORT_BINDING_STATUS_INACTIVE。
from neutron_lib import constants as const
const.PORT_BINDING_STATUS_ACTIVE
const.PORT_BINDING_STATUS_INACTIVE
创建/更新/删除端口¶
为了支持新的子资源,将在端口下引入新的方法,但当前的 create_port()、update_port() 和 delete_port() 将被修改为仅对 PortBinding 表中的 active 绑定起作用。
目前,create_port() 在 PortBinding 中添加一个未绑定的空绑定,为了支持此规范,将进行以下更改
在 PortBinding 表中创建一个状态为 active 的未绑定绑定。
此外,update_port() 将针对 active 状态进行调整,具体更改如下
更新将仅更改 PortBinding 表中 active 绑定的绑定信息。
最后,delete_port() 将针对 active 状态进行调整,具体更改如下
删除将仅对 PortBinding 表中的 active 绑定起作用。
数据模型变更¶
PortBinding 表将扩展主键到 column host,允许基于 port_id 和 host 选择绑定。
此外,将在扩展中引入一个 status 列,其中状态 active、down 和 inactive 将作为值。
在线升级,Blueprint [9],需要将 host 添加到 primary_keys,以及为 Port Binding OVO 添加一个新字段 status。如果 Blueprint [10] 中的 push-notifications 首先被合并,并且 PortBinding 对象存在于 RPC 线上,则应增加对象版本。为 status 字段定义默认值将不需要在线数据迁移。
机制驱动程序变更¶
需要一个新的机制驱动程序方法来确定是否支持绑定事物的新方式。必须针对所有绑定级别进行验证,并允许回退到以前的方法。默认情况下,新方法将返回 unsupported。
除了 l2 代理(ovs、lb、sr-iov、macvtap)的树内机制驱动程序之外,还需要考虑以下驱动程序
l2pop(但是,有想法消除 l2pop)
ironic
第三方机制驱动程序
激活 RPC 端口更新/删除¶
现有的 port_update 和 port_delete RPC 消息将被调整为在代理使用 get_devices_details_list_and_failed_devices 获取设备信息时,无论绑定状态如何,都发送特定于主机的绑定信息。这将允许发生以下附加管道:
激活将导致 port_update,它将传递主机相关的绑定信息,并指示从 inactive 到 active 的过渡,在 get_devices_details_list_and_failed_devices 响应中。这将允许发送 GARP,更新拓扑到状态更改。
激活将导致向源主机发送 port_delete rpc 调用,删除源 VIF。由于 Nova 无法发出删除端口,因为端口仍然存在于另一台主机上,因此需要完成此操作。绑定将保持在 inactive 状态,其中已填充绑定信息,但从代理的角度来看,端口将不存在。此外,从 active 到 inactive 的过渡将在 rpc 调用中指示,影响 update_device_list 不更新端口状态。
在 Blueprint [10] 下为端口实现 push-notifications 的情况下,get_devices_details_list_and_failed_devices 将不会针对过渡状态进行调整。相反,绑定过渡状态将作为端口对象的一部分发送到代理。其余操作相同。
其他变更¶
Neutron/Openstack Python Client 支持。
Neutron-Lib 支持新的常量 PORT_STATUS_INACTIVE,请参阅 激活非活动绑定。
命令行客户端影响¶
需要在 OSC 中支持端口绑定。将添加以下内容
$ openstack port binding list {ARGS} <port>
$ openstack port binding show {ARGS} <port> <host>
$ openstack port binding create {ARGS} <port>
$ openstack port binding update {ARGS} <port> <host>
$ openstack port binding delete {ARGS} <port> <host>
$ openstack port binding activate {ARGS} <port> <host>
安全影响¶
无。
通知影响¶
无。
其他最终用户影响¶
无。
性能影响¶
不应有性能影响。
IPv6 影响¶
无。
其他部署者影响¶
无。
开发人员影响¶
对 Nova 实时迁移的影响,并直接支持他们的努力。
社区影响¶
是的。此更改已在 ML 上讨论,在 Neutron 会议(尤其是 ML2)、中期会议和设计峰会上讨论过。
备选方案¶
另一种选择是使用端口下的当前资源来促进此更改以进行实时迁移。问题是,需要扩展当前的字典结构以适应“bindings”键。这可能会引起一些混淆,因为用户已经收到“bindings:profile”和各种其他值。
实现¶
负责人¶
主要负责人:* Jakub Libosvar
请在此处添加您的姓名,如果您想参与贡献,请参加 ML2 子团队会议。
依赖项¶
无。
测试¶
Tempest 测试¶
添加场景测试,test_bindings.py,以遍历创建源迁移实例、在辅助主机上创建非活动绑定、创建辅助目标迁移实例、激活非活动绑定、停用源迁移活动绑定,然后验证连接是否仍然有效。
功能测试¶
将向 ml2/test_plugin.py 添加额外的功能测试,以扩展当前的端口绑定测试。这将适应在添加非活动绑定时进行状态检查。
API 测试¶
绑定资源(CRUD)
绑定资源(CRUD)以及在当前端口扩展下的活动绑定验证。
文档影响¶
是的。
用户文档¶
无。
开发人员文档¶
在 devrefml2_port_bindings.rst 中创建有关 active/inactive 绑定操作的详细说明。这应详细说明对 ml2 的更改以及扩展的 ports 资源。