强化计算节点主机名处理¶
包含您的 Launchpad 蓝图的 URL
https://blueprints.launchpad.net/nova/+spec/example
Nova 长期以来依赖于计算节点上不变的主机名。本规范旨在解决此限制,至少从检测意外更改并避免数据库中可能因主机名更改(无论是故意的还是意外的)而导致的灾难的角度来看。
问题描述¶
目前 nova 使用计算节点的主机名(特别是 CONF.host)用于多种用途
作为通过 RPC 与计算节点通信的路由键
作为数据库中实例、服务和计算节点对象之间的链接
为了让 neutron 将端口绑定到正确的主机名(在某些情况下,它必须与 neutron agent 配置中的等效设置匹配)
为了让 cinder 将卷导出到正确的主机
作为 placement 中的资源提供者名称(这实际上来自 libvirt 的主机名概念,而不是
CONF.host)
如果计算节点的主机名发生更改,所有这些链接都会中断。 在使用更改后的名称启动计算节点时,我们将无法在数据库中找到匹配的 nova-compute Service 记录,并创建一个新的记录。 之后,我们将无法找到匹配的 ComputeNode 记录并创建一个新的记录,并带有新的 UUID。 引用旧计算节点和服务的记录的实例将不会与正在运行的主机关联,因此无法通过 API 进行管理。 此外,在重命名后在计算节点上创建的新实例将能够声明已承诺给孤立实例的资源(例如 PCI 设备和 VCPU),因为这些资源的跟踪与旧计算节点记录相关联。
如果孤立实例相对静态,那么首先指示出现问题的时间可能是在实际重命名之后很长时间,那时现实已经分叉,并且在不同的计算节点上运行的实例引用了两个不同的计算节点记录,因此在两个不同的位置进行了统计。
此外,neutron、cinder 和 placement 资源将拥有现有实例的旧信息和当前实例的新信息,这需要协调。 这种状况也可能阻止重启旧实例,如果旧主机名已无法访问。
用例¶
作为操作员,我希望确保我的数据库不会因临时或永久的 DNS 更改或中断而损坏
作为操作员,我可能需要在我的网络演进多年后更改计算节点名称。
作为部署工具编写者,我希望确保工具和库中的更改绝不会导致数据丢失或数据库损坏。
提议的变更¶
我们可以在这里做很多事情来增强 Nova 处理此数据的方式。 每一种方法都会提高安全性,但我们不必全部执行。
确保稳定的计算节点 UUID¶
对于非 ironic virt 驱动程序,每当我们生成计算节点 uuid 时,都应该将其写入本地磁盘上的文件。 每当我们启动时,都应该查找该 UUID 文件,使用它,并且在任何情况下都不应该生成另一个 UUID。 为了便于部署工具预生成此文件,如果这是第一次启动,我们应该使用它并创建数据库中的 ComputeNode 记录。
我们将实际的计算节点 UUID 查找放在 virt 驱动程序的 get_available_nodes() 方法中(或创建一个新的 UUID 专用方法)。 ironic 将使用其当前实现覆盖此方法,该实现根据 ironic 的状态和哈希环返回 UUID。 因此,只有非 ironic 计算节点才会读取和写入持久的 UUID 文件。
单主机 virt 驱动程序(如 libvirt)能够容忍系统主机名更改,更新 ComputeNode.hypervisor_hostname 而不会破坏任何事情。
通过 id 链接 ComputeNode 记录与 Service 记录¶
目前,ComputeNode 和 Service 记录在数据库中纯粹通过主机名字符串关联。 这意味着它们可能会被分离,并且从性能角度来看也不是理想的。 其他一些数据结构通过 id 与 ComputeNode 链接,因此当名称匹配时,它们不会被重新关联。
这种关系曾经存在,但在 Kilo 时间框架中被 移除。 我认为这是由于希望使流程更专注于服务对象而不是计算节点(可能因为 ironic),尽管打破这种紧密关系也有严重的缺点。 我认为我们可以为单主机计算节点保留紧密绑定,在有意义的情况下。
在启动时,nova-compute 应该通过持久的 UUID 解析其 ComputeNode 对象,找到关联的 Service,如果主机名与 CONF.host 不匹配,则启动失败。 由于这与外部服务一起使用,我们不应该只是“修复它”,因为其他链接也会中断。 这至少可以让我们避免打开静默数据损坏的窗口。
通过 id 链接实例到 ComputeNode¶
目前,实例记录纯粹通过主机名与它们的 Service 和 ComputeNode 对象链接。 我们应该通过其 id 将它们链接到 ComputeNode。 由于我们需要 Service 才能获得 RPC 路由键或在与外部服务通信时进行主机名解析,因此我们应该基于 Instance->ComputeNode->Service id 关系找到它。
我们已经通过 id 将实例的 PCI 分配链接到计算节点,即使实例本身通过主机名链接。 这种差异很容易使两者不同步。
未来的潜在变化¶
如果进行上述更改,我们将为支持以下内容打开可能性
如果计算主机真的需要更改其主机名,则通过 API 重命名服务对象。 这将需要同时更改其他服务,但 nova 至少将拥有主机名的单一事实来源,使其可行。
如果我们做到这一切,Nova 可能会对有意的重命名有足够的信心,从而更新端口绑定、cinder 卷附件和 placement 资源,使其无缝进行。es
如果需要,将 RPC 路由键迁移到使用服务 UUID。
删除数据库中的大量重复字符串字段。
备选方案¶
我们也可以什么都不做。 计算主机名一直无法更改,现状是“不要这样做,否则会破坏”,这当然是我们也可以继续依赖的事情。
我们可以实现其中的一部分(例如,持久的 ComputeNode UUID),而无需其余的数据库更改。 这将允许我们检测到这种情况并中止,但没有(获得更强大的数据库模式的好处,该模式可能也支持自愿重命名)的工作量。
数据模型影响¶
这里的大部分影响是 Instance、ComputeNode、Service 的数据模型。 其他引用计算主机名的模型也可能值得更改(尽管完全推迟或推迟到不同阶段也是合理的)。 示例
迁移
InstanceFault
InstanceActionEvent
TaskLog
ConsoleAuthToken
此外,主机聚合使用服务名称进行成员资格。 迁移到 UUID 是不可能的,因为多个单元会导致重叠。 我们可以将它们迁移到 UUID 或简单地忽略这种情况,并假设未来的任何实际重命名操作都将涉及 API 操作来修复聚合(这是可行的,不像更改 Instance 等事物的宿主)。
REST API 影响¶
对于此,没有特定的 REST API 影响,除了将来可能启用可变的 Service 主机名之外。
安全影响¶
没有影响。
通知影响¶
没有影响。
其他最终用户影响¶
对最终用户不可见。
性能影响¶
理论上,基于整数的链接在这些对象之间存在一些好处,而这些对象当前通过字符串链接。 最终,我们可以减少数据库模式和占用空间中的大量字符串重复。
由于需要进行在线数据迁移才能迁移到更强大的模式,因此肯定会产生一次性性能影响。
其他部署者影响¶
这实际上是对部署者的好处。
开发人员影响¶
在过渡期间,数据库模型会发生一些变化。 查找实例的主机名需要 Instance->ComputeNode->Service,但可以通过在 Instance 对象中添加辅助程序来隐藏,这样实际工作流程中就不需要进行太多更改。
升级影响¶
需要进行一些大量在线数据迁移才能使事物进入新的模式,并且只有在所有内容都转换后才能实现好处。
实现¶
负责人¶
- 主要负责人
danms
工作项¶
在生成时将计算节点 UUID 持久保存到磁盘。 如果存在该位置,则在查找是否需要生成、创建或查找现有节点记录之前,从该位置读取计算节点 UUID。
更改计算节点启动过程,以便在检测到不匹配时中止
进行模式更改以通过 id 链接数据库模型。 ComputeNode 和 Service 对象/表仍然具有我们可以重新启用的 id 字段,而无需对这些字段进行模式更改。
如果存在基于 ID 的链接,则使数据模型尊重这些链接
编写在线数据迁移以在现有数据库上构建这些链接
稍后,将会有工作项来:* 删除遗留列 * 潜在地实现实际的服务重命名过程
依赖项¶
这项工作的基本工作没有外部依赖项,但它依赖于发布周期,这会影响我们实施此工作并放弃旧方法的速度。
测试¶
对于实际的计算节点启动行为,单元和功能测试应该没问题。 现有的集成测试应该确保我们没有破坏任何运行时行为。 Grenade 作业将测试数据迁移,我们可以实施一些 nova 状态项来帮助验证升级作业中的内容。
文档影响¶
需要为部署者和工具作者记录持久的计算节点 UUID 文件。 理想情况下,此操作的唯一可见结果是,如果计算服务检测到意外的重命名,则会出现一些额外的故障模式,因此记录这些故障模式以及如何处理它们会很有帮助。
参考资料¶
TODO(danms):可能存在我们可以参考的关于计算节点重命名不可能或有问题(如果发生)的错误。
历史¶
发布名称 |
描述 |
|---|---|
Antelope |
引入 |