Pod注入envoy sidecar之后,会通过pilot-agent grpc协议来访问pilot,pilot通过xds协议向envoy推送配置文件
什么是XDS?
LDS: 监听发现服务
RDS: 路由发现服务
CDS: 集群发现服务
SDS: 密钥发现服务
EDS: 端点发现服务
ADS: 聚合发现服务,pilot与envoy通过grpc连接,pilot检测到配置有更新时,会向enovy同步LDS/CDS/RDS/SDS配置,但是它们的配置同步是有顺序的,ADS对这些配置更新API聚合并排序。仅适用于grpc流,不适合rest。
通过istioctl来查看xds信息
部署bookinfo应用示例后,会有以下Pod
# kubectl get po
NAME READY STATUS RESTARTS AGE
details-v1-7d78fc5688-9k9ch 2/2 Running 0 155m
productpage-v1-844495cb4b-8dkxz 2/2 Running 0 156m
ratings-v1-55ccf46fb4-wg7xb 2/2 Running 0 155m
reviews-v1-68bb7b8c4f-lrjm5 2/2 Running 0 10d
查看proxy status,会显示xds同步信息,如果非SYSCED说明有问题,一般是网络问题导致Pilot不能顺利将配置下发
istioctl ps
NAME CDS LDS EDS RDS PILOT VERSION
details-v1-65d64b5965-zsr2n.ns1 SYNCED SYNCED SYNCED SYNCED istiod-1-6-10-7db56f875b-fdzt8 1.6.10
details-v1-7d78fc5688-9k9ch.test SYNCED SYNCED SYNCED SYNCED istiod-1-6-10-7db56f875b-fdzt8 1.6.10
details-v1-7d78fc5688-jmw6z.ns2 SYNCED SYNCED SYNCED SYNCED istiod-1-6-10-7db56f875b-fdzt8 1.6.10
kubesphere-router-ns2-7d448fb6b5-z77nq.kubesphere-controls-system SYNCED SYNCED SYNCED SYNCED istiod-1-6-10-7db56f875b-fdzt8 1.6.10
...
查看Listener
# istioctl7 pc l productpage-v1-844495cb4b-8dkxz.test
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15001 ALL Non-HTTP/Non-TCP
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: 0.0.0.0/0 Non-HTTP/Non-TCP
0.0.0.0 15006 Addr: 0.0.0.0/0 Non-HTTP/Non-TCP
0.0.0.0 15006 Trans: tls; App: HTTP TLS; Addr: 0.0.0.0/0 Non-HTTP/Non-TCP
0.0.0.0 15006 App: HTTP; Addr: 0.0.0.0/0 Non-HTTP/Non-TCP
0.0.0.0 15006 Addr: 10.233.70.26/32:15021 Non-HTTP/Non-TCP
0.0.0.0 15006 App: Istio HTTP Plain; Addr: 10.233.70.26/32:9080 Non-HTTP/Non-TCP
0.0.0.0 15006 Addr: 10.233.70.26/32:9080 Non-HTTP/Non-TCP
0.0.0.0 15010 App: HTTP Non-HTTP/Non-TCP
0.0.0.0 15010 ALL Non-HTTP/Non-TCP
10.233.17.226 15012 ALL Non-HTTP/Non-TCP
0.0.0.0 15014 App: HTTP Non-HTTP/Non-TCP
0.0.0.0 15014 ALL Non-HTTP/Non-TCP
0.0.0.0 15021 ALL Non-HTTP/Non-TCP
0.0.0.0 15090 ALL Non-HTTP/Non-TCP
0.0.0.0 16686 App: HTTP Non-HTTP/Non-TCP
0.0.0.0 16686 ALL Non-HTTP/Non-TCP
10.233.0.159 19093 ALL Non-HTTP/Non-TCP
10.233.0.159 19093 App: HTTP Non-HTTP/Non-TCP
10.233.40.24 50000 ALL Non-HTTP/Non-TCP
10.233.40.24 50000 App: HTTP Non-HTTP/Non-TCP
...
15001端口所有流量通过
istioctl7 pc l productpage-v1-844495cb4b-8dkxz.test --port 15001 -o json | jq
[
{
"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" # Cluster为PassthroughCluster,表明允许流量全部通过
}
}
],
"name": "virtualOutbound-catchall-tcp"
}
],
"trafficDirection": "OUTBOUND",
"hiddenEnvoyDeprecatedUseOriginalDst": true
}
]
由于我们知道productpage的端口为9080,我们直接看下这个端口
# istioctl7 pc l productpage-v1-844495cb4b-8dkxz.test --port 9080 -o json | jq
[
{
"name": "0.0.0.0_9080",
"address": {
"socketAddress": {
"address": "0.0.0.0",
"portValue": 9080
}
},
"filterChains": [
{
"filterChainMatch": {
"applicationProtocols": [
"http/1.0",
"http/1.1",
"h2c"
]
},
"filters": [
{
"name": "envoy.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager",
"statPrefix": "outbound_0.0.0.0_9080",
"rds": {
"configSource": {
"ads": {}
},
"routeConfigName": "9080" # rds的名字是9080
},
"httpFilters": [
{
"name": "istio.metadata_exchange",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm",
"value": {
"config": {
"configuration": "{}\n",
"vm_config": {
"code": {
"local": {
"inline_string": "envoy.wasm.metadata_exchange"
}
},
"runtime": "envoy.wasm.runtime.null"
}
}
}
}
},
{
"name": "istio.alpn",
"typedConfig": {
"@type": "type.googleapis.com/istio.envoy.config.filter.http.alpn.v2alpha1.FilterConfig",
"alpnOverride": [
{
"alpnOverride": [
"istio-http/1.0",
"istio"
]
},
{
"upstreamProtocol": "HTTP11",
"alpnOverride": [
"istio-http/1.1",
"istio"
]
},
{
"upstreamProtocol": "HTTP2",
"alpnOverride": [
"istio-h2",
"istio"
]
}
]
}
},
{
"name": "envoy.cors",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.http.cors.v2.Cors"
}
},
{
"name": "envoy.fault",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.http.fault.v2.HTTPFault"
}
},
{
"name": "istio.stats",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.extensions.filters.http.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": "stats_outbound"
}
}
}
}
},
{
"name": "envoy.router",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.http.router.v2.Router"
}
}
],
"tracing": {
"clientSampling": {
"value": 100
},
"randomSampling": {
"value": 1
},
"overallSampling": {
"value": 100
}
},
"streamIdleTimeout": "0s",
"useRemoteAddress": false,
"generateRequestId": true,
"upgradeConfigs": [
{
"upgradeType": "websocket"
}
],
"normalizePath": true
}
}
]
},
{
"filterChainMatch": {},
"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"
}
}
],
"metadata": {
"filterMetadata": {
"pilot_meta": {
"fallthrough": true
}
}
},
"name": "PassthroughFilterChain"
}
],
"deprecatedV1": {
"bindToPort": false
},
"listenerFilters": [
{
"name": "envoy.listener.tls_inspector",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.listener.tls_inspector.v2.TlsInspector"
}
},
{
"name": "envoy.listener.http_inspector",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.listener.http_inspector.v2.HttpInspector"
}
}
],
"listenerFiltersTimeout": "0.100s",
"continueOnListenerFiltersTimeout": true,
"trafficDirection": "OUTBOUND"
}
]
说明它走到了9080这个rds,看下这个rds,配置文件将近1000行,原因是把所有的route全部列出来了,下面我们只看与这个namespace下面的这个route
istioctl7 pc routes productpage-v1-844495cb4b-8dkxz.test --name 9080 -o json | jq | less #过滤reviews.test.svc
[
{
"name": "9080", # route的名字
"virtualHosts": [
{
"name": "allow_any", # 对于allow_any的virtualHosts全部放行
"domains": [
"*"
],
"routes": [
{
"name": "allow_any",
"match": {
"prefix": "/"
},
"route": {
"cluster": "PassthroughCluster",
"timeout": "0s",
"maxGrpcTimeout": "0s"
}
}
],
"includeRequestAttemptCount": true
},
{
"name": "details.test.svc.cluster.local:9080", # VirtualHosts,其实是http访问的时候的Header中的Host,若缺省则为url中的Host;类似nginx中的vhosts
"domains": [ # 对应的dns
"details.test.svc.cluster.local",
"details.test.svc.cluster.local:9080",
"details",
"details:9080",
"details.test.svc.cluster",
"details.test.svc.cluster:9080",
"details.test.svc",
"details.test.svc:9080",
"details.test",
"details.test:9080",
"10.233.16.147",
"10.233.16.147:9080"
],
"routes": [
{
"match": {
"prefix": "/" # 路由匹配规则
},
"route": {
"cluster": "outbound|9080|v1|details.test.svc.cluster.local", # cluster名字,当该vhosts匹配上这个路由后,路由至这个cluster,它的命名规则“流量方向|端口|版本|fqdn”
"timeout": "0s",
"retryPolicy": {
"retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
"numRetries": 2, # 当出现上面的条件时重试,重试次数
"retryHostPredicate": [
{
"name": "envoy.retry_host_predicates.previous_hosts"
}
],
"hostSelectionRetryMaxAttempts": "5",
"retriableStatusCodes": [
503
]
},
"maxGrpcTimeout": "0s"
},
"metadata": {
"filterMetadata": {
"istio": {
"config": "/apis/networking.istio.io/v1alpha3/namespaces/test/virtual-service/details" # 对应的virtualService
}
}
},
"decorator": {
"operation": "details.test.svc.cluster.local:9080/*"
}
}
],
"includeRequestAttemptCount": true
},
],
"validateClusters": false
}
]
通过fqdn来查找cluster信息
istioctl7 pc clusters productpage-v1-844495cb4b-8dkxz.test --fqdn details.test.svc.cluster.local
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
details.test.svc.cluster.local 9080 - outbound EDS details.test
details.test.svc.cluster.local 9080 v1 outbound EDS details.test
istioctl7 pc clusters productpage-v1-844495cb4b-8dkxz.test --fqdn details.test.svc.cluster.local -ojson | jq
[
{
"transportSocketMatches": [ # 在cluster里面有sds密钥配置信息
{
"name": "tlsMode-istio",
"match": {
"tlsMode": "istio"
},
"transportSocket": {
"name": "envoy.transport_sockets.tls",
"typedConfig": {
"@type": "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext",
"commonTlsContext": {
"tlsCertificateSdsSecretConfigs": [
{
"name": "default",
"sdsConfig": {
"apiConfigSource": {
"apiType": "GRPC",
"grpcServices": [
{
"envoyGrpc": {
"clusterName": "sds-grpc"
}
}
]
},
"initialFetchTimeout": "0s"
}
}
],
"combinedValidationContext": {
"defaultValidationContext": {
"matchSubjectAltNames": [
{
"exact": "spiffe://cluster.local/ns/test/sa/default"
}
]
},
"validationContextSdsSecretConfig": {
"name": "ROOTCA",
"sdsConfig": {
"apiConfigSource": {
"apiType": "GRPC",
"grpcServices": [
{
"envoyGrpc": {
"clusterName": "sds-grpc"
}
}
]
},
"initialFetchTimeout": "0s"
}
}
},
"alpnProtocols": [
"istio-peer-exchange",
"istio"
]
},
"sni": "outbound_.9080_.v1_.details.test.svc.cluster.local"
}
}
},
{
"name": "tlsMode-disabled",
"match": {},
"transportSocket": {
"name": "envoy.transport_sockets.raw_buffer"
}
}
],
"name": "outbound|9080|v1|details.test.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {}
},
"serviceName": "outbound|9080|v1|details.test.svc.cluster.local"
},
"connectTimeout": "10s",
"circuitBreakers": { # 熔断信息
"thresholds": [
{
"maxConnections": 4294967295, # 最大连接数
"maxPendingRequests": 4294967295,
"maxRequests": 4294967295, # 最大请求数
"maxRetries": 4294967295 # 最大重试次数
}
]
},
"metadata": {
"filterMetadata": {
"istio": {
"config": "/apis/networking.istio.io/v1alpha3/namespaces/test/destination-rule/details", # 匹配destinationRules
"subset": "v1" # 版本v1
}
}
},
"filters": [
{
"name": "istio.metadata_exchange",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange",
"value": {
"protocol": "istio-peer-exchange"
}
}
}
]
}
]
看下endpoint信息
istioctl7 pc endpoint productpage-v1-844495cb4b-8dkxz.test --cluster "outbound|9080|v1|details.test.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.233.70.30:9080 HEALTHY OK outbound|9080|v1|details.test.svc.cluster.local
直接根据port查看一个eds信息
➜ istioctl pc endpoint httpbin-7c8bfbfd46-znvf5.test --port 80
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.233.64.75:80 HEALTHY OK outbound|80||kubesphere-router-test.kubesphere-controls-system.svc.cluster.local
10.233.64.76:80 HEALTHY OK outbound|8080||httpbin.test.svc.cluster.local
127.0.0.1:80 HEALTHY OK inbound|8080||httpbin.test.svc.cluster.local
总结
一个Pod会有很多监听器,它会列出协议栈上的所有的监听的IP+端口,只有属于自已的端口才会有策略,其余不属于自己协议栈的listener会直接被标识为noHttp/noTcp。
router会根据Vhosts信息(即Header里面的Host信息,或是Url中的host信息)来匹配Path确实路由规则,转发流量至对应的Cluster。router会对应vitualService信息,把流量路由到逻辑地址。
Cluster中有密钥信息(即sds),会对描述流量行为,如熔断/重试等,并把流量路由到真实的endpoint地址。
endpoint对应一个IP+端口,确定四层的一个具体入口。
通过curl获取配置文件
15000是 envoy admin 端口
kubectl exec reviews-v1-6d8bc58dd7-ts8kw -c istio-proxy curl http://127.0.0.1:15000/config_dump > config_dump
config_dump可以改成listener,cluster,endpoint,route,secret
通过admin页面查看配置项
$ istio-1.6.10/bin/istioctl dashboard envoy kubesphere-router-ns4-6d4c9fb7fc-v9xjj.kubesphere-controls-system
http://localhost:64178
然后打开admin管理页面
页面上可以查看命令行的结果,不过会更直观些。
https://istio.io/latest/docs/ops/diagnostic-tools/proxy-cmd/