基于Istio ingress对外提供服务
1 简介
上一篇是在Service Mesh中两个应用之间互相访问,本片介绍下通过Istio Ingress把服务网络中的应用对外暴露,通过Ingress Gateway控制从外边访问服务网格中的应用。
在Service Mesh中部署两个服务,一个httpserver应用,一个Nginx,通过在Ingress Gateway中配置路由控制,使用同一个域名,不同的URI访问两个应用服务。如下:
| 1 | curl -H "Host: simple.baihl.io" $INGRESS_IP/simple/httpserver | 
$INGRESS_IP 为 Istio中Ingress Gateway对外的IP地址。
2 创建应用服务
| 1 | kubectl create ns simple | 
- simple.yaml
simple.yaml就是运行httpserver,并且定义了Service对外提供服务。
| 1 | apiVersion: apps/v1 | 
- nginx.yaml
 一个基本的Nginx服务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
 30apiVersion: apps/v1 
 kind: Deployment
 metadata:
 name: nginx-deployment
 spec:
 replicas: 1
 selector:
 matchLabels:
 app: nginx
 template:
 metadata:
 labels:
 app: nginx
 spec:
 containers:
 - name: nginx
 image: nginx
 apiVersion: v1
 kind: Service
 metadata:
 name: nginx
 spec:
 ports:
 - name: http
 port: 80
 protocol: TCP
 targetPort: 80
 selector:
 app: nginx
3 创建VirtualService
- istio-specs.yaml
VirtualService是在Istio服务网格内对服务的请求进行路由控制。
如下,通过创建VirtualService与gateway关联。分配控制对httpserver和nginx的访问。
| 1 | apiVersion: networking.istio.io/v1beta1 | 
部署完以上的服务,整体看下所有创建出来的对象:
执行kubectl get pod,svc,deployment,endpoints,VirtualService,Gateway  -n simple
可以看到,service/nginx 和 service/simple 分别是我们创建的两个应用程序Pod对外提供服务的Service,还有一个virtualservice,匹配的Host为”simple.baihl.io”。
4 通过Ingress Gateway访问服务
查看Ingress Gateway对外提供暴露的IP地址:
Ingress Gateway对外的IP为:10.96.190.18
| 1 | INGRESS_IP=10.96.190.18 | 
- 访问httpserver

- 访问Nginx

5 分析请求过程
5.1 Ingress Gateway Service
在访问IngressGateway时,首先经过的就是Ingress Gateway配置的Service,可以看下Service配置是什么。
执行kubectl get svc istio-ingressgateway -n istio-system  -o json
| 1 | "ports": [ | 
Service使用的type为LoadBalancer,配置了对外提供的端口80映射到宿主机的31373,在上边访问应用服务的时候因为是在Master节点,所以就直接访问了Service的IP地址10.96.190.18,但是在集群外部是无法访问10.96.190.18的,需要访问Master节点对外的IP地址,对于我本地的环境来说就是Master节点的IP地址192.168.170.137。所以在集群外部访问httpserver和nginx,需要访问 10.96.190.18:31373,操作如下:
| 1 | $ curl -H "Host: simple.baihl.io" 192.168.170.137:31373/simple/nginx | 
如上我在本地笔记本上访问Master节点的IP地址请求Isito中的Nginx服务。
5.2 iptables规则
为什么在外部访问192.168.170.137:31373和在Master节点上访问IngressGateway的IP都可以获得应用服务的响应,就是因为在Kubernetes的Master节点上的iptables规则。
比如,访问192.168.170.137:31373
| 1 | #对于访问目标端口为31373的请求,转到KUBE-SVC-G6D3V5KS3PXPUEDS | 
比如,访问10.96.190.18:80,会匹配到如下的iptables规则:
| 1 | #对于访问目标IP为10.96.190.18/32,目标端口为80的请求,转到KUBE-SVC-G6D3V5KS3PXPUEDS | 
对比上边两种访问情况的iptables规则匹配流程可以看到,最终都是对请求做了DNAT后,请求的目标IP地址变为10.10.1.4,目标端口变为8080。
可以看到,10.10.1.4的IP就是istio-ingressgateway的IP地址。
5.3 Envoy配置
目前请求转到了10.10.1.4:8080,所以可以看下在istio-ingressgateway中监听8080端口的是谁?
使用nsenter命令,进入istio-ingressgateway内部查看,可以发现监听8080端口的正式Envoy程序。
下边就可以通过看Envoy的配置,看看请求后边是怎么处理的。
- 首先看下监听8080端口的配置信息监听8080的listener匹配的route为http.8080,继续查看route信息。1 
 2
 3baihl@baihl-master:~$ istioctl pc listener -n istio-system istio-ingressgateway-576c469c96-spndl --port 8080 
 ADDRESS PORT MATCH DESTINATION
 0.0.0.0 8080 ALL Route: http.8080
- 查看route为http.8080根据route配置可以看到: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
 37baihl@baihl-master:~$ istioctl pc route -n istio-system istio-ingressgateway-576c469c96-spndl --name=http.8080 -o yaml 
 - ignorePortInHostMatching: true
 name: http.8080
 validateClusters: false
 virtualHosts:
 - domains:
 - simple.baihl.io
 includeRequestAttemptCount: true
 name: simple.baihl.io:80
 routes:
 match:
 caseSensitive: true
 ## 匹配/simple/httpserver的请求
 path: /simple/httpserver
 route:
 # httpserver route对应的cluster
 cluster: outbound|80||simple.simple.svc.cluster.local
 maxStreamDuration:
 grpcTimeoutHeaderMax: 0s
 maxStreamDuration: 0s
 prefixRewrite: /hello
 - decorator:
 operation: nginx.simple.svc.cluster.local:80/simple/nginx*
 match:
 caseSensitive: true
 prefix: /simple/nginx
 metadata:
 filterMetadata:
 istio:
 config: /apis/networking.istio.io/v1alpha3/namespaces/simple/virtual-service/simple
 route:
 # nginx 服务对应的cluster
 cluster: outbound|80||nginx.simple.svc.cluster.local
 maxStreamDuration:
 grpcTimeoutHeaderMax: 0s
 maxStreamDuration: 0s
 prefixRewrite: /
- 请求uri为/simple/httpserver,被outbound|80||simple.simple.svc.cluster.local处理。
- 请求uri为/simple/nginx,被outbound|80||nginx.simple.svc.cluster.local处理。
- 查看cluster
下边查看httpserver对应的的cluter:outbound|80||simple.simple.svc.cluster.local:
| 1 | baihl@baihl-master:~$ istioctl pc endpoints -n istio-system istio-ingressgateway-576c469c96-spndl --cluster="outbound|80||simple.simple.svc.cluster.local" | 
可以看到httpserver最终选择的endpoint为10.10.1.13:80。
| 1 | baihl@baihl-master:~$ kubectl get pod -n simple -o wide | 
可以看到运行httpserver的simple Pod,在集群内的IP地址就是10.10.1.13。
同样的方式,可以查看nginx服务对应的cluster:outbound|80||nginx.simple.svc.cluster.local:
| 1 | baihl@baihl-master:~$ istioctl pc endpoints -n istio-system istio-ingressgateway-576c469c96-spndl --cluster="outbound|80||nginx.simple.svc.cluster.local" | 
10.10.1.14对应的就是nginx-deployment Pod在集群内的IP地址。
根据上边的分析,在集群外通过istio-ingressgateway访问集群内部的应用程序,经过了iptables规则和ingressgateway中的路由控制,最后把请求分发到各个应用程序,通过ingressgateway也可以实现更加复杂的流量管理需求。
