7.4. 使用基于路由的部署策略

部署策略为应用程序的演进提供了一个途径。有些策略使用 Deployment 对象进行解析到应用程序的所有路由用户可见的更改。其他高级策略,例如本节中描述的策略,结合使用路由器功能和 Deployment 对象来影响特定的路由。

最常用的基于路由型策略是使用蓝绿部署。新版本(绿色版本)上线进行测试和评估,同时用户仍然使用稳定版本(蓝色版本)。准备就绪后,用户切换到绿色版本。如果出现问题,您可以切回到蓝色版本。

一个常见的替代策略是使用同时活跃的 A/B 版本;一些用户使用一个版本,另一些用户使用另一个版本。这可用于试验用户界面变化和其他功能,以获取用户反馈。它还可用来在影响有限用户的生产环境中验证正确的操作。

Canary 部署会测试新版本,但在检测到问题时,迅速回退到上一版本。这可以通过以上两个策略实现。

基于路由的部署策略不会缩放服务中的 pod 数。要保持所需的性能特性,部署配置可能必须要扩展。

7.4.1. 代理分片和流量分割

在生产环境中,您可以精确控制特定分片上的流量分布。在处理大量实例时,可以使用相对比例的独立分片来实现基于百分比的流量分布。这可与代理分片良好结合,将接收到的流量转发或分割到在其他位置运行的单独服务或应用程序。

在最简单的配置中,代理会原封不动转发请求。在比较复杂的设置中,可以复制传入的请求,同时将它们发送到独立集群以及应用程序的本地实例,并且比较其结果。其他模式包括使 DR 安装的缓存保持活跃,或抽样传入的流量来满足分析需要。

任何 TCP(或 UDP)代理都可以在所需的分片下运行。使用 oc scale 命令更改代理分片下服务请求的相对数量。对于更复杂的流量管理,请考虑使用比例平衡功能自定义 OpenShift Container Platform 路由器。

7.4.2. N-1 兼容性

同时运行新旧代码的应用程序必须要谨慎处理,以确保新代码写入的数据能被旧版代码读取和处理(或恰当忽略)。这有时被称为架构演进,而且是一个复杂的问题。

这可采用多种形式:数据存储在磁盘、数据库或临时缓存中,或作为用户浏览器会话的一部分。虽然大多数 Web 应用程序都支持滚动部署,但务必要测试并设计您的应用程序以便能处理它。

在一些应用程序中,同时运行新旧代码的时间是短暂的,因此程序错误或一些用户事务失败是可以接受的。至于其他应用程序,失败模式可能会导致整个应用程序无法运作。

验证 N-1 兼容性的一种方法是使用 A/B 部署:在测试环境中以受控的方式同时运行旧代码和新代码,并验证流向新部署的流量不会导致旧部署失败。

7.4.3. 恰当终止

OpenShift Container Platform 和 Kubernetes 会留出时间,让应用程序实例关机后再从负载均衡轮转中移除。但是,应用程序必须保证在用户退出前彻底终止用户连接。

在关闭时,OpenShift Container Platform 会向容器中的进程发送一个 TERM 信号。在接收 SIGTERM 时,应用程序代码停止接受新的连接。这样可确保负载均衡器将流量路由到其他活跃实例。然后,应用程序代码会等到所有开启的连接都关闭(或在下次机会出现时恰当终止独立的连接)后再退出。

在恰当终止周期到期后,还未退出的进程会收到 KILL 信号,该信号会立即结束此进程。pod 或 pod 模板的 terminationGracePeriodSeconds 属性控制恰当终止期限(默认值 30 秒),并可根据需要自定义每个应用程序。

7.4.4. 蓝绿部署

蓝绿部署涉及同时运行应用程序的两个版本,并将流量从生产版本(蓝色版本)移动到更新版本(绿色版本)。您可以使用滚动策略或切换路由中的服务。

由于许多应用程序依赖于持久性数据,您必须有支持 N-1 兼容性的应用程序;这意味着,通过创建数据层的两个副本在数据库、存储或磁盘间共享数据并实现实时迁移。

以测试新版本时使用的数据为例。如果是生产数据,新版本中的错误可能会破坏生产版本。

7.4.4.1. 设置蓝绿部署

蓝绿部署使用两个 Deployment 对象。这两者都在运行,生产环境中的 Deployment 依赖于路由指定的服务,每个 Deployment 对象公开给不同的服务。

注意

路由适用于 Web(HTTP 和 HTTPS)流量,因此这种技术最适合 Web 应用程序。

您可以创建指向新版本的新路由并进行测试。准备就绪后,将生产路径中的服务更改为指向新服务,使新(绿色)版本上线。

如果需要,可以通过将服务切回到之前的版本以回滚到老版本(蓝色)。

流程

  1. 创建两个独立的应用程序组件。

    1. example-blue 服务下,创建运行 v1 镜像的示例应用程序的副本:

      $ oc new-app openshift/deployment-example:v1 --name=example-blue
    2. example-green 服务下,创建使用 v2 镜像的第二个副本:

      $ oc new-app openshift/deployment-example:v2 --name=example-green
  2. 创建指向旧服务的路由:

    $ oc expose svc/example-blue --name=bluegreen-example
  3. 通过 bluegreen-example-<project>.<router_domain> 访问应用程序,验证您能否看到 v1 镜像。
  4. 编辑路由并将服务名称改为 example-green

    $ oc patch route/bluegreen-example -p '{"spec":{"to":{"name":"example-green"}}}'
  5. 要验证路由是否已改变,请刷新浏览器直到您看到 v2 镜像。

7.4.5. A/B 部署

A/B 部署策略允许您在生产环境中以有限的方式尝试应用程序的新版本。您可以指定生产版本获得大多数用户请求,同时让有限比例的请求进入新版本。

由于您掌控进入每个版本的请求比例,因此随着测试的推进,您可以增加进入新版本的请求的比例,最终停止使用旧版本。当您调整每个版本的请求负载时,可能需要扩展各个服务中的 pod 数,以提供预期的性能。

除了升级软件外,您还可以使用此功能来试验用户界面的不同版本。由于部分用户会使用旧版本,而另外的一部分用户会使用新版本,因此您可以评估用户对不同版本的反应,以做出明智的设计决策。

若要使此功能凑效,新旧两个版本必须足够相似,让两个版本能够同时运行。这常用于对程序错误修复的发布,也适用于新功能不会影响到旧功能的情况。各个版本需要支持 N-1 兼容性才能正常工作。

OpenShift Container Platform 通过 Web 控制台和 CLI 支持 N-1 兼容性。

7.4.5.1. A/B 测试负载均衡

用户使用多个服务设置路由。每个服务负责应用程序的一个版本。

每个服务分配到一个 weight,进入每个服务的请求的比例等于 service_weight 除以 sum_of_weights。每个服务的 weight 分布到该服务的端点,使得端点 weight 的总和等于服务 weight

路由最多可有四个服务。服务的 weight 可以在 0256 范围内。当 weight 等于 0 时,服务不参与负载均衡,但继续为现有的持久连接服务。当服务 weight 不为 0 时,每个端点的最小 weight1。因此,具有大量端点的服务会得到高于预期值的 weight。在本例中,减少 pod 数量以获得预期的负载均衡 weight

流程

设置 A/B 环境:

  1. 创建两个应用程序并使用不同的名称。它们各自创建一个 Deployment 对象。应用程序是同一程序的不同版本;一个是当前生产版本,另一个是提议的新版本。

    1. 创建第一个应用程序。以下示例创建了一个名为 ab-example-a 的应用程序:

      $ oc new-app openshift/deployment-example --name=ab-example-a
    2. 创建第二个应用程序:

      $ oc new-app openshift/deployment-example:v2 --name=ab-example-b

      两个应用程序都已部署,也创建了服务。

  2. 通过路由对外提供应用程序。此时您可以公开其中任一个。先公开当前生产版本,稍后修改路由来添加新版本,这可能比较方便。

    $ oc expose svc/ab-example-a

    ab-example-a.<project>.<router_domain> 查看应用程序,以确保可以看到预期的版本。

  3. 当您部署路由时,路由器会根据为服务指定的 weight 来均衡流量。此时,存在具有默认 weight=1 的单一服务,因此所有请求都会进入该服务。添加其他服务作为 alternateBackend 并调整 weight,即可激活 A/B 设置。这可通过 oc set route-backends 命令或编辑路由来完成。

    如果将 oc set route-backend 设为 0,则服务不参与负载均衡,但继续为现有的持久连接服务。

    注意

    对路由的更改只会改变流量进入各个服务的比例。您可能需要扩展部署来调整 pod 数量,以处理预期的负载。

    若要编辑路由,请运行:

    $ oc edit route <route_name>

    输出示例

    ...
    metadata:
      name: route-alternate-service
      annotations:
        haproxy.router.openshift.io/balance: roundrobin
    spec:
      host: ab-example.my-project.my-domain
      to:
        kind: Service
        name: ab-example-a
        weight: 10
      alternateBackends:
      - kind: Service
        name: ab-example-b
        weight: 15
    ...

7.4.5.1.1. 使用 Web 控制台管理现有路由的权重

流程

  1. 进入 NetworkingRoutes 页面。
  2. 点击您要编辑的路由旁的 Actions 菜单 kebab ,然后选择 Edit Route
  3. 编辑 YAML 文件。把 weight 更新为 0256 之间的一个整数,用于指定目标相对于其他目标引用对象的相对权重。值 0 会把请求限制到这个后端。默认值为 100。运行 oc explain routes.spec.alternateBackends 以了解有关选项的更多信息。
  4. Save
7.4.5.1.2. 使用 Web 控制台管理新路由的权重
  1. 进入 NetworkingRoutes 页面。
  2. 点击 Create Route
  3. 输入路由 名称
  4. 选择 Service
  5. Add Alternate Service
  6. WeightAlternate Service Weight 输入一个值。输入一个 0255 之间的数字,它显示了与其他目标相比的相对权重。默认值为 100
  7. 选择 Target Port
  8. 点击 Create
7.4.5.1.3. 使用 CLI 管理权重

流程

  1. 要管理由路由均衡负载的服务以及对应的权重,请使用 oc set route-backends 命令:

    $ oc set route-backends ROUTENAME \
        [--zero|--equal] [--adjust] SERVICE=WEIGHT[%] [...] [options]

    例如,以下命令将 ab-example-a 设为主服务 ( weight=198) 并将 ab-example-b 设为第一替代服务 (weight=2):

    $ oc set route-backends ab-example ab-example-a=198 ab-example-b=2

    这意味着 99% 的流量发送到服务 ab-example-a,1% 发送到 ab-example-b

    此命令不扩展部署。您可能需要进行此操作,才能有足够的 pod 来处理请求负载。

  2. 不带标志运行命令来验证当前配置:

    $ oc set route-backends ab-example

    输出示例

    NAME                    KIND     TO           WEIGHT
    routes/ab-example       Service  ab-example-a 198 (99%)
    routes/ab-example       Service  ab-example-b 2   (1%)

  3. 要改变个别服务相对于自身或主服务的权重,请使用 --adjust 标志。指定百分比来调整服务相对于主服务或第一替代服务(如果指定了主服务)的权重。如果还有其他后端,它们的权重会与更改后的值保持比例。

    以下示例会更改 ab-example-aab-example-b 服务的权重:

    $ oc set route-backends ab-example --adjust ab-example-a=200 ab-example-b=10

    或者,通过指定百分比来改变服务的权重:

    $ oc set route-backends ab-example --adjust ab-example-b=5%

    通过在百分比声明前指定 +,您可以调整相对于当前设置的权重。例如:

    $ oc set route-backends ab-example --adjust ab-example-b=+15%

    --equal 标志将所有服务的 weight 设为 100

    $ oc set route-backends ab-example --equal

    --zero 标志将所有服务的 weight 设为 0。之后,所有请求都会返回 503 错误。

    注意

    并非所有路由器都支持多个后端或加权后端。

7.4.5.1.4. 一个服务,多个 Deployment 对象

流程

  1. 创建一个新应用程序,添加对所有分片都通用的 ab-example=true 标签:

    $ oc new-app openshift/deployment-example --name=ab-example-a --as-deployment-config=true --labels=ab-example=true --env=SUBTITLE\=shardA
    $ oc delete svc/ab-example-a

    应用程序完成部署,并创建了服务。这是第一个分片。

  2. 通过路由提供应用程序,或者直接使用服务 IP:

    $ oc expose deployment ab-example-a --name=ab-example --selector=ab-example\=true
    $ oc expose service ab-example
  3. 通过 ab-example-<project_name>.<router_domain> 访问应用程序,验证您能否看到 v1 镜像。
  4. 创建第二个分片,它基于与第一分片相同的源镜像和标签,但使用不同的标记版本和独特的环境变量:

    $ oc new-app openshift/deployment-example:v2 \
        --name=ab-example-b --labels=ab-example=true \
        SUBTITLE="shard B" COLOR="red" --as-deployment-config=true
    $ oc delete svc/ab-example-b
  5. 在这一刻,路由下同时提供了两组 pod。但是,由于两个浏览器(通过使连接保持打开)和路由器(默认借助 Cookie)都试图保留后端服务器的连接,您可能不会看到两个分片都返回给您。

    使浏览器强制到其中一个分片:

    1. 使用 oc scale 命令将 ab-example-a 的副本数减少到 0

      $ oc scale dc/ab-example-a --replicas=0

      刷新浏览器以显示 v2shard B(红色)。

    2. ab-example-a 扩展为 1 个副本,ab-example-b 调到 0

      $ oc scale dc/ab-example-a --replicas=1; oc scale dc/ab-example-b --replicas=0

      刷新浏览器以显示 v1shard A(蓝色)。

  6. 如果您对其中任一分片触发部署,那么只有该分片中的 pod 会受到影响。您可以通过在任一 Deployment 对象中更改 SUBTITLE 环境变量来触发部署:

    $ oc edit dc/ab-example-a

    或者

    $ oc edit dc/ab-example-b