一、背景
xDS(Extension and Discovery Service)是一个用于配置和动态发现服务的协议,用于管理和控制复杂的分布式系统。它是Kubernetes中Envoy代理的核心组件,用于实现服务的负载均衡、流量路由和故障恢复等功能。
- 动态服务发现:在微服务架构中,服务的数量和实例经常发生变化。xDS协议提供了一种机制,可以动态地发现和注册服务实例,而无需手动配置或静态的硬编码地址。它使得服务发现能够适应服务拓扑的变化,从而实现弹性和可伸缩性。
- 负载均衡和流量管理:xDS协议支持负载均衡和流量管理策略的动态配置。它允许服务网格控制平面根据实时的负载情况、服务间的依赖关系和其他策略来分配和管理流量。这使得在服务之间实现流量控制、故障转移、AB测试等变得更加灵活和可配置。
- 配置管理和路由规则:xDS协议提供了一种机制,可以动态地配置和更新服务网格中的路由规则、策略和其他相关配置。通过使用xDS协议,服务网格中的路由规则可以根据需要进行更改,而无需重新部署或重启服务。这使得实施灰度发布、金丝雀发布和其他高级部署策略变得更加容易。
- 多语言和多平台支持:xDS协议是一种通用的协议,可以在多种编程语言和平台上实现。这意味着您可以在不同的微服务框架和环境中使用xDS协议,实现统一的服务发现和配置管理体验。它提供了一种标准化的接口,使得不同的服务网格组件可以进行交互和协作。
- 可扩展性:xDS协议设计为可扩展的,可以支持大规模的服务和高并发的流量。它使用了增量更新和缓存等技术,以减少配置传输和处理的开销,并提供了分布式的配置管理和服务发现能力。
xDS协议提供了动态的、灵活的服务发现和配置管理机制,适用于复杂的微服务环境。它能够提高服务网格的可伸缩性、可靠性和可配置性,使得在大规模微服务架构中管理和控制流量变得更加容易和高效。它在Kubernetes和Envoy等现代微服务架构中被广泛使用,用于实现服务网格、API网关和边缘路由等关键功能。
二、XDS结构
2.1 LDS
2.2 RDS
2.3 CDS
2.4 EDS
三、运行原理
3.1 框架
3.2 流程
我们以请求从 productpage
Pod 发送到 reviews
Pod 9080 端口为例,来研究Envoy代理是怎么处理流量的,会借助istioctl proxy-config的命令来具体分析。
3.2.1 Listerner处理
如果在一个 Pod 上查询监听器概要信息,将注意到 Istio 生成了下面的监听器:
-
0.0.0.0:15001
监听器接收所有进出 Pod 的流量,然后转发请求给一个虚拟监听器。- 每个服务 IP 一个虚拟监听器,针对每一个非 HTTP 的外部 TCP/HTTPS 流量。
- Pod IP 上的虚拟监听器,针对内部流量暴露的端口。
0.0.0.0
监听器,针对外部 HTTP 流量的每个 HTTP 端口。
istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs
ADDRESS PORT MATCH DESTINATION
10.96.0.10 53 ALL Cluster: outbound|53||kube-dns.kube-system.svc.cluster.local
0.0.0.0 80 App: HTTP Route: 80
0.0.0.0 80 ALL PassthroughCluster
10.100.93.102 443 ALL Cluster: outbound|443||istiod.istio-system.svc.cluster.local
10.111.121.13 443 ALL Cluster: outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.96.0.1 443 ALL Cluster: outbound|443||kubernetes.default.svc.cluster.local
10.100.93.102 853 App: HTTP Route: istiod.istio-system.svc.cluster.local:853
10.100.93.102 853 ALL Cluster: outbound|853||istiod.istio-system.svc.cluster.local
0.0.0.0 9080 App: HTTP Route: 9080
0.0.0.0 9080 ALL PassthroughCluster
0.0.0.0 9090 App: HTTP Route: 9090
0.0.0.0 9090 ALL PassthroughCluster
10.96.0.10 9153 App: HTTP Route: kube-dns.kube-system.svc.cluster.local:9153
10.96.0.10 9153 ALL Cluster: outbound|9153||kube-dns.kube-system.svc.cluster.local
0.0.0.0 15001 ALL PassthroughCluster
0.0.0.0 15006 Addr: 10.244.0.22/32:15021 inbound|15021|mgmt-15021|mgmtCluster
0.0.0.0 15006 Addr: 10.244.0.22/32:9080 Inline Route: /*
0.0.0.0 15006 Trans: tls; App: HTTP TLS; Addr: 0.0.0.0/0 Inline Route: /*
0.0.0.0 15006 App: HTTP; Addr: 0.0.0.0/0 Inline Route: /*
0.0.0.0 15006 App: Istio HTTP Plain; Addr: 10.244.0.22/32:9080 Inline Route: /*
0.0.0.0 15006 Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15010 App: HTTP Route: 15010
0.0.0.0 15010 ALL PassthroughCluster
10.100.93.102 15012 ALL Cluster: outbound|15012||istiod.istio-system.svc.cluster.local
0.0.0.0 15014 App: HTTP Route: 15014
0.0.0.0 15014 ALL PassthroughCluster
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
10.111.121.13 15021 App: HTTP Route: istio-ingressgateway.istio-system.svc.cluster.local:15021
10.111.121.13 15021 ALL Cluster: outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
10.111.121.13 15443 ALL Cluster: outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
从上面的信息可以看到,每一个 Sidecar 有一个绑定到 0.0.0.0:15001
的监听器,来确定 IP 表将所有进出 Pod 的流量路由到哪里。监听器设置 useOriginalDst
为 true 意味着它将请求传递给最适合原始请求目的地的监听器。 如果找不到匹配的虚拟监听器,它会将请求发送到直接连接到目的地的 PassthroughCluster
。
istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs --port 15001 -o json
[
{
"name": "virtualOutbound",
"address": {
"socketAddress": {
"address": "0.0.0.0",
"portValue": 15001
}
},
"filterChains": [
{
"filters": [
{
"name": "istio.stats",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.extensions.filters.network.wasm.v3.Wasm",
"value": {
"config": {
"configuration": "{\n \"debug\": \"false\",\n \"stat_prefix\": \"istio\"\n}\n",
"root_id": "stats_outbound",
"vm_config": {
"code": {
"local": {
"inline_string": "envoy.wasm.stats"
}
},
"runtime": "envoy.wasm.runtime.null",
"vm_id": "tcp_stats_outbound"
}
}
}
}
},
{
"name": "envoy.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy",
"statPrefix": "PassthroughCluster",
"cluster": "PassthroughCluster"
}
}
],
"name": "virtualOutbound-catchall-tcp"
}
],
"trafficDirection": "OUTBOUND",
"hiddenEnvoyDeprecatedUseOriginalDst": true
}
]
我们的请求是到端口 9080
的出站 HTTP 请求,它将被传递给 0.0.0.0:9080
的虚拟监听器。这一监听器将检索在它配置的 RDS 里的路由配置。 在这个例子中它将寻找 Istiod(通过 ADS)配置在 RDS 中的路由 9080
。
istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs -o json --address 0.0.0.0 --port 9080
...
"rds": {
"config_source": {
"ads": {}
},
"route_config_name": "9080"
}
...
3.2.3 Routes 处理
对每个服务,9080
路由配置只有一个虚拟主机。我们的请求会走到 reviews 服务,因此 Envoy 将选择一个虚拟主机把请求匹配到一个域。一旦匹配到, Envoy 会寻找请求匹配到的第一个路由。本例中我们没有设置任何高级路由规则, 因此路由会匹配任何请求。这一路由告诉 Envoy 发送请求到 outbound|9080||reviews.default.svc.cluster.local
集群。
istioctl proxy-config routes productpage-v1-6c886ff494-7vxhs --name 9080 -o json
[
{
"name": "9080",
"virtualHosts": [
{
"name": "reviews.default.svc.cluster.local:9080",
"domains": [
"reviews.default.svc.cluster.local",
"reviews.default.svc.cluster.local:9080",
"reviews",
"reviews:9080",
"reviews.default.svc.cluster",
"reviews.default.svc.cluster:9080",
"reviews.default.svc",
"reviews.default.svc:9080",
"reviews.default",
"reviews.default:9080",
"10.98.88.0",
"10.98.88.0:9080"
],
"routes": [
{
"name": "default",
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|9080||reviews.default.svc.cluster.local",
"timeout": "0s",
}
}
]
...
3.2.4 Cluster处理
此集群配置为从 Istiod(通过 ADS)检索关联的 endpoints。 所以 Envoy 会使用 serviceName
字段作为主键,来检查 endpoint 列表并把请求代理到其中之一。
istioctl proxy-config cluster productpage-v1-6c886ff494-7vxhs --fqdn reviews.default.svc.cluster.local -o json
[
{
"name": "outbound|9080||reviews.default.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {},
"resourceApiVersion": "V3"
},
"serviceName": "outbound|9080||reviews.default.svc.cluster.local"
},
"connectTimeout": "10s",
"circuitBreakers": {
"thresholds": [
{
"maxConnections": 4294967295,
"maxPendingRequests": 4294967295,
"maxRequests": 4294967295,
"maxRetries": 4294967295
}
]
},
}
]
3.2.5 Endpoints处理
要查看此集群当前可用的 endpoint,请使用 proxy-config
endpoints 命令。
istioctl proxy-config endpoints productpage-v1-6c886ff494-7vxhs --cluster "outbound|9080||reviews.default.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
172.17.0.7:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local
172.17.0.8:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local
172.17.0.9:9080 HEALTHY OK outbound|9080||reviews.default.svc.cluster.local