istio官方中文文档(istio 入门)

http://www.itjxue.com  2023-02-17 02:27  来源:未知  点击次数: 

六、跨语言微服务框架 - Istio日志采集EFK

ELK日志系统大家不会陌生(zipkin + jaeger , prometheus + grafana)解决了大家对于链路对于统计采集的需求,但是真正的对于日志进行存储还是得专业的上,在Istio中官方提供的方案是EFK(Fluentd + Elasticsearch + Kibana)Fluentd 是一个开源的日志收集器,支持多种数据输出并且有一个可插拔架构。 Elasticsearch是一个流行的后端日志记录程序, Kibana 用于查看。

附上:

喵了个咪的博客: w-blog.cn

Istio官方地址:

Istio中文文档:

我们把Fluentd,Elasticsearch 和 Kibana 在一个非生产集合 Services 和 Deployments 在一个新的叫做logging的 Namespace 中。

创建资源

现在有一个正在运行的 Fluentd 守护进程,使用新的日志类型配置 Istio,并将这些日志发送到监听守护进程。

创建一个新的 YAML 文件来保存日志流的配置,Istio 将自动生成并收集。

使其生效

我们先访问以下我们的示例程序bookinfo,然后老方式通过端口映射访问kibana

基于OIDC实现istio来源身份验证

本文介绍如何生成可以经过istio来源身份验证的jwt token。istio的来源身份验证是通过OpenID connect规范实现的,这里只需要遵循OIDC的小部分规范便可以实现可以通过验证的token。

首先来看一下istio官方文档对来源身份验证的说明:

ISTIO的来源身份验证通过ENVOY完成,看一下envoy官方文档对JWT的说明:

可以知道,istio会对token的 signature 、 audiences 、 issuer 三个属性进行校验,也会对有效期进行检查,而且只支持ES256和RS256两种算法,因此我们需要保证我们的token生成中这三项属性的规范性。

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,简单来说,一个JWT的TOKEN由三部分组成:

最终的结构如下:

如下:

OpenID Connect 是一套基于 OAuth 2.0 协议的轻量认证级规范,提供通过 API 进行身份交互的框架。较 OAuth 而言, OpenID Connect 方式除了认证请求之外,还标明请求的用户身份。

简单来说,我们需要提供一个符合OIDC规范的认证服务端,它需要提供token生成能力和token校验所使用的公钥。认证服务端保管好一组签名所用的私钥,生成token时选择一个私钥对token进行签名并在token中注入相关信息(比如对应的公钥ID、算法、issuer、audiences、有效期等)。然后认证服务端需要提供一个接口来开放所有的公钥,这样ISTIO才能拿到公钥对token进行校验。

上述都是OIDC规范的一部分,这里并不严格实现OIDC规范,仅仅为了实现istio的来源身份验证。

maven

用于对公私钥二进制内容的加解密,可以自行选择其他方式。

这里使用RS256算法,注意管理好keyId,这里我把公私钥都使用base64格式化,方便后续操作。

jwk.toJson()返回的内容是一个JSON,我们需要记录一下公钥的JSON用于开放给istio。

公钥JSON示例:

这里的公钥是经过OIDC规范特殊格式化的,不是base64。

注意issuer、keyId、clientId、subject等值的统一,要与下一步的开放接口一致,注意有效期可以自己定义,也可以向token中注入自定义的信息。

使用rest开放公钥(OIDC规范)

最终该接口的返回值如下所示,可以自行设计接口,该接口的访问地址用于配置在istio中。

这里提供一个最简单的实现,推荐自行根据需求开发。

maven依赖

实体类

接口

严格的OIDC规范,还需要开放一个接口用于声明所有的接口和相关的约束,包括jwksUri。该接口的访问路径是issuer/.well-known/openid-configuration,这里不再详细介绍,有兴趣的可以自行研究,或者等待后续的文章。

可以参考一下谷歌的OIDC,比如谷歌的issuer是 ,则对应的接口是 ,当然里面有许多属性可能是谷歌特有的,详细可以参考OIDC的官方文档。

在istio中为想要执行来源身份验证服务配置一个policy,issuer与生成token时一致,jwksUri就是用于开放公钥的接口地址。如果不提供jwksUri,那么就会使用issuer/.well-known/openid-configuration来访问OIDC的声明接口,来找到jwks_uri并拿到公钥。

还支持排除某些路径,或仅作用于某些路径(摘自官方文档)

详情参考官方英文文档

个人能力有限,如有错误,欢迎指正!

有兴趣的可以研究一下一些开源的实现OIDC规范的框架的源码,可以有更加深入的了解。

使用 Istio 进行路由策略的配置

本篇来讲一下如何使用 Istio 进行路由的配置,在这里直接使用 Istio 官方提供的案例应用来进行演示,首先部署 bookinfo 服务

部署完成后可以通过以下命令来看到 Pod 和 Service:

用以下命令来验证部署成功:

成功时将看到输出为 titleSimple Bookstore App/title 。

到目前为止,部署的服务还无法在外网访问,需要配置一个Istio 网关来映射相应的路由。

完成后用以下命令来验证,若是验证无误则表示网关已成功部署:

下面需要确定外网访问的 IP 和端口,在此之前,先确认自己的集群是否支持外部的负载均衡:

这里的关键点就是看有没有 EXTERNAL-IP ,若是有,则表示支持外部负载均衡,若没有则不支持。对于我们自己部署的 K8S 单机集群,默认是不支持的。

对于支持外部负载均衡的集群,使用以下命令来确认外部访问的 IP 和端口:

对于不支持外部负载均衡的集群,使用以下命令来确认外部访问的 IP 和端口:

如我的集群,得到的信息是以下:

此时在外部的浏览器上,即可以用以下 URL 访问到部署好的服务了:

打开页面后进行几次刷新,会发现在页面右侧的 Books Reviews 处,会有三种呈现形式,如下:

通过查看 kubectl get pods 也可以发现,reviews 服务有三个,也就是说对于 reviews 的请求,被路由到了不同的 Pod 进行处理。

那这个过程中发生了什么呢?我们有必要来一探究竟。

首先通过 kubectl get pods 命令,查找到 productpage 的容器名称,在我本机上是 productpage-v1-65576bb7bf-gncds ,有了这个名称后,就可以做很多事情了, 先查一下 Istio 的集群信息:

将会得到的输出是:

再看一下 reviews.default.svc.cluster.local 的 endpoint ,应当可以看到三个:

得到的结果如下,确实是三个,即是说请求确实会被路由到这三个 endpoint 之中

那么具体是怎么进行路由的呢,我们需要查看路由信息:

将会打出一个 json,这里只截取 reviews 的那一段:

这个配置即是表示,发往 reviews.default.svc.cluster.local:9080 的流量,将会被转发到 outbound|9080||reviews.default.svc.cluster.local ,而这个 集群后面有三个 endpoint,所以在访问的时候,是轮询出现的,这直接解释了在请求时,三种不同的页面会轮询出现的现象。

那么,如果要只允许路由到一个 endpoint 要怎么办呢?我们就需要给 endpoint 进行标号:

再看一下集群的情况:

可以看到已成功添加了,接着再看一下 endpoint 的情况:

可以看到的是,endpoint 也都被成功添加了。

下面就可以写一个配置,来让流量只转发到 v1:

然后执行命令让配置生效:

再看一下路由的情况,会发现只能转发到 v1 了,如下:

此时再刷新页面,就只有一种样式了,证明了流量只进入了 v1。

同理,我们还可以配置转发到 v2, v3:

如果要删除路由的规则,可以使用以下命令:

这样在页面刷新时,就又会重回在三种样式里切换的状态了。

最后,再来看一个可视化的 DashBoard,有了 DashBoard 之后,可以方便直观的看到配置的情况,要安装 DashBoard 也不难:

部署成功后,可以用 kubectl get serivces -A 命令看到 kiali 服务,并获知其监听 20001 端口。按官方文档,可以用以下命令在本机访问 Kiali:

但是我们部署的是 Ubuntu Server 版,没有桌面,也没有浏览器,所以这一步注定会失败。解决方法也很容易,编辑一下服务:

在 spec 配置下加入 externalIPs 即可:

直接保存即可,然后从外部浏览器使用以下 URL 即可以访问 Kiali:

此时即可以看到服务的图表状态,并且看到请求的负载和链路:

Service Mesh - Istio流量控制篇(下)

上篇:

Ingress 基本概念:

部署 httpbin 服务,同样,官方demo已经提供了该配置文件,执行如下命令应用即可:

为 httpbin 服务配置 Ingress 网关,定义 Ingress gateway,如下所示:

然后定义 Virtual Service 配置路由规则并关联该 Gateway:

使用如下命令获取 istio-ingressgateway 服务的实际请求地址和端口号(但服务的 EXTERNAL-IP 为 pending 或 none 时采用此方式,详见: 官方文档 ):

接下来使用 curl 命令测试一下 httpbin 的接口能否正常访问:

访问没有被暴露的接口,此时返回404:

有进入网格的流量也就有从网格出去的流量,这种入口流量与出口流量也就是我们常说的南北流量,在Istio中我们可以对网格的入口和出口流量进行管控。

Istio中访问外部服务的方法:

Egress 概念:

在本小节,我们将实践创建一个 Egress 网关,让内部服务(sleep)通过它访问外部服务(httpbin.org),这两个服务在前面的章节示例中都已经演示过了:

查看 istio-egressgateway 组件是否存在:

确认 sleep 服务已处于正常运行状态:

为 httpbin.org 这个外部服务定义 ServiceEntry:

确认创建成功:

定义 Egress gateway:

定义路由,将流量引导到 istio-egressgateway:

测试访问 httpbin.org 服务的接口:

查看日志验证出口流量是否经过了Egress网关,输出了如下日志信息代表Egress网关配置成功,出口流量经过了该Egress网关:

此时 sleep 服务访问外部服务的流程如下图:

对于一个分布式系统来说,出现网络故障是在所难免的,因此如何提升系统弹性,提升系统在面对故障时的处理能力是分布式架构非常重要的一个主题。其中,超时和重试是非常重要且常用的,用于提升系统弹性的机制。

基本概念

接下来我们还是通过Bookinfo这个应用来作为演示,对其中的一些服务添加超时策略和重试策略。我们会将请求指向 reviews 服务的 v2 版本,并在 ratings 服务中添加延迟设置,模拟一个故障出现的情况,以此来验证我们设置的超时和重试策略是否生效:

首先,创建一个Virtual Service将请求路由到 reviews 服务的 v2 版本:

给 ratings 服务注入延迟,模拟故障:

给 reviews 服务添加超时策略:

此时刷新应用页面,可以看到返回了错误信息:

将 reviews 服务的超时策略取消掉,然后给 ratings 服务添加重试策略:

查看 ratings 服务的 Sidecar 日志,然后刷新应用页面,正常情况下从日志输出可以看到重试了两次请求:

配置选项 :

什么是 断路器(Circuit Breaking)?

本小节我们实践一下为 httpbin 服务 添加断路器配置 ,然后通过负载测试工具来触发熔断。断路器相关配置是在服务的 DestinationRule 中里进行配置的,如下所示:

安装fortio,使用该负载测试工具来触发熔断:

先尝试发送单个请求,确认该工具能够正常工作:

没问题后,通过如下命令进行并发压测,并发数是3,执行30次:

如果希望查看具体指标可以使用如下命令:

配置选项 :

了解 故障注入(Fault injection) :

在配置好网络(包括故障恢复策略)后,我们可以使用Istio的故障注入机制来测试应用程序的整体故障恢复能力。故障注入是一种将错误引入系统以确保系统能够承受并从错误条件中恢复的测试方法。

所以故障注入机制特别有用,可以提前暴露一些故障恢复策略不兼容或限制性太强,从而可能导致的关键服务不可用的问题。故障注入在业界的发展和应用例子:

其实我们在之前的小节中早已演示过了Istio的故障注入配置,在超时与重试的小节中,我们就为 ratings 服务注入过一个延迟故障:

使用如下命令将Bookinfo应用各个服务的路由信息设置到各自的 v1 版本:

然后将 reviews 服务的流量指向它的 v2 版本,因为只有 v2 和 v3 版本才会调用 ratings 服务:

给 ratings 服务注入延迟故障:

virtual-service-ratings-test-delay.yaml 文件的内容:

配置选项 :

相信很多开发人员都遇到过这样的问题,就是在开发/测试环境中运行良好的功能,一上线就出问题。即便做足了单元测试、集成测试,测试覆盖率也很高,也依然会有这种问题存在,并且这类问题在开发/测试环境难以复现。

出现这种问题的一个主要原因,是因为线上环境,特别是数据环境,比如说数据量、请求的并发量以及用户使用数据的方式都与开发/测试环境非常的不一样。由于这种不一致性导致我们很难在开发/测试环境中发现线上的问题。

那么一个非常好的解决办法,就是使用流量镜像机制,将线上流量复刻一份到开发/测试环境中进行测试。

了解 流量镜像(Traffic Mirroring) :

流量镜像(Traffic mirroring,也称为Shadowing)是一个强大的概念,它允许开发团队以尽可能小的风险为生产环境带来更改。流量镜像机制可以将实时流量的副本发送到一个镜像服务。对流量的镜像发生在主服务的关键请求路径之外。

接下来我们实践一下如何配置Istio中的流量镜像机制,需求是将发送到 v1 版本的流量镜像到 v2 版本。因此,我们首先部署 httpbin 服务的 v1 和 v2 版本。v1 版本的配置如下:

部署 httpbin 服务的 v2 版本:

为 httpbin 创建一个 Service 资源,让 Pod 能够通过服务的方式暴露出来:

为 httpbin 服务创建默认的虚拟服务与目标规则:

测试一下能否正常访问到 httpbin 服务的接口:

完成以上的准备工作后,我们就可以在虚拟服务中为 httpbin 服务的 v2 版本配置对 v1 版本的流量镜像:

尝试请求 httpbin 服务的接口,由于我们配置了路由规则,该请求一定是被路由到 v1 版本上的:

此时观察 v2 版本的日志,从日志输出中可以发现 v2 版本也接收到了相同的请求,代表我们的流量镜像配置生效了:

配置选项 :

Istio是什么?

Istio是由Google、IBM和Lyft开源的微服务管理、保护和监控框架。Istio为希腊语,意思是”起航“使用istio可以很简单的创建具有负载均衡、服务间认证、监控等功能的服务网络,而不需要对服务的代码进行任何修改。你只需要在部署环境中,例如Kubernetes的pod里注入一个特别的sidecar proxy来增加对istio的支持,用来截获微服务之间的网络流量。

特性:

使用istio的进行微服务管理有如下特性:

流量管理:控制服务间的流量和API调用流,使调用更可靠,增强不同环境下的网络鲁棒性。可观测性:了解服务之间的依赖关系和它们之间的性质和流量,提供快速识别定位问题的能力。

策略实施:通过配置mesh而不是以改变代码的方式来控制服务之间的访问策略。

服务识别和安全:提供在mesh里的服务可识别性和安全性保护。

未来将支持多种平台,不论是kubernetes、Mesos、还是云。同时可以集成已有的ACL、日志、监控、配额、审计等。

正是 Istio 的出现使 “Service Mesh”( 服务网格 ) 这一概念开始流行起来。在深入介绍 Istio 的细节之前,让我们首先简单地了解一下 Service Mesh 是什么,以及它的重要性体现在哪里。我们都已经了解单体应用所面对的挑战,一种显而易见的方案是将其分解为多个微服务。虽然这种方式简化了单个服务的开发,但对于成百上千的微服务的通信、监控以及安全性的管理并不是一件简单的事。

直至目前,对于这些问题的解决方案也只是通过自定义脚本、类库等方式将服务串联在一起,并且投入专门的人力以处理分布式系统的管理任务。但这种方式降低了各个团队的效率,并且提高了维护的成本。这正是 Service Mesh 大显身手的时机

Istio以及Service Mesh的未来

istio ServiceEntry的使用

默认istio不会监控调用到网格外的服务/接口,必须使用ServiceEntry把外部服务加入到istio内部的service registry,把外部服务建模为istio内部的一个service

根据ServiceEntry文档 如下图

对于http服务,istio生成route config中的domain会包含hosts和addresss, 以下面的ServiceEntry为例:

可以使用如下方法访问

注意,配置中的addresses中的ip和endpoints中的ip没有任何关系, 不需要一致,也不需要是个真实存在的ip,可以是一个vip; 事实上hosts和addresses的作用仅仅是用作VirsualHost的domain,和实际流量的转发无关系;envoy实际并不监听这个ip,而是直接监听端口0.0.0.0:3001;

当然如果ServiceEntry中没有配置endpoints,resolution配置为None,那么addresses ip会直接作为destionation ip;

上述的hosts + addresses对应envoy的listerner 和 route config如下:

listerner

route config

所以上面的ServiceEntry其实还可以这么访问,因为port + domain能匹配上对应的VirtualHost

总结: 基于上述的知识,对于外部http服务,只需每个服务建一个ServiceEntry即可;使用域名的服务配置对应的hosts,不用配置addresses; 使用ip的服务配置正确的addresses, 而hosts配上一个有区分度的name(监控图表会用到)接口

先贴个官方文档上的TCP类型的ServiceEntry的例子

留意上面的addresses仍然是VIP,TCP服务访问是使用addresses匹配ServiceEntry的, hosts任何用处都没有;

这也很容易理解,TCP请求中,使用DNS根据domain得到ip,后续的流量都跟domain name没有任何关系了,TCP中是没有Host: domain name 这样的header的

所以对于TCP服务,把ip list配到address上即可(无需再去创造个额外的vip);

endpoints应该也不用指定,对于redis这种读写分离的服务,把ip list作为endpoints估计还是有问题的,如果一定要加endpoints应该需要对writer和reader分开建模;

至于hosts,有的话就配上; 没有的话,一样取个有区分度的name(监控图表会用到)

我们使用最开的http service entry作为demo

使用如下的服务进行测试, sleep和test-app是在istio中的服务,external-service-http就对应上面的ServiceEntry

从sleep中发起请求调用test-app(这是个http服务), test-app中通过调用ServiceEntry对应的外部服务;

istio的管理工具kiali可以自动生成这样的调用关系图

grafana中可以看到ServiceEntry对应服务的监控图表

tracing也可以追踪相关的调用链路

(责任编辑:IT教学网)

更多

推荐Dreamweaver教程文章