1.1 istio介绍及安装
基于spring-cloud去实现微服务的时候,实现服务治理,spring是基于java的,如果要所有语言都支持服务治理,就需要istio
服务网格是一种概念,只是一种思想,istio只是其中一种实现
spring cloud无法去跨平台。先把这两个理解为两个pod,如果两个服务pod要进行通信治理,基本实现就是放在业务代码里
service mesh是这么做的,在pod里加上容器,通常称为sidecar边车,流量都会经过sidecar,就可以进行一些流量的处理,就可以理解为每个业务的pod添加了类似nginx的容器,也就是服务治理的能力被放到了sidecar里,业务代码还是怎么写就怎么写,只不过代码里不写服务治理相关内容,服务治理的能力放到了平台上
sidecar里可以做很多事情,服务注册,健康检查,流量熔断
蓝色的是边车,边车之间做通信,流量和流量之间的传递是放在平台里
在你的服务旁边加上了代理层
service mesh服务网格是一种思想,它的实现,第一代是linker的和envoy,更多偏向于代理层的实现
对于这个控制层面做的不好,可以写配置,配置如何下发给你
第二代的istio事实上是service mesh的一个标准,实际上是在envoy基础上进行改良,补足了控制平面的功能
流量来走的都是微服务的proxy(可以叫envoy,sidecar,就是一个容器),流量进入到代理,出去的流量也会经过代理
转发控制的规则,是控制层面下发代理的
下载好istio版本
客户端控制工具
复制命令到path路径下
1.7.3版本
有个命令补全,需要去执行shell
查看一下profile是什么意思
可以理解为不同的配置,跟买车类似,istio的配置有这么几个
选择default,就有这么几个组件是安装的,X号代表安装
istiod就是控制平面的
查看安装的哪些组件是安装的可以查看这个链接
istioctl里有 manifest generate生成,按照指定的profile生成yaml文件
想看demo项有哪些
都是一些K8S的资源
会多一个命名空间
其实就是起了三个deployment,建立三个service
crd是istio自己实现的功能需要创建的
这样istio就安装好了,卸载就是把K8S里这么些资源删除
1.2 istio流量模型示例一
有一个前端服务,是一个前端v1 deployment版本的服务,后面是账单服务,由一个账单V1 deployment版本,前端暴露一个service账单服务去访问
先创建前端的
pod容器里用这个命令来启动
还缺一个service
匹配的是bill-service
也就是这个
先创建istio-demo命名空间
现在有一个service
进入tomcat容器,curll一下service name来访问服务
返回bill 1
第二个模型,后台要更新,现在是v2版本
创建这个资源
现在是两个pod
但是现在访问基本上流量是均衡的
k8S服务是百分百的公式
访问的时候,第一步是域名解析,解析成ip地址
另外i一个pod其实也可以访问
解析出来是这样
这个地址就是bill-service的clusterip地址
也就是这两个是等价的
进pod容器看路由,这个是flannel的ip段
明显没有10.105.42的ip段
所以只能转发到gateway,10.244.2.1的网关上去
是在主机上的
也就是访问的流量,转发到宿主机上去了
但是宿主机没有这个10段的路由
iptale里有这个实现,地址是10.105.42.173地址的流量,都转发到KUBE-SVC-PK4BNTKC2
多了一个random转发 ,0.5百分之50概率转发到KUBE-SEP-HMSXX67,剩下的转发到另外一个
两个pod,多了DNAT,转发到pod上
coredns维护的规则,你改不了,是希望流量都均分的,但是如果要90,10%就需要istio了
现在每个pod都只有一个容器
现在需要在服务里加上sidecar,inject注入
生成了一堆的yaml文件
注入后的yaml,前面都没变
影响功能的在spec里
这是一部分
从这里开头
到这里
额外加了istio-proxy名字的容器,也就是所谓的边车容器
还加了一个初始化的容器,执行了一些命令,这个容器执行后就退出了,就是做了一些iptable规则
直接部署
在原来的基础上加上了istio的边车容器
前端,和v2版本都注入一下
等于一个小的网格,现在有三个节点
规则怎么写是一个点,流量如何区分两个版本不同
一般定义一个destnation-rule,destnation-rule是区分两组服务的,起个名字,然后命名空间
subset相当于一组,下面定义了一个数组,第一组v1,匹配的是version =v1的,第二组v2
不能匹配所有的v1,v2,是匹配前面的bill-service下的v1,v2
这样就在istio内部,给这两个pod起了名字
下面就要定义转发规则了,定义virtualservice,是用来加规则的
hosts是bill-service-route,http流量,下面是route路由
权重90的目的地是bill-service下的v1,权重10放bill-service下的v2
创建好这个规则后,就等于告诉网格内的服务,找bill-service这样的名称的,都会按照这个路由规则走。90%的流量走v1,10%流量走v2
实现一下
先创建destnation-rule
vs就是virtualservice缩写
从前端的pod里访问bill-service的服务
一定要选择-c进入到哪个容器里
网格内部去访问bill-service,大概是9比1 的关系
理解envoy
9比1的规则是virtualservice定义的
最终影响到这个pod的是十分复杂的
如果是nginx,就是这么配置的
加了两个容器,istio-init,istio-proxy
进入到istio-proxy看一下
envoy其实是一个代理,轻量级的代理
通过K8S的api创建一个service,存储到ETCD里
istiod会去watch我们创建的virtualservice规则
每个pod都增加一个envoy,istio容器,istiod感知到用户创建的规则后,由istiod的server端把配置同步到envoy
envoy的配置文件肯定和创建的virtualservice规则是不一样的,格式是不一样的,istiod是做转换用的
istiod监听到创建的virtualservice规则
大致了解一些envoy
nginx也是代理,envoy也是代理
现在看nginx如何迁移到envoy
上面是nginx配置,下面是envoy配置,nginx的server在envoy里叫监听器
location就是路由
在envoy里叫过滤器
最核心的这个,可以过滤http请求,把一些包转换成http的格式
流量到了filter后,经过route_config,后面有一些匹配条件
proxy和upstream对应envoy的集群
也就是nginx的配置都可以转换成envoy的配置,envoy里有一些概念
转发后的envoy配置文件如下
envoy会启动一个端口,作为管理端口
后面都是envoy的配置
起了一个监听器listener_0,监听本地10000端口
获取的流量交给filter_chains来处理
匹配斜杠做一个路由,转发到some_service这样一个cluster集群上去,类似nginx的upstream
service是什么,是下面clusters定义的
启动envoy1.15.2的版本,这个yaml文件放到容器里/etc/envoy/envoy.yaml
期望转到service的cluster-ip是10.105.42.173
envoy就是个代理
核心的概念,就是监听器
filter_chains里有http_connection_manager,处理http流量,匹配路由规则,转发到cluster上去
配置云上ELB,SLB,也是要配置监听器,加上路由转发规则
envoy核心的概念XDS
静态配置就是yaml文件,动态配置就是可以通过接口从别的地方动态获取到了
监听器其实是可以动态的,L(listener)D(discover)S(service)
还有一个配置是RDS,route的配置也可以动态的,不用写死
CDS也是可以动态的
EDS也可以动态
LDS,RDS,CDS,EDS统称为XDS,X代表变量,这些就是envoy适合云环境下的特性,所有环境都是不固定的,信息是存到etcd里去的
最核心的就是listener,cluster,route,endpoint,也就是lds,cds,rds。eds
全都是通过xds接口去获取的,envoy可以动态获取配置来提供服务
从client发起流量,发到listener之上,经过lds,cds,eds,就会知道让请求访问哪个endpoint地址,然后最终到真正提供服务的机器上去
下面是listener替换的部分,listener filter是改一些元数据的(可以不去看),监听器里有filter_chains
使用envoy的,就是有请求,通过监听器,通过route转发给cluster,最终把请求转发给提供服务的机器上去,配置不仅仅可以是静态还可以是动态的,xds可以满足
envoy其实就是一个代理
对于K8S来讲,envoy就是istio-proxy容器里的进程,可以监控流量,可以进行熔断,追溯
envoy只是一种能力,你需要服务端才能去提供接口告诉envoy,可以通过着接口获取什么数据,istio里的pilot转眼间就提供了xds服务端接口的实现。
里面有一个pilot-discover服务,这个进程其实就提供了envoy服务所需要的xds服务接口,也就是xds的服务端
工作原理
看看问题1,envoy的动态配置长什么样子
这个就是envoy的管理端口
envoy需要一个配置文件
有一段管理配置,监听端口和地址
访问端口其实可以获取一些内容
envoy的信息可以从这里获取
下载envoy的配置
这个配置文件非常长
700多KB的配置
几个大点最主要的配置
这一个内容就比较复杂
现在在网格内部,没注入istio,是先解析bill-serviceip地址,路由到主机上,访问9999端口
注入之后就是这么走的了
如果是在前端tomcat访问的,流量会转到istio-proxy这个容器里,它去把流量转发到不同版本的服务
istio-init就是去修改iptables规则
iptables,4表5链
流量进去prerouting链,是input链还是forward链看是否是本机地址,
本机的流量会到本机的堆栈,然后转发到output链,转到postrouting链
istio-proxy如果要进行流量的管理,一定要拦截tomcat的流量,也就是istio-proxy在自己的postrouting加个规则就可以拦截请求了,如何去拦截请求就是istio-init要做的,初始化iptables规则
istio做了一次iptables的封装
-p是重定向所有tcp出站流量,也就是所有的出站流量转发到15001上,-z所有进入pod/vm的tcp流量应该被重定向到的端口(默认$INBOUND_CAPTURE_PORT)
拦截了所有的出站和入站
最后就放了一个,有一个uid,这个用户,优化自己的请求,放到15090,15021,15020的端口i上,除此之外所有请求拦截
现在id是0,发起请求
一定会被拦截到,因为不符合条件,不符合uid是1337发起的,也不是访问的15090,15021,15020,所以istio会进行拦截
上面的这条规则其实就是下面的描述,15090是做prometheus的telemetry,15020是做ingress,15021是做监控检查的
如果拦截了,就等于自己拦截自己的,进入死循环了
istio-init就是初始化iptable规则,让istio-proxy这个容器拦截出站入站流量**可以看istio-proxy里的规则,在slava1上********找到这个进程对应的pid****iptables规则是在pod设置的,是有独立的网络空间的****可以进入到网络空间,查看规则****prerouting是来入栈的。转到了15006********tcp规则,转到了istio_inbound规则,所有入站tcp流量跳转到istio_inbound上****除了这几个端口之外的,剩下的都转到了istio_in_redirect里****这里是-d生成的****排除了不是业务的流量,都转到15006端口,envoy只需要监听15006端口,拿到这个入站流量****-p是出站流量****所有出站流量转发到了istio_output****这样就拦截了每个pod的流量****15001是拦截所有出站的。15006是拦截所有入站的****业务的流量直接被转到了istio-proxy,经过处理,发送到业务端,业务端istio-proxy监听的是15006(接收所有入站)**
是被15001拦截到了,如何转发,envoy有监听器,filter_chains**这个命令可以只拿到关心的片段****出站是15001拦截的,(两个端口15006,15001)********在front-tomcat发请求,在istio-proxy被拦截,就要到istio-proxy查看这个pod的监听器全部的太长了,很难找********例子,可以查看端口****有一个15001的,这里是一个缩写****出现了一个15001的监听器,但是没有做处理****使用原始的IP地址和端口****对流量只是做了通过,并没有做其他处理****这个请求其实是被15001拦截到了********流量只是做了passthroughcluster处理****15001不处理,转给了服务本身的9999端口****正常里面会有下面的一个监听器****查看监听器的样子****rds是动态的路由,监听器转到了9999route上去了****名字就叫9999****这一项看起就是,匹配所有转发到passthroughcluster,但是我们的请求现在不会到这,还有一个比这个更匹配的****上面匹配的是**,只有找不到下面的时候才会去找上面****如果没有*号,就无法访问外网了,所以一定要加个放行的prefix,匹配前缀这里的规则都转换成了istio的规则weightedcluster基于权重的cluster要查这两个名称的clustercluster提供了一个fqdn帮你去查现在查endpoint,不知道怎么查可以-h,查看帮助v1是90%流量的port 80端口104是v2lds(listener),rds(route),cds(clsuter)eds(endpoint)
先查linstener转route,通过route找cluster
流量被istio-proxt的15001监听到,15001并不做处理,直接转发给原始的ip+端口,监听到9999端口的流量才转发给9999端口的服务,就转发到了cluster
找到endpoint的地址以后,等于从istio-proxy内部,envoy curl这个地址但是发起请求后,怎么到pod,还需要走网络,是一个pod的ip地址,在flannel网络可以看到路由这里的istio-proxy是在prerouting链上做了拦截,最终由direct转到1500615006要先查监听器,-h帮助,查是–port转换成jsoninbound入站请求
入站直接交给15006处理15006这里有入站监听器,这个监听器是按端口匹配的也有一个route,处理都交给匹配的cluster后面对应的endpoint匹配80,转到route上去了转到本机的来提供服务创建了一些virtualservice规则,被istiod 识别到,最终转变成了envoy能够识别的配置片段,然后通过istiod的server端。同步到了service端,才能使流量的方向发生变化。envoy的配置片段可以通过 istio config-dump查看,可以查看route,cluster,endpoint**envoy小知识**
意思是这两个pod进行访问,pod里有两个容器,提供服务的容器,以及envoy容器,从productpage这个容器去curl review:9080,然后流量先到达iptable,(注入的时候,通过初始化容器,有iptable配置),有个配置output链上转发到了istio_output,转到了istio_redirect。通过15001(这个端口是被envoy监听的,virtualoutbound ,这是一个listener,)转发到一个orginal的监听器上,匹配到0.0.0.0_9080,经过filter_chains,开始做处理,转到一个route上,找到一个endpoint ip+端口。 转到后端的pod,(后端的envoy监听在prerouting链上,转到istio_in_redirect链上),15006端口进行处理,找到inbound cluster来进行处理
具体的流程还是要istioctl pc来查到tomcat容器去curl在istio-proxy容器里没有按照91的比例走因为这个uid是1337,这个1337的请求并不会被iptable拦截,不拦截就不会到自己的里面去做处理,不走envoy就等于在网格外部一样它走的还是宿主机上的kube-proxy维护的iptable的网络过程,走到宿主机上,宿主机依靠flannel做的iptable转发走了**把着几个kube-proxy干掉,是否会受影响,但是用scale是不行的**********可以这么看,看yaml****这里有一个标签****这样一个没有,就自动退出了**********清理一下nat**
没有这个规则了
这样按照刚才的理论,在istio网格内部就访问不到宿主机了,是直接iistio envoy去拦截了这个流量********
真正去访问的时候其实是pod的IP**清空slave1上的iptable规则****还是可以访问的****master再去清理一下****现在在容器的istio-proxy里******现在把kube-proxy已经停止了,宿主机上的iptable规则已经删除了cluster规则****
删除一个pod试试到外网链接一下
刚才没删除之前应该有解析的缓存容器内部是可以访问到,解析不了,才到宿主机上,但是宿主机IPtable规则没有,还可以访问到,可能有一点问题所有的service都创建了虚拟监听器在pod里去访问服务正常是可以访问到的,这个访问是走的istio的监听istio内部,在集群里的每一个service都建立了一个监听器服务网格istio出现之前就有9000端口的service了下面是service的ip+端口istio是把整个service,加上istio的manager最终转到下面的route查route可以用r可以转换成json看一下domain。匹配/,转到cluster上去,找到endpoint这里都是之前的service创建的监听规则,服务越多listner越长,绝大多数都是outbound的一些监听istio不希望再去用kube-proxy,直接可以在网格内部去管理iptable规则,控制流量只要是在网格里面都有因为istio本身并不知道你这个pod需要去访问哪个服务
这些都是动态维护的,envoy的配置有静态动态,动态的都是根据istiod这个服务
这是一个istio的动态的服务端,是gRPC的服务端转换成envoy的配置段转发给envoy使用ingress-gateway访问网格服务
现在是这样的场景,用户端90%流量去访问v1版本, 10%流量去访问v2版本,实现这样的,就是去创建一个v2版本的pod,同时建立virtualservice虚拟服务去实现selector是app:front-tomcat
下面是deployment文件
app是front-tomcat会被之前的调用到,版本v2需要做的就是创建虚拟服务,通过front-tomcat在istio网格内部去访问到hosts。front-tomcat流量都经过它去匹配,根据route的配置进行转发,90到v1,10到v2
如何区分不同的机器组就是去创建destinationRule,destinationRule其实就是一组cluster
重点是host
service,和上下文的规则
这是创建的virtualservice
需要注入istio
这里是1没有注入
不注入的话从前端访问,待会从前端去访问,通过ingress去访问,就没办法在网格内部
现在访问8080应该是9比1 的流量
现在可以从界面上去访问服务
现在访问的ingress是走的它的上面
现在是1比1,没有按照istiod的规则来走
通过ingress去访问的话,不会按照istiod的规则去访问
因为istio里面去访问
现在是在宿主机上去访问不是在网格内部,注入的istio-proxy容器里是网格内部,现在宿主机走的是网格外部,走的是kube-proxy的iptable
前端页面也是走的ingress,没有走istio,就没有意义,现在要在前端也走istio而不是kube-proxy
ingress只能简单的引流外部的http流量,这里的目的就是凸显了ingress的局限性
就需要用到ingressgateway
mesh boundary是网格内部,外部流量如果想要进入网格内部的一些规则。需要通过ingress gateway组件,引入到mesh gateway也就是sidecar。同样的流量出去,istio内部要去访问网格外部需要通过egress gateway,但是不是必须的,类似curl 百度,直接就可以curl,管理不了抽象的流量
又说了ingress坏话,只支持http的流量。任何高级功能对于ingress来讲实现起来都很麻烦(因为需要重新功能,还不能在同一个ingress里)
现在外部访问还是轮询1比1访问内部
一个集群内部,ingressgateway可以有多个
要去找ingressgateway的
有这样istio=ingressgateway这样的一个label
这个规则就是,定义了这样一个gateway,是由带istio=ingressgateway的这样一个label的pod来处理,ingressgateway有多个,这样就可以在集群里指定找哪个ingressgateway来处理请求
创建上面这样的资源在K8S里的时候,就等于在istio的ingress网关上加了一条规则,这条规则就是允许tomcat.istio-demo.com的http流量进入到网格内部,通过带有istio=ingressgateway的网关来去处理,也就是tomcat.istio-demo.com的流量转到下面的pod是可以被接收的,也就是按照istio的规则去处理
**
**
**添加一个Gateway(kind),允许hosts的http流量,从网格外部流入
**
**
**
**
**
**
**
**
**
**只是允许流量进来后,发送到哪里,需要前面定义的virtualservice,virtualserivice可以和网关一起使用
**
**和前面建立的virtualservice唯一的区别就是,指定好了网关,先创建了一个允许tomcat.istio-demo.com流量进来的网关,下面创建的virtualservice绑定了这个网关,进来的流量就按照路由去匹配,90%匹配到front-tomcat,10%front-tomcat,和之前的virtualservice唯一的区别就是加了gateway绑定,也就是只有gateway来的流量才适用于这个规则,之前没有绑定gateway,意思就是在整个网格内部都会受影响,按照这个规则去走
**
**
**
**gateway没有就是一个通用的规则,也就是在istio网格内部去访问【front-tomcat】,就会按照这个virtualservice去走
**
**
**
**
**
**现在让外部流量进来,就做了gateway的规则
**
**tomcat.istio-demo.com的http流量可以进入ingress gateway来处理
**
**下面的virtualservice绑定gateway
**
**
**
**只有从这个我网关过来的流量才能进入这个规则,其他外部请求会被拒绝
**
**现在网关已经创建出来了
**
**创建规则
**
**
**
**
**
**这个virtualservice只给front-tomcat-gateway用
**
**只有gateway过来的流量才会应用这条规则
**
**如果是从其他pod发出的请求不从front-tomcat-gateway网关过来,就不会受上面规则的影响
**
**
**
**只要这个域名的流量转到ingressgateway上去了
**
**转到这个pod上去了
**
现在请求这个域名要想让ingressgateway来处理
loadbalancer创建了很多port。,3079指向了80
-oyaml
这里有一个http的port
获取端口用这个命令
现在是9比1的关系
-H 域名 地址+端口
ingress gateway服务就是这个地址
加上解析
加上端口就可以访问,90%的流量在v1,10%的流量在v2
但是访问80端口。还是1比1
现在访问30779其实就是访问istio内部的提供的ingressgateway处理请求
但是这个端口就不好看,可以找个nginx代理,或者找个云服务的lb,clb,elb都行
创建一个镜像
换个地址解析
gateway只选择这个域名
这样访问就进不去
通过域名就可以
监听域名,代理1.1版本
现在外部可以访问,但是nginx容器里访问不通
改成69,也就是本机宿主机
现在就可以了,9比1
前面加上nginx,发生问题也可以方便追踪,但是现实也是最起码买个云的LB去代理
流量路由
外部流量进来,简单来说,其实在istio网格内部,不用ingress了改成了ingressgateway,原来给ingress-controller流量都传给了ingressgateway
先转到nginx来进行反代,因为之前加的ingressgateway允许这个域名的http服务,来使用这个ingress
服务到这个ingress之后
创建了virtualservice,绑定到了gateway上去,进一步去匹配virtualservice规则
现在看一个新的实例,这是一个书店
创建一个名称空间
productpage相当于前端一个应用,这个应用会访问后面的reviews服务(v1版本不会去调用rating服务,v2,v3会调用ratings服务)和details服务
给product page创建一个ingress
都是9080端口
现在可以现在外部直接用K8S原来的ingress访问
访问product page页面的时候,detail和review是的服务
review本身还会去调用rating服务
连续访问productpage,review会在三个版本之间随机的
想要实现流量管控就需要放到istio里去,需要注入sidecar
先用istioctl kube-inject 注入指定的yaml,然后kubectl再去apply。这种方式是在名称空间里,给指定的pod去注入。(也就是可以有已经在istio的服务,也可以有不在istio的服务)
还有一种方式是这样的,给命名空间打label。比如在default名称空间打了一个istio-injection=enabled,那以后只要在default里部署服务,都会帮你注入
现在还是按pod注入
现在变成1/2就代表注入了,原来是1/1
这个就代表envoy,每个pod都注入一个envoy
**
**
**外部用ingressenvoy去访问
**
**建立一个gateway,这个gateway还是用指定的ingressgateway
**
**
**
**
**