使用托管联邦和GraphOS部署API更改
确保版本发布顺畅并最小化对客户端的影响
联邦GraphQL API是一种多层架构,由独立的组件组成。GraphQL请求通过多个组件流过以构建一个响应,然后通过这些相同的组件返回,以回报给调用者,如下图所示:
允许团队独立更新他们拥有的组件是一个关键优势。然而,了解并降低对组件进行更改的风险可能会很具有挑战性,尤其是因为更改可能需要其他组件的级联更改。这对于 GraphQL模式 定义尤其如此,这些定义必须在 子图 服务和 路由器 之间协调。
这份 文档 将涵盖基本发布步骤,这些步骤涉及对现有 supergraph API. 我们不会深入探讨对运行时代码或 router 运行时配置的更改部署。具体来说,我们将研究两个场景,这两个场景都涉及到对现有联邦 API 模式
此指南假定了一般使用 Apollo GraphOS 及其一部分特定功能:
- 托管聚合 用于在运行时将 supergraph 模式传播到您的 Router。
- Rover 用于发布 子图模式 并执行 模式检查
- GraphOS Studio 以查看 GraphOS 指标并确定何时可以安全地删除 field。
每种场景的发布指南通常适用于所有发布管理系统,无论我们是在部署到 Kubernetes、 无服务器 或 bare metal。某些细节可能因我们是否有手动部署过程,持续交付过程或两者之间的某种过程而有所不同。
向后兼容的子图模式更改
如果模式更改不影响现有 operation,则它是向后兼容的。一些向后兼容更改的例子包括:
- 添加一个类型或 field(直到客户端在新操作中包含字段之前,它未被使用)
- 向现有字段添加一个可选的 argument,最好提供一个默认值(当客户端在新操作中使用该参数时,该参数将为 null 或默认值)
- 将可为空的 field 变为不可为空(这限制了可能输出的值的集合)
- 删除或更改未使用的模式元素(如果现有 operation 将被打断)
ⓘ 注意
这还包括对模式元数据的更改,如添加或更改弃用或描述,但我们不会考虑这些更改,因为它们不影响运行时行为。
发布步骤
向后兼容更改的发布步骤如下
- 在子图代码仓库中,将包含模式更改和相应解析器的更改集合并入发布分支,触发发布管道。
- 发布管道执行预发布步骤,例如运行测试和模式检查。
- 发布管道构建可部署的工件
- 运行时代码的容器、jar 或 zip
- 部署清单,例如 Kubernetes YAML 或 SAM 模板
- 子图的SDL 文档
- 发布管道随后将触发两个连续的“部署”。
- 运行时代码的滚动部署。
- 将子图的SDL 文档发布到 Apollo GraphOS,然后更新路由器以新的超级图模式 (如果子图成功组合;更多内容稍后介绍)。
- 发布管道执行后发布步骤,如抽检。
序列化模式发布与服务部署
在步骤 4 中,我们的系统最有可能进入一个不一致的状态,其中'路由器'的版本文档与子图版本文档不同步。
当子图首先更新时,客户端可以请求新的模式元素,并且由于它还不知道更改,路由器将引发一个操作验证错误。
然而,在实践中,这很少重要。由于 GraphQL 的声明性特质,客户端必须更新其操作以使用新的模式元素。客户端不会轮询他们模式的内省响应来发现新字段并立即请求它们。另外,Apollo 建议在生产环境中禁用内省。只有在系统达到一致状态后,我们才会向客户端宣布这些新模式元素的可用性。
如果我们启用模式更改通知,Apollo GraphOS 将在路由器接收到更新的超级图模式后自动通知我们的同事,该新模式已可用。
并发子图模式更改
我们大部分时间可以专注于单个子图,但可能遇到两个或更多子图更改时的冲突。考虑以下事件序列:
- 团队 A 对子图A进行了更改。CI 中的构建检查成功,他们合并了代码。
- 团队B对子图B进行了修改。即使在CI中构建检查也成功了,但实际上它与子图A中的修改冲突,因为构建检查是针对已发布的模式定义运行的。
- 团队B将他们的更改发布到生产环境中。
- 团队A尝试发布他们的更改,但他们的新子图模式无法编译,并且路由器没有更新。
解决方案是在流程早期遇到构建错误。一旦团队A合并了一个更改集,团队B就应该运行对该变更的构建检查。
我们可以通过创建一个特殊的版本来跟踪我们图的主分支。Apollo GraphOS提供了用于此用例的默认版本称为current,但任何版本都可以用于这个目的。这需要以下条件:main
每个代码仓库的分支。Apollo GraphOS提供了一个默认版本称为current
专门用于此用例,但任何版本都可以用于此目的。这需要以下条件:
- 每次我们将更改合并到
main
分支时,每个仓库都立即将子图模式发布到current
版本,即使我们有一段时间不会发布更改。 - 我们对提议的更改运行针对
current
版本的构建检查(以快速捕捉构建错误),还包括我们的生产版本(以在实时流量上运行操作检查)。
如果针对current
版本的构建检查失败,我们需要与其他子图团队协调,确保在尝试将更改发布到生产之前,我们的子图模式是兼容的。
ⓘ 注意
从合并到发布我们的更改之间的时间越长,使用current
版本跟踪变更就越重要。另一方面,如果我们有一个持续交付的发布流程,并且合并和发布之间的时间相对较短,团队引入与未发布子图架构不兼容的变更的可能性就较小。
回滚
一旦客户端开始使用新的模式更改,回滚子图架构更改就像制作向后不兼容的架构更改一样。这取决于客户端的使用可能难以或无法完成。因此,在客户端开始在他们的操作中使用新架构之前,测试我们的新架构更改非常重要。
如果客户端尚未使用架构更改,我们很可能不需要回滚它们——它们在操作开始使用它们之前没有影响。
如果情况需要回滚,最安全的流程是在子图代码存储库中回滚更改并执行完整的发布流程,一起发布子图架构和推出新代码。
分阶段架构更改发布
与其尝试回滚架构更改,我们可以选择分阶段发布更改,如alpha、beta以及通常可用(GA)。GraphOS的合约功能使此过程变得简单:
使用指向目标发布的 '@tag' 指令标记我们的架构元素:
type Product {id: ID!newField: String @tag(name: "alpha")}配置我们的GA 版本为过滤掉所有标记为“alpha”或“beta”的字段的合约。
配置单独的beta版本,排除“alpha”标记,并配置另一个不排除任何内容的alpha版本。
设置三个单独的路由器,分别使用alpha、beta和GA 版本。
执行标准发布流程。因为我们已将新字段标记为“alpha”,所以beta和GA 版本的架构不会更改。这为我们提供了大量机会,可以通过客户端的alpha版本测试我们的更改。
向更广泛的受众发布更改很简单,只需将标记更改为“beta”或完全删除。
💡 提示
有关合约使用模式的更多信息,请参阅合约使用模式。
不兼容的子图模式更改
向后不兼容的架构更改以会破坏现有操作的方式删除或更改架构元素。
关键在于,如果一个架构元素未被使用,这并不意味着它是一个与旧版本不兼容的变更。
发布步骤
向后不兼容的变更的发布步骤与向后兼容的变更类似,但需要一些重要的前期工作。
- 使用
@deprecated
指令来告知客户端,架构元素不应再依赖。 - 使用 GraphOS Studio 跟踪类型和域的用法。在发布变更之前,联系已识别 实施影响的操作的客户端。
- 继续跟踪使用情况,直到降至零(或达到最低可接受水平,例如,域仍由不再支持的旧版移动应用程序使用)。
- 执行向后兼容变更的发布步骤。
💡 提示
考虑强制要求所有对您的 supergraph 的请求具有适当的标识头。这些标识符启用了允许您有信心进行可能中断的变更的指标。有关客户端意识的更多信息,请在此处阅读。参看客户端 ID 强制执行以获取示例实现。
序列化模式发布与服务部署
与向后兼容的发布一样,我们的系统最有可能最终处于不一致的状态,其中 路由器's 的架构版本与 子图 's 版本不同步。
当超级图在路由器中更新时,它将不再验证包含已删除 字段 的请求,或以现在被标记为非空值的空值响应。
通过上述前期工作,我们已尽可能减少或完全消除了造成这些错误的需求。
回滚
假设我们已执行前期工作并降低了相关类型和域的使用,再进行更改/删除,撤销我们的更改实际上是一个向后兼容的架构变更。
如果情况需要回滚,最安全的流程是在子图代码存储库中回滚更改并执行完整的发布流程,一起发布子图架构和推出新代码。
关键要点
- 将变更类型与其他类型分离。在可能的情况下,不要同时发布架构变更和实现/配置变更。
- 在合并代码后立即 将子图架构发布到“当前”版本,并对“当前”版本进行构建检查以捕获生产发布之前的子图兼容性问题。 (合并和部署之间的延迟越长,此步骤就越重要。)
- 在实际情况中,路由器/子图架构变更的排序并不像我们想象的那么关键,特别是如果我们使用像弃用工作流、使用报告和架构变更通知这样的工具来管理客户端操作。
- 将我们的 API 架构视为一个始终向前推进的文档。虽然必须支持代码和配置的回滚,但“回滚”已发布的 API 会对客户端和用户造成困惑。与其尝试支持 API 回滚,不如考虑为 API 更改实施分阶段部署流程。