回到Istio的微服务。 第一部分



注意事项 佩雷夫 服务网格在遵循微服务架构的应用程序的现代基础架构中无疑已经成为一个重要的解决方案。 尽管许多DevOps工程师可能会听到Istio,但它是一个相当新的产品,就提供的功能而言,它是全面的,可能需要花费大量时间才能彼此了解。 德国工程师Rinor Maloku在电信公司Orange Networks负责大客户的云计算,他撰写了一系列精彩的材料,使您可以快速而深入地研究Istio。 他从Istio可以做什么以及如何用自己的眼睛快速看到它开始他的故事。

Istio是与Google,IBM和Lyft的团队合作开发的一个开源项目。 它解决了基于微服务的应用程序中出现的困难,例如:

  • 流量管理 :超时,重试,负载均衡;
  • 安全性 :最终用户的认证和授权;
  • 可观察性 :跟踪,监视,记录。

所有这些都可以在应用程序级别解决,但是之后您的服务将不再是“微型”的。 解决这些问题的所有额外努力都是对公司资源的额外浪费,这些资源可以直接用于商业价值。 考虑一个例子:
项目经理:添加反馈需要多长时间?
开发人员:两个冲刺。

MP:什么?..只是CRUD!
R:制作CRUD是一项简单的任务,但是我们仍然需要对用户和服务进行身份验证和授权。 由于网络不可靠,因此您将需要实施重复的请求以及客户端中的断路器模式 。 不过,要确保整个系统都不会崩溃,您将需要超时和隔离墙 (有关上述两种模式的更多详细信息,请参见文章中的大约Transl。) ,以及为了检测问题,进行监视,跟踪,[...]

MP:哦,那就让我们将此功能插入产品服务中。
我认为这个主意很明确:添加一项服务所需的步骤和工作量很大。 在本文中,我们将研究Istio如何从服务中消除上述所有困难(并非针对业务逻辑)。



注意 :本文假定您具有Kubernetes的实践知识。 否则,我建议阅读我对Kubernetes的介绍,然后再继续阅读本材料。

想法伊斯蒂奥


在没有Istio的世界中,一项服务会直接向另一项服务发出请求,如果发生故障,该服务必须自行处理:进行新的尝试,提供超时,打开断路器等。


Kubernetes中的网络流量

Istio还提供了一种专门的解决方案,它与服务完全独立,并且通过干扰网络交互来起作用。 因此,它实现了:

  • 容错 :根据响应中的状态代码,它可以了解请求是否失败,然后再次运行。
  • Canary推出 :仅将请求数量的固定百分比重定向到服务的新版本。
  • 监控和指标 :服务响应了多长时间?
  • 跟踪和可观察性 :向每个请求添加特殊的标头,并在集群中跟踪它们。
  • 安全性 :提取JWT令牌,对用户进行身份验证和授权。

这些只是少数可能性(真的只有少数几种!)吸引您。 现在,让我们深入了解技术细节!

建筑Istio


Istio会拦截所有网络流量并对其应用一组规则,并以边车集装箱的形式将智能代理插入每个吊舱。 激活所有功能的代理形成一个数据平面 ,可以使用控制平面动态配置它们。

数据平面


插入到吊舱中的代理使Istio可以轻松满足我们的需求。 例如,检查重试和断路器功能。


Envoy如何实现重试和断路

总结一下:

  1. Envoy (谈论位于作为单独产品分发的Sidecar容器中的代理-大约Transl。)将请求发送到服务B的第一个实例,并且发生故障。
  2. 特使塞德卡重试(1)
  3. 失败的请求将返回给调用它的代理。
  4. 这将打开断路器,并为下一个请求调用下一个服务。 (2)

这意味着您不必使用下一个Retry库,也不必使用编程语言X,Y或Z来实现自己的Circuit Breaking和Service Discovery实施。所有这些以及更多内容都可以在Istio中直接使用,并且不需要对代码进行任何更改。

太好了! 现在,您可能想和Istio一起航行,但是仍然存在一些疑问和开放性问题。 如果这是一种适用于生活中所有场合的通用解决方案,那么您就有合理的怀疑:毕竟,实际上所有此类决定都不适用于任何场合。

最后,您问:“它可定制吗?”

现在您已准备好进行海上航行-让我们熟悉控制飞机。

控制平面


它由三个部分组成: PilotMixerCitadel ,它们一起工作以配置Envoy以路由流量,应用策略以及收集遥测数据。 从示意图上看,这一切看起来像这样:


控制平面与数据平面的交互

特使(即数据平面)使用Istio定义的Kubernetes CRD (自定义资源定义)进行配置,并专门为此目的而设计。 对您来说,这意味着它们似乎是使用熟悉的语法在Kubernetes中的下一个资源。 创建后,此资源将由控制平面提取并应用于特使。

Istio的服务比率


我们描述了Istio对服务的态度,但并非相反:服务与Istio有何关系?

老实说,当他们问自己:“什么是水?”时,Istio知道服务和鱼类的存在-关于水。


Victoria Dimitrakopoulos的插图:-您喜欢水吗? -什么是水?

因此,您可以使用工作群集,并在部署Istio组件之后,位于其中的服务将继续工作,并且在删除这些组件之后,一切都会恢复正常。 显然,这样做会失去Istio提供的机会。

足够的理论-让我们将这些知识付诸实践!

实践中的Istio


Istio需要Kubernetes集群,其中至少有4个vCPU和8 GB RAM。 为了快速启动集群并按照文章中的说明进行操作,我建议使用Google Cloud Platform,该平台向新用户免费提供300美元

创建集群并通过控制台实用程序配置对Kubernetes的访问后,可以通过Helm软件包管理器安装Istio。

头盔安装


官方文档中所述,在您的计算机上安装Helm客户端。 在下一部分中,我们将使用它来生成用于安装Istio的模板。

安装Istio


最新版本下载Istio资源(原始作者到版本1.0.5的链接已更改为当前版本,即1.0.6-大约翻译) ,将内容提取到一个目录中,以后我将其称为[istio-resources]

为了便于识别Istio资源,请在K8s集群中创建istio-system命名空间:

 $ kubectl create namespace istio-system 

通过转到[istio-resources]目录并运行以下命令来完成安装:

 $ helm template install/kubernetes/helm/istio \ --set global.mtls.enabled=false \ --set tracing.enabled=true \ --set kiali.enabled=true \ --set grafana.enabled=true \ --namespace istio-system > istio.yaml 

此命令会将Istio的关键组件输出到istio.yaml文件。 我们为自己更改了标准模板,并指定了以下参数:

  • global.mtls.enabled设置为false (即,禁用了mTLS身份验证-大约翻译),以简化我们的约会过程;
  • tracing.enabled启用使用Jaeger的查询跟踪;
  • kiali.enabledkiali.enabled安装在集群中以可视化服务和流量;
  • grafana.enabled设置Grafana以可视化收集的指标。

我们通过以下命令应用生成的资源:

 $ kubectl apply -f istio.yaml 

在群集中安装Istio已完成! 通过运行以下命令,等待istio-system命名空间中的所有Pod RunningCompleted

 $ kubectl get pods -n istio-system 

现在,我们准备在下一部分继续,我们将在其中启动和启动该应用程序。

情感分析应用架构


让我们举一个在Kubernetes中已经提到的介绍文章中使用的微服务应用程序Sentiment Analysis的示例 。 它足够复杂,可以在实践中展示Istio的功能。

该应用程序包含四个微服务:

  1. 服务SA-Frontend ,在Reactjs上服务于前端应用程序;
  2. SA-WebApp服务,用于服务于情感分析请求;
  3. 服务SA-Logic ,执行情感分析
  4. 服务SA反馈 ,从用户那里收到有关分析准确性的反馈。



在该图中,除了服务之外,我们还看到了入口控制器,它在Kubernetes中将传入的请求路由到相应的服务。 Istio在Ingress网关中使用了类似的概念,下面将详细介绍。

使用Istio的代理启动应用程序


对于本文中提到的进一步操作,请克隆istio-mastery存储库。 它包含应用程序和Kubernetes和Istio的清单。

边车插件


插入可以自动手动完成。 要自动插入istio-injection=enabled容器,需要将istio-injection=enabled标签设置为istio-injection=enabled ,这是通过以下命令完成的:

 $ kubectl label namespace default istio-injection=enabled namespace/default labeled 

现在,将在默认名称空间中部署的每个Pod将收到其Sidecar容器。 为了验证这一点,让我们通过转到[istio-mastery]存储库的根目录并运行以下命令来安装测试应用程序:

 $ kubectl apply -f resource-manifests/kube persistentvolumeclaim/sqlite-pvc created deployment.extensions/sa-feedback created service/sa-feedback created deployment.extensions/sa-frontend created service/sa-frontend created deployment.extensions/sa-logic created service/sa-logic created deployment.extensions/sa-web-app created service/sa-web-app created 

扩展服务之后,我们将通过执行kubectl get pods命令并确保在READY列下指示值2/2表示Pod有两个容器(带有服务本身及其附带的容器),这表明两个容器都在运行:

 $ kubectl get pods NAME READY STATUS RESTARTS AGE sa-feedback-55f5dc4d9c-c9wfv 2/2 Running 0 12m sa-frontend-558f8986-hhkj9 2/2 Running 0 12m sa-logic-568498cb4d-2sjwj 2/2 Running 0 12m sa-logic-568498cb4d-p4f8c 2/2 Running 0 12m sa-web-app-599cf47c7c-s7cvd 2/2 Running 0 12m 

看起来像这样:


在其中一个吊舱中的特使代理

现在,应用程序已启动并运行,我们需要允许传入流量进入应用程序。

入口网关


达到此目的(允许群集中的流量)的最佳实践是通过Istio中的Ingress网关 ,该网关位于群集的“边界”,并允许您启用Istio功能,例如路由,负载平衡,安全性以及对传入流量的监视。

在安装Istio的过程中,将Ingress Gateway组件和将其转发到外部的服务已安装到群集中。 要找出服务的外部IP地址,请执行以下操作:

 $ kubectl get svc -n istio-system -l istio=ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP istio-ingressgateway LoadBalancer 10.0.132.127 13.93.30.120 

我们将继续通过此IP访问应用程序(我将其称为EXTERNAL-IP),因此为了方便起见,我们将值写入变量:

 $ EXTERNAL_IP=$(kubectl get svc -n istio-system \ -l app=istio-ingressgateway \ -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') 

如果您现在尝试通过浏览器访问此IP,则会收到“服务不可用”错误,因为 默认情况下,Istio会阻止所有传入流量,直到定义了网关为止。

网关资源


网关是Kubernetes中的CRD(自定义资源定义),在群集中安装Istio并激活指定端口,协议和我们要允许传入流量的主机的功能后定义。

在我们的情况下,我们希望允许所有主机的HTTP流量进入端口80。 该任务通过以下定义http-gateway.yaml )实现

 apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: http-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" 

除了istio: ingressgateway之外,此配置不需要任何说明。 使用此选择器,我们可以指示将配置应用于哪个Ingress Gateway。 在我们的示例中,这是Ingress Gateway控制器,默认情况下已安装在Istio中。

通过调用以下命令来应用配置:

 $ kubectl apply -f resource-manifests/istio/http-gateway.yaml gateway.networking.istio.io/http-gateway created 

现在,网关允许访问端口80,但不知道将请求路由到何处。 这将需要虚拟服务

虚拟服务资源


VirtualService告诉Ingress Gateway如何路由群集中允许的请求。

通过http-gateway对我们的应用程序的请求必须发送到sa-frontend,sa-web-app和sa-feedback服务:


使用VirtualServices配置的路由

考虑应发送到SA-Frontend的请求:

  • /路径上的完全匹配项应发送到SA-Frontend以获取index.html;
  • 带有/static/*前缀的路径必须发送到SA-Frontend才能接收前端使用的静态文件,例如CSS和JavaScript;
  • 属于正则表达式'^.*\.(ico|png|jpg)$'路径必须发送到SA-Frontend,因为 这些是页面上显示的图像。

通过以下配置sa-virtualservice-external.yaml实现实现

 kind: VirtualService metadata: name: sa-external-services spec: hosts: - "*" gateways: - http-gateway # 1 http: - match: - uri: exact: / - uri: exact: /callback - uri: prefix: /static - uri: regex: '^.*\.(ico|png|jpg)$' route: - destination: host: sa-frontend # 2 port: number: 80 

重要事项:

  1. 这个VirtualService引用通过http-gateway发出的请求;
  2. destination定义了将请求发送到的服务。

注意 :上面的配置存储在sa-virtualservice-external.yaml文件中,该文件还包含SA-WebApp和SA-Feedback中的路由设置,但为简洁起见,本文中对此进行了缩短。

通过调用以下命令应用VirtualService:

 $ kubectl apply -f resource-manifests/istio/sa-virtualservice-external.yaml virtualservice.networking.istio.io/sa-external-services created 

注意 :当我们使用Istio资源时,Kubernetes API Server会引发一个接收Istio控制平面的事件,然后将新配置应用于每个Pod的Envoy代理。 而且Ingress Gateway控制器似乎是Control Plane中配置的下一个Envoy。 图表上的所有内容如下所示:


用于查询路由的Istio-IngressGateway配置

情感分析已在http://{EXTERNAL-IP}/ 。 如果您的状态为“未找到”,请不要担心: 有时配置会花一点时间才能生效,并且Envoy缓存也会更新

在继续之前,请与该应用程序进行一些合作以产生流量(为了清晰起见,在下一步中需要它的存在-大约Transl。)

Kiali:可观察性


要进入Kiali管理界面,请运行以下命令:

 $ kubectl port-forward \ $(kubectl get pod -n istio-system -l app=kiali \ -o jsonpath='{.items[0].metadata.name}') \ -n istio-system 20001 

...并打开http://本地主机:20001 / ,以admin / admin登录。 在这里,您会发现许多有用的功能,例如,检查Istio组件的配置,基于在拦截网络请求时收集的信息来可视化服务,以及获得以下问题的答案:“谁与谁联系谁?”,“哪个版本的服务崩溃了?” 等 通常,在继续使用Grafana可视化指标之前,探索Kiali的可能性。



Grafana:指标可视化


Istio中收集的度量标准进入Prometheus,并通过Grafana进行可视化。 要进入Grafana管理界面,请运行以下命令,然后打开http:// localhost:3000 /

 $ kubectl -n istio-system port-forward \ $(kubectl -n istio-system get pod -l app=grafana \ -o jsonpath={.items[0].metadata.name}) 3000 

通过单击左上角的“ 主页”菜单并选择左上角的Istio服务仪表板 ,从sa-web-app服务开始查看收集的指标:



在这里,我们正在等待一个空洞且完全无聊的性能-管理层永远不会批准这一点。 让我们使用以下命令创建一个小的负载:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

现在,我们有了更好的图表,此外,还有出色的Prometheus监控工具和Grafana可视化指标,这将使我们能够了解服务的性能,运行状况,改进/降级情况。

最后,让我们看一下服务中请求的踪迹。

Jaeger:追踪


我们将需要跟踪,因为我们拥有的服务越多,找到失败原因的难度就越大。 让我们从下面的图片中看一个简单的情况:


随机失败请求的典型示例

请求来了,跌倒了- 原因是什么? 第一次服务? 还是第二个? 两者都有例外-让我们看看它们的日志。 您多久发现自己这样做一次? 我们的工作更像是软件侦探,而不是开发人员……

这是微服务中一个普遍存在的问题,通过分布式跟踪系统解决了该问题,在分布式跟踪系统中,服务相互传递一个唯一的标头,然后将此信息重定向到跟踪系统,然后将其映射到请求数据。 这是一个例子:


TraceId用于标识请求。

Istio使用Jaeger Tracer,它实现了独立于供应商的OpenTracing API框架。 您可以使用以下命令访问Jaeger用户界面:

 $ kubectl port-forward -n istio-system \ $(kubectl get pod -n istio-system -l app=jaeger \ -o jsonpath='{.items[0].metadata.name}') 16686 

现在转到http:// localhost:16686 /并选择sa-web-app服务 。 如果该服务未在下拉菜单中显示,请在页面上显示/生成活动并更新界面。 之后,单击“ 查找跟踪”按钮,它将显示最新的跟踪-选择任何-所有跟踪的详细信息将出现:



此跟踪显示:

  1. 该请求到达istio-ingressgateway (这是与其中一个服务的首次交互,并且为该请求生成跟踪ID),然后网关将请求发送到sa-web-app服务
  2. sa-web-app服务中,请求由Envoy sidecar接收,在跨度中创建了一个“子”(因此我们在跟踪中看到了它),并将其重定向到sa-web-app容器。 跨度是Jaeger中的逻辑工作单元,具有名称,操作开始的时间及其持续时间。跨度可以嵌套和排序。跨度的定向无环图形成迹线。-大约翻译。)
  3. 在这里,请求由sentimentAnalysis方法处理。 这些跟踪已由应用程序生成,即 他们需要更改代码。
  4. 从这一刻起,开始向sa-logic发送POST请求。 跟踪ID必须从sa-web-app转发。
  5. ...

注意 :在第4步中,应用程序应查看Istio生成的标头,并将其传递给后续请求,如下图所示:


(A)Istio负责转发标头; (B)服务负责标题。

Istio负责大部分工作,因为 生成用于传入请求的标头,在每个sidecare中创建新的跨度并将其转发。 但是,如果不使用服务内部的标头,则请求跟踪的完整路径将丢失。

应考虑以下标题(转发):

 x-request-id x-b3-traceid x-b3-spanid x-b3-parentspanid x-b3-sampled x-b3-flags x-ot-span-context 

这是一项简单的任务,但是,为了简化其实现,已经存在许多库 -例如,在sa-web-app服务中,如果仅根据添加Jaeger和OpenTracing库,则RestTemplate客户端会转发这些标头。

请注意,“情感分析”应用程序演示了Flask,Spring和ASP.NET Core的实现。

现在,我们已经清楚了开箱即用(或者几乎是“开箱即用”)的内容,请考虑微调路由,网络流量管理,安全性等问题!

注意事项 佩雷夫 :请在下一期Rinor Maloku的Istio中了解此信息,该信息将在不久的将来在我们的博客中提供。 更新 (3月14日): 第二部分已经发布。

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN438426/


All Articles