本系列文章的第一部分介绍了如何在Kubernetes集群中实现真正的零停机时间更新。 我们专门解决了将流量从旧实例切换到新实例时出现的请求失败。 本文将展示如何使用Istio群集实现相同的目标。
服务网格技术(例如Istio)通常与容器编排结合使用。 Istio以透明的方式为我们的应用程序提供了诸如弹性,遥测和高级流量管理之类的跨领域问题。
当我们使用Istio时,与内部Kubernetes相比,集群内部网络模型看起来有些不同。 如果您不了解Istio当前的网络API的设计方式,则可以观看以下说明视频 。
使用Istio尝试零停机
让我们从文章的第一部分开始。 如果我们采用与以前类似的方式将应用程序重新部署到Istio群集,则会注意到更新期间的行为有所不同。 当我们重新运行旨在检测可用性差距的负载测试时,我们会注意到,尽管我们有preStop
pod生命周期处理程序,但仍有一些失败的请求。
Fortio 1.1.0 running at 500 queries per second, 4->4 procs, for 20s
Starting at 500 qps with 50 thread(s) [gomax 4] for 20s : 200 calls each (total 10000)
09:11:39 W http_client.go:673> Parsed non ok code 503 (HTTP/1.1 503)
[...]
Code 200 : 9960 (99.6 %)
Code 503 : 40 (0.4 %)
Response Header Sizes : count 10000 avg 165.204 +/- 10.43 min 0 max 167 sum 1652048
Response Body/Total Sizes : count 10000 avg 176.12 +/- 3.817 min 171 max 227 sum 1761200
[...]
输出表明有一些HTTP请求失败,并带有503 Service Unavailable
状态代码。 无论我们如何调整preStop
处理程序的等待时间,在流量大时更新服务时,我们似乎都会至少preStop
一些客户端请求。 同样,我们是否通过网关从网格内部还是从群集外部访问Istio服务似乎也没有什么区别。
了解发生了什么
要了解发生了什么,让我们仔细看看Istio边车容器如何连接到各个服务。
网格中的所有流量都通过连接到各个实例的Sidecar代理进行路由。 对于通过网关的入口流量也是如此。
在我们的场景中,这意味着边车可能无法连接到实例,即使它们已经准备好为交通服务。 代理以最终一致的方式配置; 配置从飞行员平面逐渐传播。
Envoy还对实例执行主动的运行状况检查,它将检测异常值并最终阻止与它们的连接。 为Pod定义的基于HTTP的就绪探针也将包括在内,并由Envoy代理执行。 换句话说,即使容器仍会接受请求,代理容器也不会连接到准备就绪探测失败的容器。 我们可以通过网状配置添加到Sidecar代理中的重试配置只能缓解但不能解决此问题。
通过Istio实现零停机
有一些方法可以在将来向Kubernetes引入更多增强的健康检查概念。
但是,当前,在工作量和可靠性之间的合理平衡是使用Istio子集作为版本指示符,并独立于Kubernetes的滚动更新机制重新路由服务流量。 通过这种方法,我们使用服务子集来标识应用程序的版本(例如v1
或v2
,并将虚拟服务配置为路由到一个特定版本。 由虚拟服务资源配置的Istio代理路由可以重新路由到具有真正零停机时间的不同子集版本。
为了使用这种方法,我们将创建单独的Kubernetes部署,为我们的应用程序的每个单独版本创建一个,并通过Istio执行实际的切换。
部署示例如下所示:
- 最初:Kubernetes部署
coffee-shop-v1
带有标签app=coffee-shop
,version=v1
,目的地规则来定义子集v1
,和虚拟服务,航线coffee-shop
v1
- 我们增强了目标规则,以包括版本
v2
的新子集 - 我们创建一个
version=v2
的部署coffee-shop-v2
version=v2
- 成功部署完成后,我们将虚拟服务重新路由到
v2
。 切换将不会丢失请求。 - 短暂的等待后,我们从目标规则中删除了子集
v1
,并部署了coffee-shop-v1
如果我们从第一部分开始重新运行相同的负载测试,则会注意到我们可以执行实际的零停机时间部署。
Fortio 1.1.0 running at 500 queries per second, 4->4 procs, for 20s
Starting at 500 qps with 50 thread(s) [gomax 4] for 20s : 200 calls each (total 10000)
[...]
Code 200 : 10000 (100.0 %)
Response Header Sizes : count 10000 avg 159.530 +/- 0.706 min 154 max 160 sum 1595305
Response Body/Total Sizes : count 10000 avg 167.853 +/- 2.51 min 161 max 171 sum 1678534
[...]
如果您不熟悉如何使用Istio的网络API来实现此过程,则可以观看说明视频 。
自动化是关键
当然,我们不想手动执行这些步骤。 想法是定义一个在每个新软件版本上执行的自动化过程。 最终,这种部署应作为持续交付管道的一部分进行,该管道将我们的软件部署到相应的环境中。
我们可以增强我们的持续交付渠道,以部署Canary版本,在该版本中,我们仅将一小部分用户流量路由到。 这也将作为自动化方法同样包含在管道中:逐渐将用户流量路由到新部署的版本,然后在Canary版本证明其自身运行良好后执行完全切换。
如果我们以模板语言定义部署和Istio路由定义,则将有帮助。 这样,我们可以可靠地定义和更改应用程序版本和映像版本,并始终如一地推出更改。 coffee-shop示例项目包括一个自动化脚本,该脚本使用Istio执行零停机时间部署,并基于使用kontemplate的YAML模板方法进行构建 。
结论
Kubernetes的生产就绪性是一个非常有价值的功能,它是开箱即用的。 但是,我们需要更多地考虑,以充分实现零停机时间行为。 测试您将在生产环境中运行的应用程序的停机时间并相应地调整探测和各种超时至关重要。
当然,了解Kubernetes和Istio如何分别管理与后端的连接也很有帮助。 如果我们在更新期间稍微调整行为,则可以消除最后的可用性差距。
零宕机时间以及正确的连接耗尽和保持活动连接处理能力使我们的应用程序可以随时部署,而不会中断用户。 一旦达到这一点,我们就可以不断改进软件,并更快地交付功能和错误修复以投入生产。 因此,零停机时间部署是持续交付和持续改进文化正常运行的前提之一。
- GitHub项目示例(Istio版本)
- Kubernetes的零停机滚动更新(第一部分)
- Istio Networking API说明视频
- Kontemplate(Kubernetes模板工具)
翻译自: https://www.javacodegeeks.com/2018/10/zero-downtime-rolling-updates-istio.html