本节展示一个请求从一个服务实例调用另一个服务的过程,分析一下请求是怎么从调用方到服务提供方的。
1.HTTP协议的请求
以service-python服务访问service-lua服务为例。
(1)DNS解析
当service-python服务要访问service-lua服务时,需要先通过kube-dns找到要访问服务的IP地址,也就是service-lua服务的Cluster IP,执行如下的命令可以看到DNS解析得到的service-lua服务的IP地址:
$ kubectl exec $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') -c service-python -- ping -c 1 service-lua PING service-lua (10.111.228.100): 56 data bytes 64 bytes from 10.111.228.100: seq=0 ttl=64 time=0.052 ms --- service-lua ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.052/0.052/0.052 ms
(2)调用方发起请求
当service-python服务拿到service-lua服务的IP地址后,发送请求给服务对应的IP和端口。由于Envoy代理会拦截所有流量,这个请求会最先到达service-python服务实例的Envoy代理上,查看Envoy代理监听了哪些地址和端口:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') ADDRESS PORT TYPE 10.244.1.16 80 HTTP 10.99.91.255 15011 TCP 10.110.93.233 443 TCP 10.99.91.255 31400 TCP 10.105.42.173 443 TCP 10.96.0.1 443 TCP 10.97.150.161 443 TCP 10.99.91.255 8060 TCP 10.101.237.88 15011 TCP 10.96.0.10 53 TCP 10.99.91.255 853 TCP 10.111.27.172 42422 TCP 10.99.91.255 443 TCP 0.0.0.0 15001 TCP 0.0.0.0 9093 HTTP 0.0.0.0 15010 HTTP 0.0.0.0 15031 HTTP 0.0.0.0 80 HTTP 0.0.0.0 9091 HTTP 0.0.0.0 15030 HTTP 0.0.0.0 15004 HTTP 0.0.0.0 8080 HTTP 0.0.0.0 8060 HTTP
从上面的监听器可以看出,由于service-python服务访问service-lua服务使用的是HTTP协议并且是80端口,所以会匹配到0.0.0.0:80监听器。
查看具体监听器的信息:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') --type HTTP --port 80 --address 0.0.0.0 -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": "80" }, ... } } ] } ], } ]
从上面的输出信息可以看出,0.0.0.0:80的监听器使用了名为80的路由规则。
查看路由规则信息如下:
$ istioctl proxy-config route $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') --name=80 -o json [ { "name": "80", "virtualHosts": [ ... { "name": "service-lua.default.svc.cluster.local:80", "domains": [ "service-lua.default.svc.cluster.local", "service-lua.default.svc.cluster.local:80", "service-lua", "service-lua:80", "service-lua.default.svc.cluster", "service-lua.default.svc.cluster:80", "service-lua.default.svc", "service-lua.default.svc:80", "service-lua.default", "service-lua.default:80", "10.109.146.20", "10.109.146.20:80" ], "routes": [ { "match": { "prefix": "/" }, "route": { "cluster": "outbound|80||service-lua.default.svc. cluster.local", "timeout": "0.000s", "maxGrpcTimeout": "0.000s" } ... } ] }, ... ], "validateClusters": false } ]
从上面的路由信息可以看出,对于请求service-lua服务的流量使用了名为"outbound|80||service-lua.default.svc.cluster.local"的服务实例集群。
查看服务实例集群的信息:
$ istioctl proxy-config cluster $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') --fqdn=service-lua.default.svc.cluster.local -o json [ { "name": "outbound|80||service-lua.default.svc.cluster.local", "type": "EDS", "edsClusterConfig": { "edsConfig": { "ads": {} }, "serviceName": "outbound|80||service-lua.default.svc.cluster.local" }, "connectTimeout": "1.000s", "circuitBreakers": { "thresholds": [ {} ] } } ]
从中可以看出,请求service-lua服务的流量最终都转发到了名为"outbound|80||service-lua.default.svc.cluster.local"的endpoint上。
查看endpoint信息:
$ istioctl proxy-config endpoint $(kubectl get pod -l app=service-python -o jsonpath='{.items[0].metadata.name}') --cluster "outbound|80||service-lua.default.svc.cluster.local" ENDPOINT STATUS CLUSTER 10.244.1.15:80 HEALTHY outbound|80||service-lua.default.svc.cluster.local 10.244.2.9:80 HEALTHY outbound|80||service-lua.default.svc.cluster.local
从中可以看出,请求service-lua服务的流量最终到达10.244.1.10:80和10.244.2.8:80地址上,而这两个地址其实就是Kubernetes中service-lua服务实例的Pod IP地址。
查看service-lua服务的Pod IP地址:
$ kubectl get pod -l app=service-lua -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE service-lua-v1-5c9bcb7778-l6qv2 2/2 Running 0 22m 10.244.1.15 lab3 <none> service-lua-v2-75cb5cdf8-svn5c 2/2 Running 0 22m 10.244.2.9 lab2 <none>
调用方的Envoy代理在获取到具体的service-lua服务实例地址后,对相应的地址发起请求。
(3)服务方接收请求
由于Envoy代理会拦截所有流量,这个请求会最先到达service-lua服务实例的Envoy代理上,查看Envoy代理监听了哪些地址和端口:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-lua -o jsonpath='{.items[0].metadata.name}') ADDRESS PORT TYPE 10.244.1.15 80 HTTP 10.99.91.255 443 TCP 10.99.91.255 8060 TCP 10.111.27.172 42422 TCP 10.96.0.1 443 TCP 10.110.93.233 443 TCP 10.97.150.161 443 TCP 10.99.91.255 31400 TCP 10.101.237.88 15011 TCP 10.96.0.10 53 TCP 10.99.91.255 15011 TCP 10.99.91.255 853 TCP 10.105.42.173 443 TCP 0.0.0.0 9091 HTTP 0.0.0.0 8060 HTTP 0.0.0.0 15010 HTTP 0.0.0.0 8080 HTTP 0.0.0.0 80 HTTP 0.0.0.0 9093 HTTP 0.0.0.0 15030 HTTP 0.0.0.0 15031 HTTP 0.0.0.0 15004 HTTP 0.0.0.0 15001 TCP
从上面的监听器可以看出,请求service-lua服务实例的流量会匹配到10.244.1.15:80监听器。
查看具体监听器的信息:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-lua -o jsonpath='{.items[0].metadata.name}') --type HTTP --port 80 --address 10.244.1.15 -o json ... "virtual_hosts": [ { "domains": [ "*" ], "name": "inbound|http|80", "routes": [ { ... "route": { "cluster": "inbound|80||service-lua.default.svc.cluster.local", "max_grpc_timeout": "0.000s", "timeout": "0.000s" } } ] } ] ...
从上面的路由规则可以看出,10.244.1.15:80监听器会使用名为"inbound|80||service-lua.default.svc.cluster.local"的服务实例集群。
查看服务实例集群的信息:
$ istioctl proxy-config cluster $(kubectl get pod -l app=service-lua -o jsonpath='{.items[0].metadata.name}') --fqdn=service-lua.default.svc.cluster.local --direction inbound -o json [ { "name": "inbound|80||service-lua.default.svc.cluster.local", "connectTimeout": "1.000s", "hosts": [ { "socketAddress": { "address": "127.0.0.1", "portValue": 80 } } ], "circuitBreakers": { "thresholds": [ {} ] } } ]
从上面的服务实例集群信息可以看出,请求service-lua服务的流量最终地址为127.0.0.1:80。service-lua服务实例的Envoy代理请求本地址获取响应结果后,返回给服务调用方的Envoy代理,再由调用方的Envoy代理返回数据给服务调用方。
2.TCP协议的请求
以service-go服务访问Redis服务为例。
(1)DNS解析
当service-go服务要访问Redis服务时,需要先通过kube-dns找到要访问服务IP地址,也就是Redis服务的Cluster IP,执行如下的命令可以看到DNS解析得到Redis服务的IP地址:
$ kubectl exec $(kubectl get pod -l app=service-go -o jsonpath='{.items[0].metadata.name}') -c service-go -- ping -c 1 redis PING redis (10.96.84.23): 56 data bytes 64 bytes from 10.96.84.23: seq=0 ttl=64 time=0.066 ms --- redis ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.066/0.066/0.066 ms
(2)调用方发起请求
当service-go服务拿到Redis服务的IP地址后,发送请求给服务对应的IP和端口。由于Envoy代理会拦截所有流量,这个请求会最先到达service-go服务实例的Envoy代理上,查看Envoy代理监听了哪些地址和端口:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-go -o jsonpath='{.items[0].metadata.name}') ADDRESS PORT TYPE 10.244.2.8 80 HTTP 10.99.91.255 443 TCP 10.96.0.1 443 TCP 10.97.150.161 443 TCP 10.105.42.173 443 TCP 10.99.91.255 31400 TCP 10.99.91.255 8060 TCP 10.96.0.10 53 TCP 10.110.93.233 443 TCP 10.111.27.172 42422 TCP 10.101.237.88 15011 TCP 10.99.91.255 15011 TCP 10.99.91.255 853 TCP 0.0.0.0 15030 HTTP 0.0.0.0 15010 HTTP 0.0.0.0 8080 HTTP 0.0.0.0 8060 HTTP 0.0.0.0 15031 HTTP 0.0.0.0 9091 HTTP 0.0.0.0 15004 HTTP 0.0.0.0 9093 HTTP 0.0.0.0 80 HTTP 0.0.0.0 15001 TCP 10.96.84.23 6379 TCP
从上面的监听器可以看出,由于service-go服务访问Redis服务使用的是TCP协议并且是6379端口,所以会匹配到10.96.84.23:6379监听器。
查看具体监听器的信息:
$ istioctl proxy-config listener $(kubectl get pod -l app=service-go -o jsonpath='{.items[0].metadata.name}') --type TCP --port 6379 --address 10.96.84.23 -o json ... "filters": [ { "name": "envoy.tcp_proxy", "config": { ... "cluster": "outbound|6379||redis.default.svc.cluster.local", "stat_prefix": "outbound|6379||redis.default.svc.cluster.local" } } ]
从上面的监听器信息可以看出,对于请求Redis服务的流量使用了名为"outbound|6379||redis.default.svc.cluster.local"的服务实例集群。
查看服务实例集群的信息:
$ istioctl proxy-config cluster $(kubectl get pod -l app=service-go -o jsonpath='{.items[0].metadata.name}') --fqdn=redis.default.svc.cluster.local -o json [ { "name": "outbound|6379||redis.default.svc.cluster.local", "type": "EDS", "edsClusterConfig": { "edsConfig": { "ads": {} }, "serviceName": "outbound|6379||redis.default.svc.cluster.local" }, "connectTimeout": "1.000s", "circuitBreakers": { "thresholds": [ {} ] } } ]
从上面的服务实例集群信息可以看出,请求Redis服务的流量最终都转发到了名为"outbound|6379||redis.default.svc.cluster.local"的endpoint上。
查看endpoint信息:
$ istioctl proxy-config endpoint $(kubectl get pod -l app=service-go -o jsonpath='{.items[0].metadata.name}') --cluster "outbound|6379||redis.default.svc.cluster.local" ENDPOINT STATUS CLUSTER 10.244.2.12:6379 HEALTHY outbound|6379||redis.default.svc.cluster.local
可以看出,请求Redis服务的流量最终到达10.244.2.12:6379地址上,而这个地址其实就是Kubernetes中Redis服务实例的Pod IP地址。
查看Redis服务实例的Pod IP地址:
$ kubectl get pod -l app=redis -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE redis-v1-7d56d758f5-5bx5w 2/2 Running 0 22m 10.244.2.12 lab2 <none>
调用方的Envoy代理在获取到具体的服务实例地址后,对相应的地址发起请求。
(3)服务方接收请求
由于Envoy代理会拦截所有流量,这个请求会最先到达Redis服务实例的Envoy代理上,查看Envoy代理监听了哪些地址和端口:
$ istioctl proxy-config listener $(kubectl get pod -l app=redis -o jsonpath='{.items[0].metadata.name}') ADDRESS PORT TYPE 10.244.2.12 6379 TCP 10.111.27.172 42422 TCP 10.96.0.10 53 TCP 10.110.93.233 443 TCP 10.99.91.255 443 TCP 10.99.91.255 8060 TCP 10.97.150.161 443 TCP 10.99.91.255 15011 TCP 10.96.84.23 6379 TCP 10.99.91.255 31400 TCP 10.99.91.255 853 TCP 10.101.237.88 15011 TCP 10.96.0.1 443 TCP 10.105.42.173 443 TCP 0.0.0.0 9093 HTTP 0.0.0.0 15031 HTTP 0.0.0.0 15010 HTTP 0.0.0.0 80 HTTP 0.0.0.0 15004 HTTP 0.0.0.0 8080 HTTP 0.0.0.0 8060 HTTP 0.0.0.0 15030 HTTP 0.0.0.0 9091 HTTP 0.0.0.0 15001 TCP
从上面的监听器可以看出,请求Redis服务实例的流量会匹配到10.244.2.12:6379监听器。
查看具体监听器的信息:
$ istioctl proxy-config listener $(kubectl get pod -l app=redis -o jsonpath='{.items[0].metadata.name}') --type TCP --port 6379 --address 10.244.2.12 -o json ... { "name": "envoy.tcp_proxy", "config": { ... "cluster": "inbound|6379||redis.default.svc.cluster.local", "stat_prefix": "inbound|6379||redis.default.svc.cluster.local" } } ...
从中可以看出,10.244.2.12:6379监听器会使用名为"inbound|6379||redis.default.svc.cluster.local"的服务实例集群。
查看服务实例集群的信息:
$ istioctl proxy-config cluster $(kubectl get pod -l app=redis -o jsonpath='{.items[0].metadata.name}') --fqdn=redis.default.svc.cluster.local --direction inbound -o json [ { "name": "inbound|6379||redis.default.svc.cluster.local", "connectTimeout": "1.000s", "hosts": [ { "socketAddress": { "address": "127.0.0.1", "portValue": 6379 } } ], "circuitBreakers": { "thresholds": [ {} ] } } ]
从中可以看出,请求Redis服务的流量最终地址为127.0.0.1:6379。Redis服务实例的Envoy代理请求本地地址获取响应结果后,返回给服务调用方的Envoy代理,再由Envoy代理返回数据给服务调用方。