通过 Istio 网格扩展功能为迁移提供支持:概念

本文是系列文章的第一部分,该系列探讨了如何使用服务网格将功能逐个从旧版环境(例如在虚拟机中运行应用的本地数据中心)迁移到 Google Kubernetes Engine (GKE)。

该系列文章包含这篇概念介绍文章和配套教程。 本文说明了迁移的基本原理,并概述了迁移的简要步骤。配套教程将指导您完成一次示例迁移。

简介

本文的目标读者是负责管理复杂基础架构,且希望在尽可能减少以下问题的前提下对其执行逐步迁移及现代化改造的 IT 专业人员:

  • 停机时间
  • 重构工作量
  • 网络运营复杂度

本文解释的概念适用于任何云环境,因此假设您熟悉云技术、容器和微服务。

混合云和多云模式及做法一文所述,迁移到云端主要有三种模式:直接原样迁移、改进并迁移、淘汰并替换。本文介绍了改进并迁移的一种模式,采用这种模式时,该模式会运用于应用的各个特性,而非运用于整个应用。

在迁移过程中,应用采用混合架构,其中一些特性位于 Google Cloud 上,而一些特性仍留在旧版环境中。迁移完成后,整个应用会托管在 Google Cloud 上。

术语

应用
在本文中,应用是指包含许多特性的一个完整软件系统。用户将每个应用视为一个单元。例如,图书销售网站就是一个应用。
特性

特性是应用的一个功能单元,例如书店应用中的书评特性。特性由多个微服务构成。

特性可以是“无状态”的,即不依赖于任何类型的数据;也可以是有状态的,即依赖于某些数据。

微服务

微服务是一种独立组件,旨在容纳应用的一项特性。在本文中,应用由用户无法区分的多个不同微服务组成。例如,处理图书评论的组件就属于一个微服务。

在微服务模式中,应用是多个微服务的集合,每个微服务具有一个特定目标。例如,您可能具有一个处理图书评分的微服务,另外还有一个处理图书评论的微服务。这些微服务应该松散耦合,且应通过明确定义的 API 相互连接。它们可以使用不同语言和框架进行编写(就像在 Polyglot 应用中一样),可以具有不同的生命周期。

如需进一步定义每个微服务的边界,可以使用以下工具对它们进行容器化:

服务网格

服务网格是将不同服务关联在一起的一种软件,可提供诸如服务发现、安全通信、负载平衡、流量管理、监控和可观察性等颇有价值的网络相关特性。

服务网格的典型实现是将每项服务与提供这些特性的代理配对。服务代理通常被称为“辅助资源” 。辅助资源的作用是增强和改进其附加到的应用,而应用往往不知道辅助资源的存在。

迁移

迁移是将旧版环境中运行的一个或多个应用的特性移动到目标环境(如 Google Cloud)的过程。在本文中,迁移可以是以下类型之一:

  • 一次性迁移:一次性迁移某个应用的全部特性。
  • 逐个特性的逐步迁移:一次迁移一个特性。
合规测试套件

合规测试套件是一组可针对某个环境运行的测试,用于检查此环境是否满足给定的一组要求。如果环境有效,则表示其符合要求。例如,您可以验证对测试请求的响应,还可以检查是否已安装应用的依赖项。

如需执行手动验证,您可以从监视、跟踪和服务网格可视化工具入手。然后,您可以实现测试套件,并不断对其加以完善改进:

  • 负载测试。您可以测试流量自动发送到环境并评估结果,以便改进测试套件。
  • 合规测试工具。您可以使用专用工具设计和开发测试套件。

为何选择逐步迁移策略?

由于在一次操作中迁移一个或多个应用存在较大的挑战和风险,因此一次性迁移极难实现。如果您的时间和预算有限,专注于一次性迁移只会导致您没有足够的时间和预算去开发新的应用特性。

相比之下,采用逐个特性的逐步迁移方法时,由于每个特性的覆盖面要小于整个应用,因此迁移工作负载的规模较小,整体复杂度也较低。逐步迁移方法让您可以通过多个较小规模的迁移实践来分散风险,避免采用一次性、高风险的迁移方案。此外,在采用逐步迁移方法时,迁移团队还能规划、设计和制定多项迁移策略,适应不同类型的特性。

将单体式应用迁移到 Google Kubernetes Engine 上的微服务中,您可以找到有关如何选择要优先迁移的特性、如何迁移有状态特性的指南。

为何使用服务网格?

服务网格将服务功能(业务逻辑的实现方式)从网络功能(如何以及何时将流量路由到服务功能)中分离开来。

在旧版环境中,大多数服务调用不会涉及到网络,因为这些服务调用是在同一个单体式平台中发生的。在微服务架构中,服务之间的通信要通过网络进行,服务必须妥善应对这种不同的模型。服务网格单独抽象出处理网络通信的功能,因此您不需要在每个应用中实现这类功能。 服务网格还能降低网络的操作复杂性,因为它提供了开箱即用的安全通信通道、负载平衡、流量管理、监控和可观测性功能。

随附的教程中使用 Istio 作为服务网格。Istio 具有如下特性:

  • 流量管理:借助针对 HTTP、gRPC、WebSocket 和 TCP 流量的丰富的路由规则,可对流量进行精细的控制。
  • 请求弹性特性:重试、故障转移、断路器和故障注入等请求弹性功能。
  • 可插入式政策层和配置 API,支持访问控制和速率限制。
  • 自动指标、日志和跟踪记录,适用于集群中的所有流量(包括集群入站流量和出站流量)。
  • 基于服务帐号进行的身份验证和授权,可保障服务到服务的通信安全。
  • 辅助各种测试和部署任务,如 A/B 测试、Canary 版发布、故障注入和速率限制等任务。

您还可以直观地查看服务网格。像 Kiali 这样的工具与 Istio 集成,以显示哪些服务属于服务网格,以及它们的连接方式。

以下屏幕截图展示了表示 Istio 网格的一个 Kiali 服务图示例。

表示 Istio 网格的 Kiali 服务图

通过部署和配置服务网格,您可以将流量动态路由到旧版环境或目标环境。流量管理对于网格中的服务是透明的,因此您无需修改应用配置即可支持迁移。

这种方法能够很好地处理无状态特性,但如果要迁移有状态、对延迟较为敏感或与其他功能高度耦合的特性,您需要进行额外的规划和重构:

  • 有状态特性。迁移有状态特性时,您必须同时迁移数据,从而最大限度地减少停机时间,并妥善处理迁移期间的同步和完整性问题。您可以通过将单体式应用迁移到 Google Kubernetes Engine 上的微服务详细了解数据迁移策略。
  • 延迟敏感型特性。如果某项特性在与其他特性通信时对于延迟较为敏感,那么在迁移过程中,您可能需要部署额外的组件。通常会使用能够预取数据或缓存层的代理来缓解这种敏感性。
  • 与其他特性高度耦合的特性。如果有两项或多项特性高度耦合,那么您可能必须同时迁移这些特性。虽然这种方法仍要比迁移整个应用简单一些,但与迁移单个特性相比,可能较为困难。

迁移计划

本部分介绍了一项使用服务网格执行逐个特性的逐步迁移的方案。该方案包括以下阶段:

  1. 评估旧版环境。
  2. 在目标环境中做好准备。
  3. 在目标环境中部署服务,并开始将流量路由至目标环境。
  4. 停止将流量路由到旧版环境。
  5. 停用旧版环境。

评估旧版环境

在执行任何迁移设计或实现活动之前,您需要评估旧版环境以收集信息,并为目标环境确定一组需求以及一项测试和验证基准。首先,您需要构建一个包含要迁移的所有应用特性的目录。对于每项特性,您都应该能够回答这组问题(并非详尽无遗):

  • 运行时环境是什么?有哪些性能要求?
  • 与其他特性是否存在依赖关系?
  • 是否属于业务关键型特性?
  • 属于无状态特性还是有状态特性?
  • 为了迁移此特性,预计需要执行多少重构工作?
  • 此特性能否承受切换期?

您可以详细了解评估过程以及要迁移的特性。然后针对旧版环境运行合规测试套件,将其结果作为基准,随后在迁移期间和迁移之后针对目标环境运行合规测试套件。

您的测试套件应侧重于在迁移期间执行以下几个方面的验证:

  • 预配。首先在环境中预配必要的资源,以便后续执行资源配置。
  • 配置。在环境中预配资源后,根据应用需求对其进行配置。采用一个配置测试套件,确保环境准备好托管您的应用。
  • 业务逻辑。验证环境的预配与配置之后,对应用的业务逻辑执行验证。例如,您可以验证对请求的响应情况。

InSpecRSpecServerspec 工具均可用于开发自动化合规测试套件。它们独立于平台,并且具有可扩展的特点,让您可以基于内置控件实现自己的控件。

下图展示了一个旧版环境示例:

旧版环境

预配目标环境

既然您已经充分了解了环境和待迁移的应用,接下来即可根据评估过程中设置的需求预配目标环境了。

在这个阶段中,您可以使用合规测试套件来验证目标环境。您可能需要在考虑到旧版环境与目标环境间根本差异(例如硬件和网络拓扑)的前提下更新测试套件。切记,您正在从由您全权掌控的本地环境迁移到公有云环境,而在公有云环境中,您通常不具备对整个堆栈的完整访问权限。

由于您要预配新环境,我们建议您采用基础架构即代码方法,让您的基础架构可审核、可重复且可自动预配。

下图展示了旧版环境和新完成预配(目前为空)的目标环境。

旧版环境和(空)目标环境

配置服务网格

下一步是设置跨越旧版环境和目标环境的服务网格。服务网格负责连接在旧版环境中运行且即将迁移到目标环境的各种微服务。在这个阶段中,服务网格是空的,等待服务进行注册。此时服务网格尚未接收到任何生产流量。

下图展示了旧版环境与目标环境中的空服务网格。

旧版环境和空服务网格

将旧版环境中的服务添加到网格

在此示例中,旧环境并非直接与服务网格集成。这种集成要求您手动向服务网格注册在旧版环境中运行的所有服务。如果您的环境已在 Kubernetes 中运行,那么借助与服务网格 API 的原生集成,您可以实现注册自动化。

在此阶段,客户端仍然要使用旧版环境接口来访问要迁移的微服务。服务网格尚未接收到任何生产流量。

下图展示了在旧版环境中运行的服务已添加到服务网格。

在旧版环境中运行的服务已添加到服务网格

通过服务网格公开服务

注册旧版环境后,您可以使用服务网格公开在旧版环境中运行的微服务。在这个阶段,您也要逐步将通过旧版环境接口传送到微服务的流量路由到目标环境的接口。

客户端不会注意到任何服务中断,因为它们会通过一个负载平衡层访问两个环境的接口。此外,服务网格内的流量路由对于客户端是透明的。客户端不会知道发生了路由配置更改。

下图展示了在旧版环境中运行的服务已通过服务网格公开。

在旧版环境中运行的服务已通过服务网格公开

在目标环境中部署服务

在这个阶段中,您将在目标环境中部署微服务。此处假设您已经为这些微服务实现了容器化。在完成该过程之后,您可以选择一项部署策略来初始化要迁移到目标环境中的工作负载:

  • 批量部署:在目标环境中同时部署所有微服务实例。
  • 逐步部署:一次部署一项微服务。

此时目标环境中的微服务实例尚未接收到任何生产流量。

迁移有状态微服务时,您必须同时迁移相关数据,从而最大限度地减少停机时间,并妥善处理同步和完整性问题。 详细了解数据迁移策略

由于与 Kubernetes 和 Istio 的原生集成,在目标环境中运行的微服务会自动注册到服务网格中。在此阶段,客户端仍然使用旧版环境中运行且通过服务网格公开的微服务。在目标环境中运行的微服务在此时仍然不会接收到任何生产流量。

下图展示了经过扩展的服务不会接收到任何生产流量,旧版环境中的服务已使用服务网格公开。

经过扩展的服务未接收到任何生产流量,旧版环境中的服务已使用服务网格公开

设置路由规则以拆分流量

现在,您可以设置路由规则,以便使用服务网格将生产流量拆分到在旧版环境中运行的服务以及在目标环境中运行的服务之间。首先,您可以将一小部分生产流量路由到目标环境中运行的微服务实例。借助测试套件和强大的监控树立对目标环境的信心之后,您就可以逐渐增加路由到目标环境中微服务实例的流量占总体流量的比例。

此时,客户端请求会在两个环境中路由,因此您需要就有状态微服务执行额外的规划和协调工作,因为相关数据也必须迁移,并且在迁移期间可能存在具有多个事实来源的临时阶段。

下图展示了流量在运行于目标环境中的微服务与运行于旧版环境中的微服务之间的拆分情况。

流量在运行于目标环境中的微服务与运行于旧版环境中的微服务之间的拆分情况

此外我们还建议您优化路由规则,禁止跨环境请求,这样无论在客户端请求传送到旧版环境还是目标环境,都会保留在相应的环境中。

设置规则以将流量路由至目标环境

在这个阶段中,您需要更新路由规则,以便逐步实现仅将流量路由到运行在目标环境中的服务。

下图展示了流量现在如何仅路由到目标环境,而旧版环境仅留作备用。

流量现在仅路由到目标环境,而旧版环境仅留作备用

停用旧版环境

在这个阶段中,您将停用旧版环境。

在停用旧环境之前,请确保满足以下条件:

  • 目前没有任何流量路由到在旧版环境中运行的微服务实例。
  • 没有任何流量通过旧版环境的接口传输。
  • 目标环境已全面经过验证。

满足这些条件后,您就可以更新 DNS 记录,将其指向您在目标环境预配阶段设置的负载平衡器。

下图仅展示了目标环境,因为旧版环境已停用。

目标环境(旧版环境已停用)

后续步骤