微服务治理 - 初探Istio

服务网格概念源于 Buoyant 公司的CEO Willain Morgan 的文章 “What’s a service mesh ? And do i need one?”

一、微服务治理的挑战

  • Kubernets 提供了一系列强大的服务管理机制,如多种类型的Pod控制器实现应用部署、升级和弹性扩缩容的服务管理机制,并借助Service CRD等实现了服务注册和负载均衡,但是在随着服务体系不断完善和无法忽略的网络不可靠因素显然也带来了新的挑战,如 :
    • 服务注册和服务发现、负载均衡、健康状态检查、限流、熔断、异常点检测、流量镜像、A/B测试、故障注入、日志、分布式跟踪等…

二、服务网格是什么

  • 服务网格(Service Mesh)是一个专门处理服务通讯的基础设施层。它的职责是在由云原生应用组成服务的复杂拓扑结构下进行可靠的请求传送。在实践中,它是一组和应用服务部署在一起的轻量级的网络代理,并且对应用服务透明。
  • 服务网格从总体架构上来讲比较简单,不过是一堆紧挨着各项服务的用户代理,外加一组任务管理组件组成。
  • control plane 控制平面 : 管理组件被称为控制层主要负责与控制平面中的代理通信,下发策略和配置。
  • data plane 数据平面 : 代理在服务网格中被称为数据层主要负责直接处理入站和出站数据包,转发、路由、健康检查、负载均衡、认证、鉴权、产生监控数据等。
  • 一个典型的服务网格部署网络结构图如下:( 其中绿色方块为应用服务,蓝色方块为 Sidecar Proxy ,应用服务之间通过 Sidecar Proxy 进行通信,整个服务通信形成图中的蓝色网络连线,图中所有蓝色部分就形成了 Service Mesh。)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zbYU8Fvh-1655374527066)(https://atlas-rc.pingcode.com/files/public/6294b879cb3c89ff0e8e1c79/origin-url)]

三、服务网格带来的便捷

  • Service Mesh 解决方案极大降低了业务逻辑于网络功能之间的耦合度,能够快捷、方便地集成到现有的业务环境中,并提供了多语言、多协作,运维和管理成本被大大压缩,且开发人员能够精力集中于业务逻辑本身,而无需关注业务代码以外的其他功能;
  • Service Mesh 服务间通信将遵循以下通信逻辑 :
    • 微服务彼此间不会直接进行通信,而是由各服务前端的称为 Service Mesh的代理程序进行 Envoy Sidecar;
    • Service Mesh 内置支持服务发现、熔断、负载均衡等网络相关的用于控制服务间通信的各种高级功能;
    • Service Mesh于编程语言无关,开发人员可以使用任何编程语言编写微服务的业务逻辑,各服务之间也可以使用不同的编程语言开发;
    • 服务间的通信的局部故障可由 Service Mesh自动处理;
    • Service Mesh中的各服务的代理程序由控制平面(Control Plane)集中管理;各代理程序之间的通信网络也称为数据平面(Data Plane);
    • 部署于容器编排平台,各代理程序会以微服务容器的Sidecar模式运行 ( Kubernetes );

四、开源服务网格的实现方案

  • 在实现上,数据平面的主流解决方案由 Linkerd 、Nginx、Envoy、Haproxy和Traefix等,而控制平面的主要实现有 Istio、SmartStack等几种。
    • Linkerd
      • 由Buoyant 公司于2016年率先创建的开源高性能网络代理程序(数据平面),是业界第一款 Service Mesh产品,引领并促进了相关技术的快速发展。
      • Linkerd使用Namerd提供的控制平面,实现中心化管理和存储路由规则、服务发现配置、支持运行时动态的路由等功能。
    • Envoy
      • 核心功能于数据平面,与2016年由Lyft公司创建并开源,目标是成为通用的数据平面。
      • 云原生应用,既可以作为前端代理,也可以实现Service Mesh中的服务间通信。
      • Envoy 常被用于实现 API Gateway 以及Kubernetes的Ingress Controller ,不过基于Envoy实现的 Service Mesh产品 Istio有着更广泛的用户基础。
    • Istio
      • 相比前两者来说,Istio发布事件稍晚,它与2017年5月面世,但却是目前最火热的Service Mesh解决方案,得到了Google 、IBM、Redhat等公司的大力推广及支持。
      • 目前仅支持部署在Kubernetes之上,其数据平面由Envoy实现。
  • 最新服务网格全景图

五、Istio架构解析

5.1、控制平面 - istiod

  • Istio的整体架构,从逻辑上,Istio分为数据平面和控制平面两个部分:
    • 数据平面是以 sidecar 方式部署的智能代理,Istio默认集成的是Envoy。数据平面用来控制微服务之间的网络通讯,以及和Mixer模块通信。
    • 控制平面负责管理和配置数据平面,控制数据平面的行为,如代理路由流量,实施策略,收集遥测数据,加密认证等。控制平面分为Pilot、Mixer、Citadel三个组件;
  • 迄今,Istio架构经历了三次重要变革

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VbKUGEHt-1655374527067)(https://atlas-rc.pingcode.com/files/public/6295a982cb3c89ff0e8e1d2c/origin-url)]

  • 2018.07,Istio v1.0 ,单体
    • 控制平面主要有三个组件Pilot(流量治理核心组件)
      • Pilot - 流量治理核心组件 : 控制平面核心组件
        • 管理和配置部署在Istio服务网格中的所有Envoy代理实例。
        • 为Envoy Sidecar 提供服务发现、智能路由的流量管理功能 (例如,A/B测试、金丝雀等)和弹性(超时、重试、断路器等)。
      • Citadel - 安全相关核心组件 : 身份和凭据管理等安全相关的功能,实现强大的服务到服务和最终用户身份验证,帮助用户基于服务身份(而非网络控制机制)构建零信任的安全网络环境;
      • Mixer - 遥测相关功能组件 : 遥测(指标、日志、分布式链路)和策略(访问控制、配额、限速等),通过内部插件接口扩展支持第三方组件,插件的修改或更新,需要重新部署Mixer。
  • 2019.03, Istio v1.1 ,完全分布式,新增Galley
    • Galley - 验证用户编写的配置校验
      • 是Istio的配置验证、摄取、处理和分发组件;
      • 负责将其余的Istio组件从底层平台(例如Kubernetes) 获取用户配置的细节隔离开来,从而将Pilot与底层平台进行解耦;
  • 2020.03,Istio v1.5 - istiod ,回归单体
    • 抛弃影响性能的Mixer,遥测功能交由 Envoy自行完成;
    • 将 Pilot、Citadel、Galley 整合为一个单体应用 Istiod ;
    • Istiod
      • Istio 充当控制平面,将配置分发到所有的 Sidecar 代理和网关;
      • 它能够为支持网络的应用实现智能化的负载均衡机制,且相关流量绕过了 kube-proxy ;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-etRZkobe-1655374527067)(https://atlas-rc.pingcode.com/files/public/6295a6d2cb3c89ff0e8e1d2a/origin-url)]

5.2、数据平面 - Envoy

  • Istio 的核心控件Envoy
    • Istio 选择 Envoy 作为 Sidecar 代理,Envoy 本质上是一个为面向服务的架构而设计的 7 层代理和通信总线。Envoy 基于 C++ 11 开发而成,性能出色。除了具有强大的网络控制能力外,Envoy 还可以将流量行为和数据提取出来发送给 Mixer 组件,用以进行监控。
    • Envoy 在网络控制方面的主要功能如下。
      • HTTP 7 层路由、支持 gRPC、HTTP/2服务发现和动态配置、健康检查、负载均衡等
  • 我们知道,在Kubernetes环境中,同一个Pod内的不同容器间共享网络栈,这一特性使得Sidecar可以接管进出这些容器的网络流量,这就是Sidecar模式的实现基础。Envoy是目前Istio默认的数据平面,实际上因为Istio灵活的架构,完全可以选择其他兼容的产品作为Sidecar。目前很多服务网格产品都可以作为Istio的数据平面并提供集成。

在这里插入图片描述

  • Listeners : 面向客户端一次,监听套接字,用于接收客户端请求组件;
  • Filter : Listeners内部会包含一到多个Filter,组成过滤器链,支持多条过滤串连(支持多个过滤器),依次仅从匹配后向后端代理,也可称为 filter chains;
  • router :用于将Filter过滤的请求分类以后,过滤到不同的后端组件 Cluster
  • Cluster : Cluster在Envoy中可以定义多个,用于实现归类被代理服务器组的组件,它们后端对应的一到多个 Server 组成;

六、Istio流量治理入门

  • Istio的所有流量规则和控制策略都基于 Kubernetes CRD 实现,这包括网络功能相关的 VirtualServiceDestinationRuleGatewayServiceEntryEnvoyFiler 等;
  • Istio通过 Ingress Gateway 为网格引入外部流量;
    • Gateway 中运行的主程序亦为Envoy,它同样从控制平面接收配置,并负责完成相关的流量传输;
    • 换而言之,Gateway资源对象用于将外部访问映射到内部服务,它自身只负责通信子网的相关功能,例如套接字,而七层路由功能则由 VirtualService 实现;
  • Istio 基于 ServiceEntry 资源对象将外部服务注册到网格内,从而像将外部服务以类同内部服务一样的方式进行治理;
    • 对于外部服务,网格内 Sidecar方式运行的Envoy即能执行治理;
    • 若需要将外出流量约束于特定几个节点时则需要使用专门的 Egress Gateway 完成,并基于此 Egress Gateway执行相应的流量治理;
  • Virtual Services 和 Destination Rules 是Istio流量路由功能的核心组件;
    • Virtual Services 用于将分类流量并将其路由到指定的目的地 (Destination),而 Destination Rules 则用于配置哪个指定 Destination 如何处理流量;
      • Virtual Service
        • 用于在 Istio及其底层平台 (例如 Kubernetes) 的基础上配置如何将请求路由到网格中的各 Service之上;
        • 通常由一组路由规则 (routing rules) 组成,这些路由规则按顺序进行评估,从而使 Istio能够将那些对 Virtual Service 的每个给定请求匹配到网格内特定的目标之上;
        • 事实上,其定义的是分发给网格内各 Envoy 的VirtualHost 和 Route的相关配置;
      • Destination Rules
        • 定义流量在 “目标” 内部的各端点之间的分发机制,例如将各端点进行分组,分组内端点间的流量均衡机制,异常探测等;
        • 事实上,其定义的是分发给网格内各 Envoy和 Cluster的相关配置;
  • 下图为入栈流量请求路线 :Ingress Gateway -> Gateway -> VirtualService -> DestinationRule -> Service -> Pod

在这里插入图片描述

6.1、istio中是如何开放服务给外部访问 ?

如果不考虑网格的话,Kubernetes中是如何让内部应用给外部访问的呢 ?
方式一 :Pod hostNetwork 网络模型,通过Pod所运行的Node 节点访问
方式二 :Service 类型为 NodePort 通过任何 Node节点的地址访问
方式三 :Service 类型为 LoadBalancer 集群外部的负载均衡器访问
方式四 :Ingress (NodePort) -> Service (ClusterIP) -> Pod 通过Ingress Service类型为NodePort 再通过任何 Node节点的地址访问

以 Grafana 为例 :ingress gateway(接入集群外部流量 80) -> virtualservice -> destinationrule

  • 1、 Gateway CRD - ingress gateway 配置grafana 侦听器和路由,将外部grafana.test.om域名的对于80端口和路由的请求引入到内部grafana
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: grafana-gateway
  namespace: istio-system
spec:
  # 匹配 ingress-gaetway 标签Pod
  selector:
    app: istio-ingressgateway
  servers:
  - port:
      # 端口, 通过 istio-ingressgateway 标准80端口接入
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "grafana.test.com"
  • 2、 virtualservice ,使其和Gateway进行联动
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: grafana-virtualservice
  namespace: istio-system
spec:
  hosts:
  - "grafana.test.com"
  gateways:
  - grafana-gateway
  http:
  # 定义路由匹配条件
  - match:
    - uri:
        prefix: /   # 用户请求路由,表示由 grafana.test.com主机由 / 开头, 都路由此目标主机;
    route:
    - destination:
        host: grafana  # 目标
        port:
          number: 3000 # 目标端口

# kubectl get vs -n istio-system
NAME                     GATEWAYS              HOSTS                  AGE
grafana-virtualservice   ["grafana-gateway"]   ["grafana.test.com"]   12s

# 查看 Ingress Gateway 中定义的路由
# istioctl proxy-config routes $InGW -n istio-system
NAME           DOMAINS              MATCH                  VIRTUAL SERVICE
http.8080      grafana.test.com     /*                     grafana-virtualservice.istio-system
               *                    /healthz/ready*
               *                    /stats/prometheus*
               
# 此时cluster其实是没有人为去定义的, 虽然grafana的cluster并没有和destinationrule所关联,但是cluster是存在的(因为Service是事先存在的)
istioctl proxy-config clusters $InGW -n istio-system --port 3000
SERVICE FQDN                               PORT     SUBSET     DIRECTION     TYPE     DESTINATION RULE
grafana.istio-system.svc.cluster.local     3000     -          outbound(出栈概念是站在sidecar proxy角度)      EDS
  • 3、 destinationrule 额外定义路由策略
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: grafana
  namespace: istio-system
spec:
  host: grafana
  trafficPolicy:
    tls:
      mode: DISABLE

在这里插入图片描述

6.2、istio中网格内部服务间如何通讯 ?

frontend访问demoapp -> frontend访问多版本demoapp
6.2.1、frontend访问demoapp
  • 两个应用
    • frontend(proxy) : 前端应用,会请求后端的 demoapp
      • service : proxy
    • demoapp : 后端应用
      • service : demoappv10

在这里插入图片描述

  • 1、 部署demoapp v10 - 标签 demoapp: v1.0
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: demoapp
  name: demoappv10
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demoapp
      version: v1.0
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: demoapp
        version: v1.0
    spec:
      containers:
      - image: ikubernetes/demoapp:v1.0
        name: demoapp
        env:
        - name: PORT
          value: "8080"
  • 2、 为demoapp v.1.0创建service - demoappv10 (istio发现并作为服务作为网格内部使用,需要创建service)
apiVersion: v1
kind: Service
metadata:
  labels:
    app: demoapp
  name: demoappv10
spec:
  ports:
  - name: http-8080
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: demoapp
    version: v1.0
  type: ClusterIP
# kubectl get pods   
NAME                          READY   STATUS    RESTARTS   AGE
demoappv10-65cdf575c8-cqx5b   2/2     Running   0          25s  # demoapp + sidecar
demoappv10-65cdf575c8-fc7cv   2/2     Running   0          25s
demoappv10-65cdf575c8-nwftc   2/2     Running   0          25s

# DEMOAPP=$(kubectl get pods -l app=demoapp -o jsonpath={.items[0].metadata.name})
# istioctl proxy-status
NAME                                                   CDS        LDS        EDS        RDS          ISTIOD                      VERSION
demoappv10-5c497c6f7c-24dk4.default                    SYNCED     SYNCED     SYNCED     SYNCED       istiod-76d66d9876-lqgph     1.12.1
demoappv10-5c497c6f7c-fdwf4.default                    SYNCED     SYNCED     SYNCED     SYNCED       istiod-76d66d9876-lqgph     1.12.1
demoappv10-5c497c6f7c-ks5hk.default                    SYNCED     SYNCED     SYNCED     SYNCED       istiod-76d66d9876-lqgph     1.12.1

# 查看侦听器
# istioctl proxy-config listeners $DEMOAPP --port=8080
ADDRESS PORT MATCH                        DESTINATION
0.0.0.0 8080 Trans: raw_buffer; App: HTTP Route: 8080
0.0.0.0 8080 ALL                          PassthroughCluster

# 查看路由信息
# istioctl proxy-config routes $DEMOAPP | grep "demoappv10"
8080                                                                      demoappv10, demoappv10.default + 1 more...           /*

# 查看集群信息
# istioctl proxy-config clusters $DEMOAPP | grep "demoappv10"
demoappv10.default.svc.cluster.local                                 8080      -          outbound      EDS

# 查看后端端点信息
# istioctl proxy-config endpoints $DEMOAPP | grep "demoappv10"
10.220.104.135:8080              HEALTHY     OK                outbound|8080||demoappv10.default.svc.cluster.local
10.220.104.139:8080              HEALTHY     OK                outbound|8080||demoappv10.default.svc.cluster.local
10.220.104.140:8080              HEALTHY     OK                outbound|8080||demoappv10.default.svc.cluster.local
  • 3、 部署frontend proxy 前端代理应用
apiVersion: apps/v1
kind: Deployment
metadata:
  name: proxy
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: proxy
  template:
    metadata:
      labels:
        app: proxy
    spec:
      containers:
        - env:
          - name: PROXYURL
            value: http://demoappv10:8080   # 请求demoappv10
          image: ikubernetes/proxy:v0.1.1
          imagePullPolicy: IfNotPresent
          name: proxy
          ports:
            - containerPort: 8080
              name: web
              protocol: TCP
          resources:
            limits:
              cpu: 50m
---
apiVersion: v1
kind: Service
metadata:
  name: proxy
spec:
  ports:
    - name: http-80
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app: proxy
  • 4、 client 访问 frontend proxy (补充 :真正发挥网格流量调度的是 egress listener)

流量走向 :client pod -> Sidecar Envoy(Egress Listener proxy:80) -> (Ingress Listener) poroxy pod -> (Egress Listener)demoappv10:8080 -> (Ingress Listener)demoappv10 pod

# kubectl run client --image=ikubernetes/admin-box -it --rm --restart=Never --command -- /bin/sh
If you don t see a command prompt, try pressing enter.
root@client # curl proxy
# 后端demoappv10服务网络的内容
Proxying value: iKubernetes demoapp v1.0 !! ClientIP: 127.0.0.6, ServerName: demoappv10-5c497c6f7c-24dk4, ServerIP: 10.220.104.143!
 - Took 314 milliseconds.
  • 5、流量走向视图

在这里插入图片描述

6.2.2、frontend访问多版本demoapp,并期望流量在两版本中进行按需分配

如proxy访问demoapp 时 http://demoapp/canary 转发至 v11版本,http://demoapp/ 转发至 v10版本,并且要求访问 v11版本权重为 90% ,v10版本为10%;

在这里插入图片描述

  • 6、 部署demoapp v11 - 标签 demoapp: v1.1
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: demoappv11
    version: v1.1
  name: demoappv11
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  selector:
    matchLabels:
      app: demoapp
      version: v1.1
  template:
    metadata:
      labels:
        app: demoapp
        version: v1.1
    spec:
      containers:
      - image: ikubernetes/demoapp:v1.1
        imagePullPolicy: IfNotPresent
        name: demoapp
        env:
        - name: "PORT"
          value: "8080"
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        resources:
          limits:
            cpu: 50m

7、 为demoapp v.11 创建service - demoappv11 (istio发现并作为服务作为网格内部使用,需要创建service)

apiVersion: v1
kind: Service
metadata:
  name: demoappv11
spec:
  ports:
    - name: http-8080
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: demoapp
    version: v1.1
  type: ClusterIP
# kubectl get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
demoappv10   ClusterIP   10.100.67.168   <none>        8080/TCP   18h
demoappv11   ClusterIP   10.100.72.0     <none>        8080/TCP   17s
  • 8、 为demoapp v1.0 & 1.1 创建service - demoapp 将demoappv10和demoappv11两个版本绑定到一组Cluster
apiVersion: v1
kind: Service
metadata:
  name: demoapp
spec:
  ports:
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector: # 选择pod标签为 demoappv10 和 demoappv11 共同存在的标签
    app: demoapp
  type: ClusterIP
  • 9、 定义DestinationRule : DestinationRule 的主要作用就是将定义的demoapp 的service后端适配到的Pod分为两组,v10和v11两个组称为两个子集;
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  # DS名称,标注集群名
  name: demoapp
spec:
  # 主机 :对demoapp service 服务的访问
  host: demoapp
  # 集群子集划分策略, 这里使用标签选择器对后端POD做逻辑组划分
  subsets:
  # 逻辑组名称
  - name: v10
    # 在原本的筛选条件上,额外增加使用以下标签选择器对后端端点归类为 v10 子集
    labels:
      version: v1.0
  - name: v11
    # 在原本的筛选条件上,额外增加使用以下标签选择器对后端端点归类为 v11 子集
    labels:
      version: v1.1
  • 10、 调配 VirtualService :对 frontend proxy 访问的 demoapp的route进行定义
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: demoapp
spec:
  hosts:
  - demoapp
  http:
  - name: canary
    # 匹配条件
    match:
    - uri:
        prefix: /canary
    rewrite:
      uri: /
    # 路由目标
    route:
    - destination:
        # 调度给demoapp的clusters的v11子集
        host: demoapp
        # 子集
        subset: v11
      weight: 90   # 承载权重 90% 流量
  - name: default
    route:
    - destination:
        # 调度给demoapp的clusters的v10子集
        host: demoapp
        # 子集
        subset: v10
	  weight: 10        # 承载权重 10% 流量
  • 11、流量走向视图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JrwP39ix-1655374527069)(https://atlas-rc.pingcode.com/files/public/629642e8cb3c89ff0e8e1dd2/origin-url)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值