vendordata reboot

https://blueprints.launchpad.net/nova/+spec/vendordata-reboot

Nova 团队希望停止动态加载 Python 模块以在元数据服务和 configdrive 中实现 vendordata。相反,我们建议提供一个可以从外部 REST 服务器获取动态 vendordata 的模块。

问题描述

Nova 通过称为元数据的机制向其启动的实例提供配置信息。这些元数据通过 configdrive 或元数据服务提供。这些机制被广泛用于 cloud-init 等辅助工具,以指定诸如实例应使用的 root 密码之类的信息。

Nova 当前支持元数据中添加“vendordata”的机制,这些 vendordata 将传递给实例。vendordata 当前由单个模块提供,该模块通过一个标志“插入”到元数据服务器中,该标志是 Python 模块的路径。Nova 源代码中当前只有一个实现,它获取静态 JSON 文件并将其添加到元数据中。

Nova 团队对这种插入 vendordata 扩展的机制表示担忧,因为所使用的 Python 接口不稳定,如果更改调用的参数,我们不知道会破坏哪些外部用户。此外,在我们的进程中运行树外代码出于安全原因是不受欢迎的。

相反,Nova 团队建议将 vendordata 支持更改为仅加载 _命名的_ 模块,这些模块必须出现在 Nova 源代码中。我们将提供一个能够对外部服务进行 REST 调用以获取 vendordata 的模块,以及一个部署者可以扩展的该外部服务的示例实现。

为什么不能通过启动请求期间的用户数据提供此动态 vendordata?有时这些信息在启动时是未知的,或者不是实例的最终用户可以合理地期望知道的信息。例如,注册实例到 Active Directory 所需的加密元素,最终用户可能没有生成这些元素的权限。

用例

静态 vendordata 在部署者希望指定始终为他们的云真实,但无法用传统元数据表达的事项时很有用。例如,这可能是他们的公司 LDAP 服务器的 IP 地址。

动态 vendordata 对于特定于给定实例的信息很有用,但无法通过元数据模式表达。例如,这可能是实例在启动后才能注册到 Active Directory 实现所需的加密元素。

提议的变更

  • 弃用加载 vendordata 的 Python 模块。不过,目前不要删除此支持。这已经完成。

  • 添加一个新的标志,vendordata_providers,它是一个将 vendordata 添加到实例元数据的模块名称列表。当前的 vendordata_json 模块将以“StaticJSON”的形式出现在此列表中。

  • 添加一个新的模块,它挂钩名称“DynamicJSON”,并且具有一个标志来配置一个 REST 微服务的 URL 列表,这些微服务提供动态元数据。

我们需要确保实现 DynamicJSON 的模块对 REST 微服务中的 HTTP 缓存标头执行一些有意义的操作。这些标头可用于管理 Nova 侧的缓存,以尽可能减少由于重复请求给微服务的负载。此外,REST 微服务的 SSL 验证可能需要与我们用于其他服务的 SSL 验证不同,因为这些服务可能仅供内部使用并使用自签名证书。此行为应由一个标志控制。

DynamicJSON 还需实现 HTTP 请求超时,以防 REST 微服务在合理的时间内没有响应。在这种情况下,vendordata 将在没有该微服务的条目(换句话说,在下面的示例中根本没有键)的情况下创建,并且实例启动将继续。

我们传递给 REST 微服务哪些数据?目前认为我们应该提供以下属性

  • 项目ID

  • 镜像 ID

  • 实例 ID

  • 已定义的所有用户数据

这些数据将作为 JSON 编码的 POST 发送到 REST 微服务。

如何处理将新数据添加到传递给微服务的数据集中?我确信在未来我们会发现需要传递给微服务的额外数据。但这问题不大——我们可以将数据添加到我们传递的数据集中,而删除数据会更困难。因此,部署者可以根据需要请求传递额外的,只要他们确保处理缺少这些数据的情况,直到他们升级所有内容,一切都会顺利进行。

如何让微服务知道 Nova 正在发出真实的请求?我们建议将调用者提供给 Nova 的令牌作为我们的调用的一部分传递给微服务,就像将客户端的令牌传递给 Cinder、Glance 或 Neutron 一样。这将允许微服务确保客户端有权执行微服务实施的操作。这意味着微服务需要能够实施 keystone 身份验证——对于使用 WSGI 编写的 Python 微服务来说,这当然是事实,它们应该能够使用现有的中间件。我们认为 Go 和 Java 也有 keystone 客户端实现。

如何处理来自多个服务的元数据?为了保持向后兼容性,任何定义的 StaticJSON 都会出现在元数据中的一个名为 vendor_data.json 的文件中。

对于 DynamicJSON,对微服务的调用的结果将被放置到元数据中的一个新 JSON 文件中,该文件名为 vendor_data2.json。此文件包含一个字典,该字典是一系列字典。例如

{
    "static": {
        "bar": "2",
        "foo": "1"
    }
}

在此示例中,您可以看到静态 JSON 也包含在此新文件中,这提高了人们最终只需要读取一个文件即可获取所有 vendordata 的希望。每个 REST 微服务都通过将新项目附加到 vendordata_dynamic_targets 标志中提供的列表中来配置。此标志由以下形式的条目组成

name@http://example.com/foo

此微服务的名称元素成为 vendor_data2.json 文件中的一个新键,如下所示

{
    "name": {
        "fancy": "pants"
    },
    "static": {
        "bar": "2",
        "foo": "1"
    }
}

假设部署者将确保一个名称仅出现在一个微服务中。重复的名称将在运行时被处理为错误,从而阻止实例启动。

如果 REST 调用返回 {},则在 vendor_data2.json 中创建一个空条目。

备选方案

有人提出我们可以使用添加到用户请求中的 WSGI paste 中间件来实现动态 vendordata 之类的功能,该中间件捕获来自用户的 nova 启动请求,并在将请求传递给 nova-api 之前添加额外数据。这存在一些问题

  • 它很可能不可靠,因为它实现起来对新手来说并不明显。

  • 该代码将在 nova 进程中运行,这是不可取的。

  • 用户数据存储在 nova 数据库中,这对于加密数据来说是不希望的。

  • 有人告诉我,这个提议是 Sean Dague 听过的最糟糕的提议,并且他不得不服用安定才能继续对话。我对此感到有点冒犯。因此,已经表明通过中间件实现此功能可能会伤害 nova 核心的感情,我们不能那样做。

数据模型影响

REST API 影响

Nova REST API 没有影响。外部 REST 服务器将有一个新的、非常小的 API,但这被认为是一个小问题。

安全影响

我们将不再在 nova 数据库中存储机密信息,就像人们使用用户数据来实现等效功能时一样。此外,nova 的任何进程都不需要对任何公司系统具有特权访问权限,因为这些权限已转交给 REST 微服务。这减少了公司系统管理员需要担心保护的表面积。

通知影响

其他最终用户影响

性能影响

存在外部 REST 微服务在发出请求时可能关闭或速度非常慢的风险。我们可以使用超时来确保 nova 启动过程不会受到严重降级。这可能会导致实例缺少它们在启动后需要的所有数据,但这超出了 nova 的控制范围。

一些元数据服务器用户非常频繁地请求元数据,这可能会导致外部 REST 服务承受沉重的负载。但是,该微服务的部署者可以使用缓存和负载均衡等技术来缓解这些问题。Nova 还会实现对 REST 服务响应中的 HTTP 缓存标头的处理,以尝试减少我们需要调用 REST 服务的次数。

其他部署者影响

对于使用动态 vendordata 的部署者,他们需要维护另一个 REST 服务。

开发人员影响

实现

负责人

主要负责人

mikal

其他贡献者

工作项

  • 编写 Nova 对此功能的支持。

  • 提供一个示例外部 REST 微服务,可能不在 Nova 源代码树中。

  • 为 devstack / tempest 添加测试支持。

依赖项

测试

我们应该通过将示例 REST 微服务添加到 devstack 并添加至少一个 tempest 测试来验证所有内容是否从端到端正常工作来测试此功能。

文档影响

需要扩展管理指南以解释此功能。

参考资料

这项工作是由在阳光明媚的奥斯汀举行的 Newton 设计峰会以及 openstack-operators 线程促成的

历史