8.4. 使用基于路由的部署策略
部署策略为应用程序的演进提供了一个途径。有些策略使用 Deployment
对象进行解析到应用程序的所有路由用户可见的更改。其他高级策略,例如本节中描述的策略,结合使用路由器功能和 Deployment
对象来影响特定的路由。
最常用的基于路由型策略是使用蓝绿部署。新版本(绿色版本)上线进行测试和评估,同时用户仍然使用稳定版本(蓝色版本)。准备就绪后,用户切换到绿色版本。如果出现问题,您可以切回到蓝色版本。
或者,您可以使用两个版本同时活跃的 A/B 版本策略。借助这一策略,一些用户可以使用 版本 A,而其他用户可使用 版本 B。您可以使用此策略来试验用户界面更改或其他功能,以获得用户反馈。它还可用来在影响有限用户的生产环境中验证正确的操作。
Canary 部署会测试新版本,但在检测到问题时,迅速回退到上一版本。这可以通过以上两个策略实现。
基于路由的部署策略不会缩放服务中的 pod 数。要保持所需的性能特性,部署配置可能必须要扩展。
8.4.1. 代理分片和流量分割
在生产环境中,您可以精确控制特定分片上的流量分布。在处理大量实例时,可以使用相对比例的独立分片来实现基于百分比的流量分布。这可与代理分片良好结合,将接收到的流量转发或分割到在其他位置运行的单独服务或应用程序。
在最简单的配置中,代理会原封不动转发请求。在比较复杂的设置中,可以复制传入的请求,同时将它们发送到独立集群以及应用程序的本地实例,并且比较其结果。其他模式包括使 DR 安装的缓存保持活跃,或抽样传入的流量来满足分析需要。
任何 TCP(或 UDP)代理都可以在所需的分片下运行。使用 oc scale
命令更改代理分片下服务请求的相对数量。对于更复杂的流量管理,请考虑使用比例平衡功能自定义 OpenShift Container Platform 路由器。
8.4.2. N-1 兼容性
同时运行新旧代码的应用程序必须要谨慎处理,以确保新代码写入的数据能被旧版代码读取和处理(或恰当忽略)。这有时被称为架构演进,而且是一个复杂的问题。
这可采用多种形式:数据存储在磁盘、数据库或临时缓存中,或作为用户浏览器会话的一部分。虽然大多数 Web 应用程序都支持滚动部署,但务必要测试并设计您的应用程序以便能处理它。
在一些应用程序中,同时运行新旧代码的时间是短暂的,因此程序错误或一些用户事务失败是可以接受的。至于其他应用程序,失败模式可能会导致整个应用程序无法运作。
验证 N-1 兼容性的一种方法是使用 A/B 部署:在测试环境中以受控的方式同时运行旧代码和新代码,并验证流向新部署的流量不会导致旧部署失败。
8.4.3. 恰当终止
OpenShift Container Platform 和 Kubernetes 会留出时间,让应用程序实例关机后再从负载均衡轮转中移除。但是,应用程序必须保证在用户退出前彻底终止用户连接。
在关闭时,OpenShift Container Platform 会向容器中的进程发送一个 TERM
信号。在接收 SIGTERM
时,应用程序代码停止接受新的连接。这样可确保负载均衡器将流量路由到其他活跃实例。然后,应用程序代码会等到所有开启的连接都关闭(或在下次机会出现时恰当终止独立的连接)后再退出。
在恰当终止周期到期后,还未退出的进程会收到 KILL
信号,该信号会立即结束此进程。pod 或 pod 模板的 terminationGracePeriodSeconds
属性控制恰当终止期限(默认值 30 秒),并可根据需要自定义每个应用程序。
8.4.4. 蓝绿部署
蓝绿部署涉及同时运行应用程序的两个版本,并将流量从生产版本(蓝色版本)移动到更新版本(绿色版本)。您可以使用滚动策略或切换路由中的服务。
由于许多应用程序依赖于持久性数据,您必须有支持 N-1 兼容性的应用程序;这意味着,通过创建数据层的两个副本在数据库、存储或磁盘间共享数据并实现实时迁移。
以测试新版本时使用的数据为例。如果是生产数据,新版本中的错误可能会破坏生产版本。
8.4.4.1. 设置蓝绿部署
蓝绿部署使用两个 Deployment
对象。这两者都在运行,生产环境中的 Deployment 依赖于路由指定的服务,每个 Deployment
对象公开给不同的服务。
路由适用于 Web(HTTP 和 HTTPS)流量,因此这种技术最适合 Web 应用程序。
您可以创建指向新版本的新路由并进行测试。准备就绪后,将生产路径中的服务更改为指向新服务,使新(绿色)版本上线。
如果需要,可以通过将服务切回到之前的版本以回滚到老版本(蓝色)。
流程
创建两个独立的应用程序组件。
在
example-blue
服务下,创建运行v1
镜像的示例应用程序的副本:$ oc new-app openshift/deployment-example:v1 --name=example-blue
杂
example-green
服务下,创建使用v2
镜像的第二个副本:$ oc new-app openshift/deployment-example:v2 --name=example-green
创建指向旧服务的路由:
$ oc expose svc/example-blue --name=bluegreen-example
-
通过
bluegreen-example-<project>.<router_domain>
访问应用程序,验证您能否看到v1
镜像。 编辑路由并将服务名称改为
example-green
:$ oc patch route/bluegreen-example -p '{"spec":{"to":{"name":"example-green"}}}'
-
要验证路由是否已改变,请刷新浏览器直到您看到
v2
镜像。
8.4.5. A/B 部署
A/B 部署策略允许您在生产环境中以有限的方式尝试应用程序的新版本。您可以指定生产版本获得大多数用户请求,同时让有限比例的请求进入新版本。
由于您掌控进入每个版本的请求比例,因此随着测试的推进,您可以增加进入新版本的请求的比例,最终停止使用旧版本。当您调整每个版本的请求负载时,可能需要扩展各个服务中的 pod 数,以提供预期的性能。
除了升级软件外,您还可以使用此功能来试验用户界面的不同版本。由于部分用户会使用旧版本,而另外的一部分用户会使用新版本,因此您可以评估用户对不同版本的反应,以做出明智的设计决策。
若要使此功能凑效,新旧两个版本必须足够相似,让两个版本能够同时运行。这常用于对程序错误修复的发布,也适用于新功能不会影响到旧功能的情况。各个版本需要支持 N-1 兼容性才能正常工作。
OpenShift Container Platform 通过 Web 控制台和 CLI 支持 N-1 兼容性。
8.4.5.1. A/B 测试负载均衡
用户使用多个服务设置路由。每个服务负责应用程序的一个版本。
每个服务分配到一个 weight
,进入每个服务的请求的比例等于 service_weight
除以 sum_of_weights
。每个服务的 weight
分布到该服务的端点,使得端点 weight
的总和等于服务 weight
。
路由最多可有四个服务。服务的 weight
可以在 0
到 256
范围内。当 weight
等于 0
时,服务不参与负载均衡,但继续为现有的持久连接服务。当服务 weight
不为 0
时,每个端点的最小 weight
为 1
。因此,具有大量端点的服务会得到高于预期值的 weight
。在本例中,减少 pod 数量以获得预期的负载均衡 weight
。
流程
设置 A/B 环境:
创建两个应用程序并使用不同的名称。它们各自创建一个
Deployment
对象。应用程序是同一程序的不同版本;一个是当前生产版本,另一个是提议的新版本。创建第一个应用程序。以下示例创建了一个名为
ab-example-a
的应用程序:$ oc new-app openshift/deployment-example --name=ab-example-a
创建第二个应用程序:
$ oc new-app openshift/deployment-example:v2 --name=ab-example-b
两个应用程序都已部署,也创建了服务。
通过路由对外提供应用程序。此时您可以公开其中任一个。先公开当前生产版本,稍后修改路由来添加新版本,这可能比较方便。
$ oc expose svc/ab-example-a
在
ab-example-a.<project>.<router_domain>
查看应用程序,以确保可以看到预期的版本。当您部署路由时,路由器会根据为服务指定的
weight
来均衡流量。此时,存在具有默认weight=1
的单一服务,因此所有请求都会进入该服务。添加其他服务作为alternateBackend
并调整weight
,即可激活 A/B 设置。这可通过oc set route-backends
命令或编辑路由来完成。注意使用
alternateBackends
时,也使用roundrobin
负载均衡策略来确保请求按预期分发到服务。也可以使用路由注解为一个路由设置roundrobin
。如果将
oc set route-backend
设为0
,则服务不参与负载均衡,但继续为现有的持久连接服务。注意对路由的更改只会改变流量进入各个服务的比例。您可能需要扩展部署来调整 pod 数量,以处理预期的负载。
若要编辑路由,请运行:
$ oc edit route <route_name>
输出示例
apiVersion: route.openshift.io/v1 kind: Route 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 # ...
8.4.5.1.1. 使用 Web 控制台管理现有路由的权重
流程
-
进入 Networking
Routes 页面。 - 点击您要编辑的路由旁的 Actions 菜单 ,然后选择 Edit Route。
-
编辑 YAML 文件。把
weight
更新为0
到256
之间的一个整数,用于指定目标相对于其他目标引用对象的相对权重。值0
会把请求限制到这个后端。默认值为100
。运行oc explain routes.spec.alternateBackends
以了解有关选项的更多信息。 - 点 Save。
8.4.5.1.2. 使用 Web 控制台管理新路由的权重
-
进入 Networking
Routes 页面。 - 点击 Create Route。
- 输入路由 名称。
- 选择 Service。
- 点 Add Alternate Service。
-
为 Weight 和 Alternate Service Weight 输入一个值。输入一个
0
到255
之间的数字,它显示了与其他目标相比的相对权重。默认值为100
。 - 选择 Target Port。
- 点击 Create。
8.4.5.1.3. 使用 CLI 管理权重
流程
要管理由路由均衡负载的服务以及对应的权重,请使用
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 来处理请求负载。
不带标志运行命令来验证当前配置:
$ 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%)
要覆盖负载平衡算法的默认值,请通过将算法设置为
roundrobin
来调整路由上的注解。对于 OpenShift Container Platform 上的路由,默认的负载均衡算法被设置为random
或source
值。要将算法设置为
roundrobin
,请运行以下命令:$ oc annotate routes/<route-name> haproxy.router.openshift.io/balance=roundrobin
对于传输层安全 (TLS) 透传路由,默认值为
source
。对于所有其他路由,默认值为random
。要改变个别服务相对于自身或主服务的权重,请使用
--adjust
标志。指定百分比来调整服务相对于主服务或第一替代服务(如果指定了主服务)的权重。如果还有其他后端,它们的权重会与更改后的值保持比例。以下示例会更改
ab-example-a
和ab-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 错误。注意并非所有路由器都支持多个后端或加权后端。
8.4.5.1.4. 一个服务,多个 Deployment
对象
流程
创建一个新应用程序,添加对所有分片都通用的
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
应用程序完成部署,并创建了服务。这是第一个分片。
通过路由提供应用程序,或者直接使用服务 IP:
$ oc expose deployment ab-example-a --name=ab-example --selector=ab-example\=true
$ oc expose service ab-example
-
通过
ab-example-<project_name>.<router_domain>
访问应用程序,验证您能否看到v1
镜像。 创建第二个分片,它基于与第一分片相同的源镜像和标签,但使用不同的标记版本和独特的环境变量:
$ 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
在这一刻,路由下同时提供了两组 pod。但是,由于两个浏览器(通过使连接保持打开)和路由器(默认借助 Cookie)都试图保留后端服务器的连接,您可能不会看到两个分片都返回给您。
使浏览器强制到其中一个分片:
使用
oc scale
命令将ab-example-a
的副本数减少到0
。$ oc scale dc/ab-example-a --replicas=0
刷新浏览器以显示
v2
和shard B
(红色)。将
ab-example-a
扩展为1
个副本,ab-example-b
调到0
:$ oc scale dc/ab-example-a --replicas=1; oc scale dc/ab-example-b --replicas=0
刷新浏览器以显示
v1
和shard A
(蓝色)。
如果您对其中任一分片触发部署,那么只有该分片中的 pod 会受到影响。您可以通过在任一
Deployment
对象中更改SUBTITLE
环境变量来触发部署:$ oc edit dc/ab-example-a
或者
$ oc edit dc/ab-example-b