Istio 流量管理


流量管理是 istio 最核心的问题,涉及 v1alpha3 中的配置资源,包括Gateway、VirtualSerice、DestinationRule 等。本文主要是基于 Istio 基础一文已经部署的实例来进行讲解。

1   概述

对于入口流量管理,您可能会问: 为什么不直接使用 Kubernetes Ingress API ? 原因是 Ingress API 无法表达 Istio 的路由需求。 Ingress 试图在不同的 HTTP 代理之间取一个公共的交集,因此只能支持最基本的 HTTP 路由,最终导致需要将代理的其他高级功能放入到注解(annotation)中,而注解的方式在多个代理之间是不兼容的,无法移植。

Istio Gateway 通过将 L4-L6 配置与L7配置分离的方式克服了 Ingress 的这些缺点。 Gateway 只用于配置 L4-L6 功能(例如,对外公开的端口,TLS 配置),所有主流的L7代理均以统一的方式实现了这些功能。 然后,通过在 Gateway 上绑定 VirtualService 的方式,可以使用标准的 Istio 规则来控制进入 Gateway 的 HTTP 和 TCP 流量。

所谓四层负载均衡就是使用IP加端口的方式进行路由转发;七层负载均衡一般是基于请求URL地址的方式进行代理转发。同理,还有基于MAC地址信息(虚拟MAC地址到真实MAC地址)进行转发的二层负载均衡和基于IP地址(虚拟IP到真实IP)的三层负载均衡。

四层负载均衡具体实现方式为:通过报文中的IP地址和端口,再加上负载均衡设备所采用的负载均衡算法,最终确定选择后端哪台下游服务器。以TCP为例,客户端向负载均衡发送SYN请求建立第一次连接,通过配置的负载均衡算法选择一台后端服务器,并且将报文中的IP地址信息修改为后台服务器的IP地址信息,因此TCP三次握手连接是与后端服务器直接建立起来的。

七层服务均衡在应用层选择服务器,只能先与负载均衡设备进行TCP连接,然后负载均衡设备再与后端服务器建立另外一条TCP连接通道。因此,七层设备在网络性能损耗会更多一些。

从安全视角上: 四层负载均衡与服务器直接建立起TCP连接,很容易遭受SYN Flood攻击。SYN Flood是一种广为人知的DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽的攻击方式。从技术实现原理上可以看出,四层负载均衡很容易将垃圾流量转发至后台服务器,而七层设备则可以过滤这些恶意并清洗这些流量,但要求设备本身具备很强的抗DDOS流量的能力。

2   Gateway

典型的网格将具有一个或多个负载均衡器(我们称之为网关),它们从外部网络终止TLS并允许流量进入网格。逻辑上相当于网格边缘的一个负载均衡器,用于接收和处理网格边缘出站和入站的网络连接,其中包括 TCP/TLS 等相关的配置内容。有两类网关

  1. 内部虚拟 Mesh 网关:代表网格内部的所有 Sidecar,换句话说:所有网格内部服务之间的互相通信,都是通过这个网关进行的。承载了所有 Kubernetes Service 的流量,只要是注射了 Istio 的服务均可。
  2. 自定义 Gateway 网关:如果要对外提供服务,就需要定义 Gateway 对象,并在 VirtualService 的 gateways 字段中进行赋值。流经用 selector(一般直接用 istio: ingressgateway) 指定的 Pods 流量,也就是只能通过 ingressgateway 服务 IP 访问的流量(这里是最终通过该 IP 访问的,可以设置域名,只要最终通过该 IP 即可)

3   VirtualService

3.1   理解

所有流量无论从哪里进来,从 Gateway 网关进来,从 Service 资源进来,都由 VirtualService 提供服务,VirtualService 通过 DestinationRule 转发到实际的 Service 里的的 Pod(Pod 标签匹配的 DestinationRule 设置的 subset 标签)。可以看出,流量进来后,不再直接把 Kubernetes service 放在前面,而是把 istio 的 VirtualService 放在前线提供服务。

VirtualService 是基于7层流量的,对指定的 hosts 有效;当然提供服务可以是 http、tcp 等

3.2   实例

我们以下面的为例进行解释:

[yhdodo19@instance-1 ~]$ kubectl get svc
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
goapi         NodePort    10.97.35.169     <none>        81:30001/TCP   30h
goapisec      NodePort    10.111.145.131   <none>        82:30002/TCP   30h

[yhdodo19@instance-1 ~]$ kubectl get svc -n istio-system
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                           
istio-ingressgateway     LoadBalancer   10.99.215.11     <pending>     15020:31966/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32293/TCP,15030:30857/TCP,15031:30499/TCP,15032:31537/TCP,15443:32082/TCP

服务的映射关系可以直接替换访问,比如 10.99.217.250:443 等同于 10.142.0.3:31390、127.0.0.1:31390,可以直接替换

Gateway example-gateway 的 hosts 配置如下:

    hosts:
      - "*"

以该 Gateway 配置,以两种情况的 VirtualService 的理解它们之间的关系。

3.2.1   配置一

VirtualService 的 hosts 配置如下:

 hosts:
  - goapi.default.svc.cluster.local
  - goapisec.default.svc.cluster.local
  - kube.jemper.cn
 gateways:
  - example-gateway
  - mesh

并准备以下命令语句:

for i in `seq 10`; do curl http://10.106.118.207:81/index; done
for i in `seq 10`; do curl http://10.101.139.70:82/sec/index; done
for i in `seq 10`; do curl http://goapi:81/index; done
for i in `seq 10`; do curl http://goapisec:82/sec/index; done
for i in `seq 10`; do curl http://10.99.217.250:443/index -H 'host: kube.jemper.cn'; done
for i in `seq 10`; do curl http://10.99.217.250:443/sec/index -H 'host: kube.jemper.cn'; done

因此可以看出,Kubernetes Service 的 IP 在网格内被导向了域名,而域名因为在 VirtualService 配置所以受到其控制,所以体现出网格内外不一致的表现;而网格外不会被导向域名,所以不受其控制。

3.2.1   配置二

VirtualService 的 hosts 配置如下:

 hosts:
  - “*”
 gateways:
  - example-gateway

并准备以下命令语句:

for i in `seq 10`; do curl http://10.106.118.207:81/index; done
for i in `seq 10`; do curl http://10.101.139.70:82/sec/index; done
for i in `seq 10`; do curl http://goapi:81/index; done
for i in `seq 10`; do curl http://goapisec:82/sec/index; done
for i in `seq 10`; do curl http://10.99.217.250:443/index; done
for i in `seq 10`; do curl http://10.99.217.250:443/sec/index; done

4   DestinationRule

DestinationRule 是为 VirtualService 服务的,可以细分 Kubernetes Service 的 pods,以便一个 VirtualService 对应 Service 的多个版本。建议为每个网格都设置明确的目标访问规则。

5   总结

  1. Gateway: Istio Gateway是负责打开k8s上相关Istio的pods上的端口并接收主机的流量,是接收流量与路由之间的关键链接。L4-L6层配置,比如 TLS。Gateway 指向 Pods
  2. VirtualService: Istio VirtualService是“附加”到 Gateway 上的,并负责定义 Gateway 应实现的路由。可以将多个VirtualServices连接到Gateway,但不适用于同一个域。L7层配置,比如 CorsPolicy、HTTPRewrite、HTTPRedirect、HTTPMatchRequest 等。VirtualService 指向注射了 istio 的 Kubernetes Service。
  3. DestinationRule 依赖于 Kubernetes 的 Service 和其关联的 pods,并服务于 VirtualService。由此可以,istio 对 pods 要求必须关联 Service,而无论其是否开放端口,DestinationRule 的 host 是依赖于 Kubernetes Service。
  4. Gateway 的 hosts 是决定因素,VirtualService 的 hosts 是依赖于前者的。对于 Kubernetes 服务其 host 可以简写或全写比如:goapi、goapi.default.svc.cluster.local,建议写全。但访问的方式就更多了,比如 goapi、goapi.default、goapi.default.svc.cluster.local 都可以。

kubectl -n istio-system edit deployment istio-ingressgateway

kubectl -n istio-system edit svc istio-ingressgateway

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

kubectl get pods –all-namespaces -l app.kubernetes.io/name=ingress-nginx –watch kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx -o jsonpath=’{.items[0].metadata.name}'

kubectl exec -it nginx-ingress-controller-5694ccb578-w6wn5 -n ingress-nginx – /nginx-ingress-controller –version

curl -v http://34.74.171.148 -H ‘host: kube.jemper.cn’ curl -v http://35.227.70.245 -H ‘host: kube.jemper.cn’ curl -v http://35.237.188.250 -H ‘host: kube.jemper.cn’

for i in seq 10; do curl http://35.237.188.250:30001/index; done for i in seq 10; do curl http://10.109.74.93:81/index; done for i in seq 10; do curl http://10.99.215.11/index -H ‘host: kube.jemper.cn’; done

curl -v http://35.237.188.250:30001/index curl -v http://10.109.74.93:81/index curl http://10.99.215.11:443/sec/index -H ‘host: kube.jemper.cn’ curl http://10.99.215.11:443/index -H ‘host: kube.jemper.cn’ curl http://10.142.0.2:31390/sec/index -H ‘host: kube.jemper.cn’ curl http://10.99.215.11/index -H ‘host: kube.jemper.cn’ for i in seq 10; do curl http://10.99.215.11:443/index -H ‘host: kube.jemper.cn’; done for i in seq 10; do curl http://10.99.215.11:443/sec/index -H ‘host: kube.jemper.cn’; done

kubectl explain DestinationRule.spec –api-version=networking.istio.io/v1alpha3

scp -r -i /home/feixin10/.ssh/dodo /home/feixin10 yhdodo19@35.196.205.161:/home/yhdodo19

for i in seq 10; do curl http://35.237.188.250:30001/index; done for i in seq 10; do curl http://35.237.188.250:30002/sec/index; done

for i in seq 10; do curl http://10.97.35.169:81/index; done for i in seq 10; do curl http://10.111.145.131:82/sec/index; done

for i in seq 10; do curl http://goapi:81/index; done for i in seq 10; do curl http://goapisec:82/sec/index; done

sudo tcpdump port 8080 -n sudo tcpdump -i eth0 src host 10.2.200.11 or dst host 10.2.200.11

sudo tcpdump -i eth0 -s 80 -w /tmp/tcpdump.cap

参考文献 [1] Istio v1aplha3 路由 API 介绍. https://istio.io/zh/blog/2018/v1alpha3-routing/ [2] Traffic Management. https://istio.io/docs/reference/config/networking/