博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Istio 网关中的 Gateway 和 VirtualService 配置深度解析
阅读量:6860 次
发布时间:2019-06-26

本文共 10419 字,大约阅读时间需要 34 分钟。

原文链接:

通过前几篇文章的学习与实践,我们对 Gateway、VirtualService 和 Destinationrule 的概念和原理有了初步的认知,本篇将对这几个对象资源的配置文件进行深度地解析,具体细节将会深入到每一个配置项与 Envoy 配置项的映射关系。

在开始之前,需要先搞清楚我们创建的这些对象资源最后都交给谁来处理了,负责处理这些资源的就是 pilot。

1. pilot总体架构

首先我们回顾一下 pilot 总体架构,上面是,因为是 old_pilot_repo 目录下,可能与最新架构有出入,仅供参考。所谓的 pilot 包含两个组件:pilot-agentpilot-discovery。图里的 agent 对应 pilot-agent 二进制,proxy 对应 Envoy 二进制,它们两个在同一个容器中,discovery service 对应 pilot-discovery 二进制,在另外一个跟应用分开部署的单独的 Deployment 中。

  • discovery service : 从 Kubernetes apiserver list/watch serviceendpointpodnode 等资源信息,监听 istio 控制平面配置信息(如VirtualService、DestinationRule等), 翻译为 Envoy 可以直接理解的配置格式。
  • proxy : 也就是 Envoy,直接连接 discovery service,间接地从 Kubernetes 等服务注册中心获取集群中微服务的注册情况。
  • agent : 生成 Envoy 配置文件,管理 Envoy 生命周期。
  • service A/B : 使用了 Istio 的应用,如 Service A/B,的进出网络流量会被 proxy 接管。

简单来说 Istio 做为管理面,集合了配置中心和服务中心两个功能,并把配置发现和服务发现以一组统一的 xDS 接口提供出来,数据面的 Envoy 通过 xDS 获取需要的信息来做服务间通信和服务治理。

2. pilot-discovery 为 Envoy 提供的 xds 服务

所谓 xds

pilot-discovery 为数据面(运行在 sidecar 中的 Envoy 等 proxy 组件)提供控制信息服务,也就是所谓的 discovery service 或者 xds 服务。这里的 x 是一个代词,类似云计算里的 XaaS 可以指代 IaaS、PaaS、SaaS 等。在 Istio 中,xds 包括 cds(cluster discovery service)、lds(listener discovery service)、rds(route discovery service)、eds(endpoint discovery service),而 ads(aggregated discovery service) 是对这些服务的一个统一封装。

以上 cluster、endpoint、route 等概念的详细介绍和实现细节可以参考 Envoy 在社区推广的 data plane api(),这里只做简单介绍:

  • endpoint : 一个具体的“应用实例”,对应 ip 和端口号,类似 Kubernetes 中的一个 Pod。
  • cluster : 一个 cluster 是一个“应用集群”,它对应提供相同服务的一个或多个 endpoint。cluster 类似 Kubernetes 中 Service 的概念,即一个 Kubernetes Service 对应一个或多个用同一镜像启动,提供相同服务的 Pod。
  • route : 当我们做灰度发布、金丝雀发布时,同一个服务会同时运行多个版本,每个版本对应一个 cluster。这时需要通过 route 规则规定请求如何路由到其中的某个版本的 cluster 上。

以上这些内容实际上都是对 Envoy 等 proxy 的配置信息,而所谓的 cluster discovery service、route discovery service 等 xxx discovery service 就是 Envoy 等从 pilot-discovery 动态获取 endpoint、cluster 等配置信息的协议和实现。为什么要做动态配置加载,自然是为了使用 istioctl 等工具统一、灵活地配置 service mesh。至于如何通过 istioctl 来查看 xds 信息,下文将会详细介绍。

而为什么要用 ads 来“聚合”一系列 xds,并非仅为了在同一个 gRPC 连接上实现多种 xds 来省下几个网络连接,ads 还有一个非常重要的作用是解决 cdsrds 信息更新顺序依赖的问题,从而保证以一定的顺序同步各类配置信息,这方面的讨论可以详见 。

如何查看 xds

pilot-discovery 在初始化阶段依次 init 了各种模块,其中 discovery service 就是 xDS 相关实现。 可以查到 v1 和 v2 两个版本的 API 文档。 给了 v2 grpc 接口相关的数据结构和接口。

那么如何查看 xds 的信息呢?虽然 v2 是 grpc 的接口,但是 pilot 提供了 InitDebug,可以通过 debug 接口查询服务和 routes 等服务和配置信息。

查看 eds

首先找到 Service istio-pilot 的 Cluster IP

$ export PILOT_SVC_IP=$(kubectl -n istio-system get svc istio-pilot -o go-template='{
{.spec.clusterIP}}')复制代码

然后查看 eds:

$ curl http://$PILOT_SVC_IP:8080/debug/edsz复制代码
[{    "clusterName": "outbound|9080||reviews.nino.svc.cluster.local",    "endpoints": [{        "lbEndpoints": [{            "endpoint": {                "address": {                    "socketAddress": {                        "address": "10.244.0.56",                        "portValue": 9080                    }                }            }        }, {            "endpoint": {                "address": {                    "socketAddress": {                        "address": "10.244.0.58",                        "portValue": 9080                    }                }            }        }, {            "endpoint": {                "address": {                    "socketAddress": {                        "address": "10.244.2.25",                        "portValue": 9080                    }                }            }        }]    }]}, {    "clusterName": "outbound|9080|v3|reviews.nino.svc.cluster.local",    "endpoints": [{        "lbEndpoints": [{            "endpoint": {                "address": {                    "socketAddress": {                        "address": "10.244.0.58",                        "portValue": 9080                    }                }            }        }]    }]}]复制代码

查看 cds

$ curl http://$PILOT_SVC_IP:8080/debug/cdsz复制代码
[{
"node": "sidecar~172.30.104.45~fortio-deploy-56dcc85457-b2pkc.default~default.svc.cluster.local-10", "addr": "172.30.104.45:43876", "connect": "2018-08-07 06:31:08.161483005 +0000 UTC m=+54.337448884","Clusters":[{ "name": "outbound|9080||details.default.svc.cluster.local", "type": "EDS", "edsClusterConfig": { "edsConfig": { "ads": { } }, "serviceName": "outbound|9080||details.default.svc.cluster.local" }, "connectTimeout": "1.000s", "circuitBreakers": { "thresholds": [ { } ] }},...{ "name": "outbound|9090||prometheus-k8s.monitoring.svc.cluster.local", "type": "EDS", "edsClusterConfig": { "edsConfig": { "ads": { } }, "serviceName": "outbound|9090||prometheus-k8s.monitoring.svc.cluster.local" }, "connectTimeout": "1.000s", "circuitBreakers": { "thresholds": [ { } ] }},{ "name": "BlackHoleCluster", "connectTimeout": "5.000s"}]}]复制代码

查看 ads

$ curl http://$PILOT_SVC_IP:8080/debug/adsz复制代码

3. Envoy 基本术语回顾

为了让大家更容易理解后面所讲的内容,先来回顾一下 Envoy 的基本术语。

  • Listener : 监听器(listener)是服务(程序)监听者,就是真正干活的。 它是可以由下游客户端连接的命名网络位置(例如,端口、unix域套接字等)。Envoy 公开一个或多个下游主机连接的侦听器。一般是每台主机运行一个 Envoy,使用单进程运行,但是每个进程中可以启动任意数量的 Listener(监听器),目前只监听 TCP,每个监听器都独立配置一定数量的(L3/L4)网络过滤器。Listenter 也可以通过 Listener Discovery Service(LDS)动态获取。
  • Listener filter : Listener 使用 listener filter(监听器过滤器)来操作链接的元数据。它的作用是在不更改 Envoy 的核心功能的情况下添加更多的集成功能。Listener filter 的 API 相对简单,因为这些过滤器最终是在新接受的套接字上运行。在链中可以互相衔接以支持更复杂的场景,例如调用速率限制。Envoy 已经包含了多个监听器过滤器。
  • Http Route Table : HTTP 的路由规则,例如请求的域名,Path 符合什么规则,转发给哪个 Cluster。
  • Cluster : 集群(cluster)是 Envoy 连接到的一组逻辑上相似的上游主机。Envoy 通过服务发现发现集群中的成员。Envoy 可以通过主动运行状况检查来确定集群成员的健康状况。Envoy 如何将请求路由到集群成员由负载均衡策略确定。

更多详细信息可以参考 ,本文重点突出 ListenerRouteCluster 这三个基本术语,同时需要注意流量经过这些术语的先后顺序,请求首先到达 Listener,然后通过 Http Route Table 转到具体的 Cluster,最后由具体的 Cluster 对请求做出响应。

4. Gateway 和 VirtualService 配置解析

还是拿之前 这篇文章中的例子来解析吧,首先创建了一个 Gateway,配置文件如下:

apiVersion: networking.istio.io/v1alpha3kind: Gatewaymetadata:  name: bookinfo-gatewayspec:  selector:    istio: ingressgateway # use istio default controller  servers:  - port:      number: 80      name: http      protocol: HTTP    hosts:    - "*"复制代码

然后又创建了一个 VirtualService

apiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata:  name: bookinfospec:  hosts:  - "*"  gateways:  - bookinfo-gateway  http:  - match:    - uri:        exact: /productpage    - uri:        exact: /login    - uri:        exact: /logout    - uri:        prefix: /api/v1/products    route:    - destination:        host: productpage        port:          number: 9080复制代码

VirtualService 映射的就是 Envoy 中的 Http Route Table,大家可以注意到上面的 VirtualService 配置文件中有一个 gateways 字段,如果有这个字段,就表示这个 Http Route Table 是绑在 ingressgatewayListener 中的;如果没有这个字段,就表示这个 Http Route Table 是绑在 Istio 所管理的所有微服务应用的 Pod 上的。

为了分清主次,我决定将本文拆分成两篇文章来讲解,本篇主要围绕 ingressgateway 来解析 Gateway 和 VirtualService,而微服务应用本身的 VirtualService 和 DestinationRule 解析放到下一篇文章再说。

显而易见,上面这个 VirtualService 映射的 Http Route Table 是被绑在 ingressgateway 中的,可以通过 istioctl 来查看,istioctl 的具体用法请参考:。

首先查看 Listener 的配置项:

$ istioctl -n istio-system pc listeners istio-ingressgateway-b6db8c46f-qcfks --port 80 -o json复制代码
[    {        "name": "0.0.0.0_80",        "address": {            "socketAddress": {                "address": "0.0.0.0",                "portValue": 80            }        },        "filterChains": [            {                "filters": [                    {                        "name": "envoy.http_connection_manager",                        "config": {                            ...                            "rds": {                                "config_source": {                                    "ads": {}                                },                                "route_config_name": "http.80"                            },                            ...                        }                    }                ]            }        ]    }]复制代码

通过 rds 配置项的 route_config_name 字段可以知道该 Listener 使用的 Http Route Table 的名字是 http.80

查看 Http Route Table 配置项:

$ istioctl -n istio-system pc routes istio-ingressgateway-b6db8c46f-qcfks --name http.80 -o json复制代码
[    {        "name": "http.80",        "virtualHosts": [            {                "name": "bookinfo:80",                "domains": [                    "*"                ],                "routes": [                    {                        "match": {                            "path": "/productpage"                        },                        "route": {                            "cluster": "outbound|9080||productpage.default.svc.cluster.local",                            "timeout": "0.000s",                            "maxGrpcTimeout": "0.000s"                        },                        ...                    },                    ...                    {                        "match": {                            "prefix": "/api/v1/products"                        },                        "route": {                            "cluster": "outbound|9080||productpage.default.svc.cluster.local",                            "timeout": "0.000s",                            "maxGrpcTimeout": "0.000s"                        },                        ...                    },                    ...                ]            }        ],        "validateClusters": false    }]复制代码
  • VirtualService 中的 hosts 字段对应 Http Route Table 中 virtualHosts 配置项的 domains 字段。这里表示可以使用任何域名来通过 ingressgateway 访问服务(也可以直接通过 IP 来访问)。
  • VirtualService 中的 exact 字段对应 Http Route Table 中 routes.match 配置项的 path 字段。
  • VirtualService 中的 prefix 字段对应 Http Route Table 中 routes.match 配置项的 prefix 字段。
  • VirtualService 中的 route.destination 配置项对应 Http Route Table 中 routes.route 配置项的 cluster 字段。

关于 Envoy 中的 HTTP 路由解析可以参考我之前的文章:。

查看 Cluster 配置项:

$ istioctl -n istio-system pc clusters istio-ingressgateway-b6db8c46f-qcfks --fqdn productpage.default.svc.cluster.local --port 9080 -o json复制代码
[    {        "name": "outbound|9080||productpage.default.svc.cluster.local",        "type": "EDS",        "edsClusterConfig": {            "edsConfig": {                "ads": {}            },            "serviceName": "outbound|9080||productpage.default.svc.cluster.local"        },        "connectTimeout": "1.000s",        "circuitBreakers": {            "thresholds": [                {}            ]        }    }]复制代码

可以看到,Cluster 最终将集群外通过 ingressgateway 发起的请求转发给实际的 endpoint,也就是 Kubernetes 集群中的 Service productpage 下面的 Pod(由 serviceName 字段指定)。

实际上 istioctl 正是通过 pilot 的 xds 接口来查看 Listener 、Route 和 Cluster 等信息的。

好了,现在请求已经转交给 productpage 了,那么接下来这个请求将会如何走完整个旅程呢?请听下回分解!

5. 参考

转载于:https://juejin.im/post/5ca09524f265da30d561e8a4

你可能感兴趣的文章
Navicat Premium 12.0.18安装与激活(转)
查看>>
LLVM与Clang的一些事儿
查看>>
问题总结
查看>>
深度解析利用ES6进行Promise封装总结
查看>>
零基础的你还在纠结怎么学习Python编程吗?
查看>>
Flask在Windows环境下的部署
查看>>
力扣(LeetCode)56
查看>>
图片懒加载通俗易懂
查看>>
浅析vue2.0的diff算法
查看>>
协方差深入解读
查看>>
使用Node.js和WebHDFS REST API访问Hadoop HDFS数据
查看>>
聊聊flink Table的Over Windows
查看>>
基本排序算法
查看>>
分布式系统关注点——想通关「限流」?只要这一篇
查看>>
Java™ 教程(接口)
查看>>
一些简单的数组排序算法
查看>>
使用Spring AOP和自定义注解进行参数检查
查看>>
WMS项目中使用到的注解
查看>>
聊聊Java对象在内存中的大小
查看>>
Spring Boot集成JasperReports生成PDF文档
查看>>