在服务治理中,流量管理是一个广泛的话题,一般情况下,常用的包括:

  • 动态修改服务访问的负载均衡策略,比如根据某个请求特征做会话保持;
  • 同一个服务有多版本管理,将一部分流量切到某个版本上;
  • 对服务进行保护,例如限制并发连接数、限制请求数、隔离故障服务实例等;
  • 动态修改服务中的内容,或者模拟一个服务运行故障等。

  在Istio中实现这些服务治理功能时无须修改任何应用的代码。较之微服务的SDK方式,Istio以一种更轻便、透明的方式向用户提供了这些功能。用户可以用自己喜欢的任意语言和框架进行开发,专注于自己的业务,完全不用嵌入任何治理逻辑。只要应用运行在Istio的基础设施上,就可以使用这些治理能力。

  总结Istio流量治理的目标:以基础设施的方式提供给用户非侵入的流量治理能力,用户只需关注自己的业务逻辑开发,无须关注服务访问管理。

istio流量治理的核心组件Pilot

  在istio1.8中,istio的分为 envoy (数据平面) 、istiod (控制平面) 、addons(管理插件) 及 istioctl (命令行工具,用于安装、配置、诊断分析等操作)组成。

  Pilot是Istio控制平面流量管理的核心组件,管理和配置部署在Istio服务网格中的所有Envoy代理实例。

  pilot-discovery为envoy sidecar提供服务发现,用于路由及流量的管理。通过kubernetes CRD资源获取网格的配置信息将其转换为xDS接口的标准数据格式后,通过gRPC分发至相关的envoy sidecar

  Pilot组件包含工作在控制平面中的 pilot-discovery 和工作与数据平面的pilot-agent 与Envoy(istio-proxy)

  pilot-discovery主要完成如下功能:

  • 从service registry中获取服务信息
  • 从apiserver中获取配置信息。
  • 将服务信息与配置信息适配为xDS接口的标准数据格式,通过xDS api完成配置分发。

  pilot-agent 主要完成如下功能

  • 基于kubernetes apiserver为envoy初始化可用的boostrap配置文件并启动envoy。

  • 管理监控envoy的云兄状态及配置重载。

envoy

  • 每个sidecar中的envoy是由pilot-agent基于生产的bootstrap配置进行启动,并根据指定的pilot地址,通过xDS api动态获取配置。
  • sidecar形式的envoy通过流量拦截机制为应用程序实现入站和出站的代理功能。

Pilot的实现

  在istio中的管理策略都是基于Kubernetes CRD的实现,其中有关于流量管理的CRD资源包括 VirtualService EnvoyFilter Gateway ServiceEntry Sidecar DestinationRule WorkloadEntry WorkloadGroupreference istio-networking-crd-resouces

  • VirtualServices:用于定义路由,可以理解为envoy的 listener => filter => route_config

  • DestinationRule:用于定义集群,可以理解为envoy 的 cluster

  • Gateway:用于定义作用于istio-ingress-gateway

  • ServiceEntry:用于定义出站的路由,作用于istio-egress-gateway

  • EnvoyFilter:为envoy添加过滤器或过滤器链。

  • Sidecar:用于定义运行在sidecar之上的envoy配置。

Virtual Services和 Destination Rules是Istio流量路由功能的核心组件

istio流量流程概要

  在控制面会经过如下流程:

  • (1)管理员通过命令行或者API创建流量规则;
  • (2)Pilot将流量规则转换为Envoy的标准格式;
  • (3)Pilot将规则下发给Envoy。

  在数据面会经过如下流程:

  • (1)Envoy拦截Pod上本地容器的Inbound流量和Outbound流量;
  • (2)在流量经过Envoy时执行对应的流量规则,对流量进行治理。

路由规则 :Virtual Services

VirtualServices是istio用于在其运行平台Kubernetes定义的配置,用来影响流量的路由规则;其本质就是为集群中envoy提供路由配置的。

VirtualServices名词解释

VirtualServices中一些流量路由定义的关键术语。

  • Services:服务的唯一应用名称的单位,在Kubernetes之上 Services通常为Kubernetes Services资源。

  • Source:在上文中,下游发起请求的客户端服务。

  • Host:客户端请求服务时使用的地址

  • Service versions:service允许的不同版本的子集(通常为流量管理中的概念,如AB等)每个Service都有一个包含所有实例的默认版本。

VirtualServices资源说明

VirtualServices中主要有这些配置用于配置流量的路由定义。 reference virtual services

  • hosts:string[] 目标主机,可以是带有统配符的DNS Name或IP

  • gateways:string[],这些资源生效的网关和sidecar的名称。默认为名称空间级别,跨名称空间使用 <gateway namespace>/<gateway name>

    • mesh 默认值,表示生效与网格内所有sidecar

    • 仅应用于Gateway,该字段设置为Gateway的名称。

    • 忽略此字段:将应用于网格内部所有的sidecar

  • http: HTTP协议流量的路由规则表。

    • match:[] 匹配的条件。一个列表内单项内容的条件具有AND,整个列表的条件为OR。
      • name:
      • uri:匹配值区分大小写
        • exact: 精确匹配。
        • prefix:用于前缀匹配。
        • regex:基于正则表达式匹配。
      • method:HTTP方法,参数与uri相同。
    • route:[] 设置的http流量的转发规则
      • destination:请求转发到的唯一标识符。
        • host:允许平台及ServiceEntry的服务名称,Kubernetes中为短名称reviews.default.svc.cluster.local
        • subset,在DestinationRule中定义的子集
        • port:可选,公开服务的端口
      • weight:转发流量的比例0-100 ,各目标的和应为100。
      • headers:操作头规则。
    • redirect:重定向规则
    • delegate:只能在RouteRedirect为空时设置,委托的VirtualServices 名称
    • rewrite:重写HTTP URI。
    • timeout:HTTP请求超时,默认禁用。
    • retries:HTTP请求重试策略。
    • fault:故障注入
    • mirror:流量镜像
    • mirrorPercentage:对应mirror的比例
    • headers:操作http头的规则
  • tcp:TCP流量的路由规则的有序列表

  • exportTo:允许 VirtualServices 其他名称空间的sidecar与gateway使用。

VirtualServices配置实例

  基于HTTP header的请求,将请求为/ratings/v2/ 路径,并且请求头包含 end-user 值为jason

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings-route
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - match:
    - headers:
        end-user:
          exact: jason
      uri:
        prefix: "/ratings/v2/"
      ignoreUriCase: true # 是否区分大小写,仅exact和prefix生效。
    route:
    - destination:
        host: ratings.prod.svc.cluster.local

委托其他virtualServices处理

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "bookinfo.com"
  gateways:
  - mygateway
  http:
  - match:
    - uri:
        prefix: "/productpage"
    delegate:
       name: productpage
       namespace: nsA
  - match:
    - uri:
        prefix: "/reviews"
    delegate:
        name: reviews
        namespace: nsB
yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
  namespace: nsA
spec:
  http:
  - match:
     - uri:
        prefix: "/productpage/v1/"
    route:
    - destination:
        host: productpage-v1.nsA.svc.cluster.local
  - route:
    - destination:
        host: productpage.nsA.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
  namespace: nsB
spec:
  http:
  - route:
    - destination:
        host: reviews.nsB.svc.cluster.local

目标规则:DestinationRule

  DestinationRule定义在完成路由配置后应用于服务流量的策略,即如何将流量调度至集群内,可以理解为DestinationRule定义的是envoy中的cluster。应用的内容也是envoy中cluster段的配置,如负载均衡配置,sidecar连接值及离群检测。

DestinationRule字段说明

  • host: 注册表中的服务名称,kubernetes平台中使用短名称
  • trafficPolicy:应用的流量策略。
    • loadBalancer:使用的负载均衡算法,
      • simple
        • ROUND_ROBIN
        • LEAST_CONN
        • RANDOM
        • PASSTHROUGH
    • connectionPool:一致性hash
    • outlierDetection:离群值检测
      • consecutiveGatewayErrors:满足502 503 504 错误数弹出。
      • consecutive5xxErrors: 满足5xx错误数弹出。
      • interval:探测时间间隔
      • baseEjectionTime:最小逐出时间。主机被驱逐的时间等于baseEjectionTime * 退出次数。
      • maxEjectionPercent:最大驱逐比例,默认10%。
      • minHealthPercent:最少健康比例,默认为0%
    • tls
    • portLevelSettings
  • subsets:[] 服务各个版本命名集。
    • name:子集的名称
    • labels:标签过滤器
    • trafficPolicy:子集流量策略,继承DestinationRule级别流量策略。
  • exportTo:跨名称空间使用。

DestinationRule配置实例

基于服务子集的配置

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: bookinfo-ratings
spec:
  host: ratings.prod.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      simple: LEAST_CONN
  subsets:
  - name: testversionv3
    labels:
      version: v3
  - name: testversionv2
    labels:
      version: v2
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN

配置离群值

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews-cb-policy
spec:
  host: reviews.prod.svc.cluster.local
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http2MaxRequests: 1000
        maxRequestsPerConnection: 10
    outlierDetection:
      consecutiveErrors: 7
      interval: 5m
      baseEjectionTime: 15m

集群网关入口:Gateway

  Istio还提供了一种配置模型 Istio GatewayGateway KubernetesIngress 相比,Gateway有高度的定制化与灵活性,并且允许将Istio功能应用于集群流量入口。

Gateway中运行的程序为envoy,它从控制平面接收相应的配置,并完成相关流量的传输;Gateway资源只负责网络入口点的相关功能,具体的路由实现则由VirtualService完成。

Gateway 配置说明

  Gateway定义了一个集群入口的负载均衡器,该负载均衡为运行在网格的边缘代理,负责将外部流量引入集群的内部。

  Gateway资源生效于Ingress | Egress Envoy Pod的标签选择器,使用selector定义:selector: app=istio-ingressgateway

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: study-gateway
  namespace: default
spec:
  selector: # 基于名称空间中匹配pod的标签从而生效的应用
    app: istio-ingressgateway # 标签可以是一个或多个
  servers: # 描述对应的envoy的lintener的配置。
  - port:  # 设置envoy lintener
      number: 90 #  端口号 (Required)
      targetPort: # 可选 (Optional)
      name: envoy_end # 分配给端口的标签。
      protocol: HTTP # 端口服务协议,HTTP|HTTPS|GRPC|HTTP2|MONGO|TCP|TLS
    hosts: [ "*" , "text.studyenvoy.com" ] # 设置dnsName 可选的名称空间,*|. 
    tls: # 与TLS相关的选项集 (Optional)
    name: # 服务器的可选名称,必须唯一 (Optional)

Gateway配置实例

基于istio Bookinfo示例的Gateway资源清单。

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

这里可以看到istio-ingress-gateway的pod的标签 app=istio-ingressgateway

text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ kubectl get pods -n istio-system --show-labels
NAME                                    READY   STATUS    RESTARTS   AGE   LABELS
istio-ingressgateway-78b47bc88b-xqqpn   1/1     Running   0          22d   app=istio-ingressgateway, 
chart=gateways, 
heritage=Tiller, install.operator.istio.io/owning-resource=unknown,
istio.io/rev=default,istio=ingressgateway,
operator.istio.io/component=IngressGateways,
pod-template-hash=78b47bc88b,
release=istio,service.istio.io/canonical-name=istio-ingressgateway,
service.istio.io/canonical-revision=latest

外部服务引入配置:ServiceEntry

  在Istio中提供了ServiceEntry,可将网格外的服务加入网格中,像网格内的服务一样进行管理。

  在实现上就是把外部服务加入 Istio 的服务发现,这些外部服务因为各种原因不能被直接注册到网格中。

ServiceEntry字段说明

  • host:与ServiceEntry关联的主机
  • addresses:与服务关联的虚拟IP地址。
  • ports:
    • number:服务的端口。
    • protocol:服务公开的协议。HTTP|HTTPS|GRPC|HTTP2|MONGO|TCP| TLS之一。
    • targetPort:目标端口号。
  • location:MESH_EXTERNAL | MESH_INTERNAL,决定是网格内部还是外部。
  • resolution:服务发现机制。
    • NONE:
    • STATIC:指定静态IP地址。
    • DNS:通过DNS发现。
  • endpoints:服务关联的端点,workloadSelectorendpoints 二选一。
  • exportTo:共享其他名称空间
  • subjectAltNames:如指定,将验证服务器证书的使用者备用名称是否与指定值之一匹配。

使用istio ingress gateway 配置一个网格外部的应用

部署应用程序

准备一个后端的应用

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpend-deply
  namespace: kube-system
  labels:
    app: httpend-deply
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpend-deply
  template:
    metadata:
      namespace: kube-system
      name: httpend-deply
      labels:
        app: httpend-deply
    spec:
      containers:
        - name: envoy-end
          image: cylonchau/envoy-end
          imagePullPolicy: IfNotPresent
          livenessProbe:
            initialDelaySeconds: 3 # 首次探测延迟时间
            periodSeconds: 2 # 定期重试
            failureThreshold: 1 # 失败重试次数
            httpGet:
              port: 90
              path: ping
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: envoy-end
  labels:
    app: envoy-end
  namespace: kube-system
spec:
  type: NodePort # nodeport是为了验证服务是否正常
  ports:
    - port: 90
      name: envoy-end
      targetPort: 90
      nodePort: 30102
  selector:
    app: httpend-deply

应用Gateway和VirtualServices

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: envoyend-gateway
  namespace: kube-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 1090
        name: http
        protocol: HTTP
      hosts:
        - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: envoy-end
  namespace: kube-system
spec:
  hosts:
    - "*"
  gateways:
    - envoyend-gateway
  http:
    - match:
        - uri:
            prefix: /
      route:
        - destination:
            host: envoy-end
            port:
              number: 1090

应用DestinationRule

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: envoy-end
  namespace: kube-system
spec:
  host: envoy-end
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN

应用ServiceEntry

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: envoy-end
  namespace: kube-system
spec:
  hosts:
  - "envoy-end"
  ports:
  - number: 90
    name: http
    protocol: HTTP
  location: MESH_EXTERNAL
  resolution: DNS