摘要:通常要在全公司范围内创建虚拟服务和目标规则,我们必须使用与Istio相关的Helm模板来更新每个git repo。Istio通过在应用程序旁边添加基于Envoy的sidecar代理进行工作,该应用程序拦截所有进出Pod的入站和出站请求。

每周为数百万的顾客送餐比表面上看起来要复杂得多。在后台,按我们的规模运作,需要大量的基础设施,才能最终将外卖送到顾客手中。

在HelloFresh,我们运行着数百个的微服务,这些微服务能够完成从供应链管理、付款到了解顾客喜好的所有工作。大规模运行微服务并非没有挑战,相信现在许多公司已经开始体验到大规模微服务的复杂性所带来的痛苦。与许多其他使用微服务的人一样,我们发现随着服务数量的增加,理解这些服务之间的交互变得越来越困难。当微服务中出现故障时,就很难定位到问题出现在堆栈中的位置。在2019年初,我们开始着手研究解决如何定位问题的方法,并得出结论认为服务网格,尤其是Istio是最佳选择。

什么是Istio

Istio是围绕Envoy代理构建的服务网格,用于管理和流量控制,保护服务并查看它们之间发生了什么。此外,Istio还可以与Jaeger、Grafana、Kiali和Prometheus等其他常见的基础架构和监控组件配合使用。由于我们已经将所有的工作负载转移到了Kubernetes/EKS,并且已经使用了上述工具,所以Istio非常适合我们。我们花了几个月的时间在临时环境还有生产环境上部署和配置了Istio,到了2019年12月份,除生产环境之外已经全部部署配置了Istio。这一系列的博客文章将继续为大家带来我们在这段时间里所学到的所有内容,并涵盖一些未必在文档中出现的经验。

专注需求

Istio可以做很多的事情。它所带来的功能数量之多是令人难以抗拒的,但其实Istio的核心是做四件事:连接性、可观测性、安全性和流量控制。在早些时候,我们决定将精力集中在可观测性和弹性上。我们的策略是首先实现可观测性和弹性的构建模块,并在适应该基准后将其转移到其他功能上。

在Istio中,这意味要选择一组核心特性,这些特性使系统具有可观测性和可靠性。为了提高弹性,我们启用了断路、异常检测、重试(必要时)和超时。我们以一种使开发人员可以选择他们想要实现的功能的方式启用它们,但是使用的是公司标准接口(更多内容请参见下文)。实际上,我们为大多数服务添加了sidecar代理(Envoy),网关,虚拟服务和目标规则。

这里我们的建议是,对于大多数公司而言,Istio可能过于复杂而无法一次全部推出所有功能。因此,首先关注一个或两个方面的需求,然后再添加其余方面的。

集中式的Istio模板

我们在使用Helm图表部署所有服务时。通常要在全公司范围内创建虚拟服务和目标规则,我们必须使用与Istio相关的Helm模板来更新每个git repo。于是,我们编写了一个Helm插件,它是一个能够加载包含Istio虚拟服务,目标规则,网关资源的集中式Helm模板。该插件能将这些模板与项目特定的值结合使用,用来生成完整的图表。然后开发团队就可以在维护模板的同时配置文件的值来满足他们的需求。为了所有人都能用上Istio,我们要做的就是创建模板,而团队只需更新其helm值即可。我们创建了一个简单的界面,通过以下helm值来控制Istio的所有方面:

Sidecar应用

最终,经过反复思考决定要推出的哪些功能以及开发人员将如何与它们交互之后,我们开始进行测试。在Istio,将代理sidecar添加到应用程序Pods中。Istio通过在应用程序旁边添加基于Envoy的sidecar代理进行工作,该应用程序拦截所有进出Pod的入站和出站请求。然后,可以将sidecar代理配置为控制或保护通过它的流量,也可以收集遥测指标和跟踪信息,以供Prometheus和Jaeger使用。

首先,我们选择不向每个Pod中注入sidecar,因此我们全局禁用了自动注入:

global:

proxy:

autoinject: disabled

同样,我们并不需要为每个Kubernetes namepace注入sidecar,因此我们通过向启用了istio的namepace添加以下标签来限制可能具有sidecar的namespace:

istio-injection: "enabled"

有了这两部分之后,我们就可以通过在Pod中添加以下注释,逐个应用地推出Istio:

sidecar.istio.io/inject: "true"

Istio可以在应用程序级别上彻底改变预期的行为。在盲目地将它部署到任何地方之前,我们需要对在哪个应用程序上运行进行有意识的选择。另外,并非每个应用程序都与Istio兼容,因此使用前请务必先 检查

分阶段推出

在HelloFresh,我们将团队分为小组和群体。每个群体都有自己的Kubernetes namespace。如上所述,我们按namespace启用sidecar注入namespace,然后按应用程序启用。在为Istio启用应用程序之前,我们开了个研讨会,以便小组能够了解应用程序发生的变化。由于我们采用“谁构建,谁负责”的模型,因此,团队可以在进行故障排除时监控流量。不仅如此,它还提高了公司内部的知识水平。我们还创建了与Istio相关的 OKR ,用来跟踪我们的进度并实现我们的Istio采用目标。

缩放控制平面

每增加新的sidecar都会给Istio控制平面增加更多的负载。 Pilot连接到每个istio-proxy,每个istio-proxy都针对每个请求(减去一些缓存)使用Mixer进行检查并报告,因此这些控制平面组件变得非常关键。在将每个namespace迁移到Istio之前,我们都已部署了监控并调整控制平面。在继续增加负载之前,给我们提供了一个很好的检查点。我们必须定期调整每个控制平面组件的副本数,CPU和内存请求/限制。另外,我们还要关注每个istio-proxy消耗的内存量。尽管Envoy代理是相对轻量级的,但是运行数千个请求会增加大量的内存占用。我们已经在使用Kubernetes集群自动缩放器,因此我们的集群会自动缩放,但是在计算运行服务网格的成本和性能开销时,这部分是不能忽略的。

同样,所有生成的日志,指标和跟踪信息都会给我们的Graylog,Jaeger和Prometheus基础架构带来额外的负担。一般我们会在日志记录存储,Jaeger,Cassandra数据库中增加更多的容量,并在将更多namespace加入Istio之前扩展Prometheus Pod。

结论

前面这些只是我们为确保Istio在整个公司中顺利铺开而采取的一些步骤。请继续关注第2部分,我们将在其中深入了解实现细节。

相关文章