istio 1.10学习笔记10: Istio流量管理之流量镜像

流量镜像,也叫称为影子流量,是指将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。 本节将测试使用istio流量管理中的流量镜像功能。会在k8s的default命名空间内部署httpbin服务的v1和v2两个版本,首先把流量全部路由到httpbin:v1,然后执行规则将一部分流量镜像到v2版本。

部署服务并配置默认路由到v1版本

因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,所以这里直接部署httpbin应用v1和v2的两个版本。

httpbin v1的deployment:

cat <<EOF | kubectl create -f -apiVersion: apps/v1kind: Deploymentmetadata: name: httpbin-v1spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"] ports: - containerPort: 80EOF

httpbin v2的deployment:

cat <<EOF | kubectl create -f -apiVersion: apps/v1kind: Deploymentmetadata: name: httpbin-v2spec: replicas: 1 selector: matchLabels: app: httpbin version: v2 template: metadata: labels: app: httpbin version: v2 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"] ports: - containerPort: 80EOF

httpbin的k8s service:

kubectl create -f - <<EOFapiVersion: v1kind: Servicemetadata: name: httpbin labels: app: httpbinspec: ports: - name: http port: 8000 targetPort: 80 selector: app: httpbinEOF

创建httpbin的目标规则,并配置好v1和v2两个服务子集:

kubectl apply -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: DestinationRulemetadata: name: httpbinspec: host: httpbin subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2EOF

为了能从集群外部访问httpbin,给它创建一个Ingress Gateway:

kubectl apply -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: Gatewaymetadata: name: httpbin-gatewayspec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - httpbin.example.com tls: httpsRedirect: true - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE credentialName: bookinfo-credential # must be the same as secret hosts: - httpbin.example.comEOF

这里将使用二级域名httpbin.example.com作为入口,因为前面为bookinfo应用创建Gateway时创建好的证书bookinfo-credential里是*.example.com的通配证书,这里直接使用这个证书bookinfo-credential。

接下来为httpbin服务创建虚拟服务,并与上面创建的gateway关联,创建好入口路由规则:

kubectl apply -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: httpbinspec: gateways: - httpbin-gateway hosts: - httpbin.example.com http: - route: - destination: host: httpbin port: number: 8000 subset: v1 weight: 100EOF

此时从入口域名httpbin.example.com访问httpbin服务时,所有的流量都将被路由到httpbin:v1

在集群外部访问https://httpbin.example.com/headers,正常返回信息:

curl https://httpbin.example.com/headers{ "headers": { "Accept": "*/*", "Host": "httpbin.example.com", "User-Agent": "curl/7.64.1", "X-B3-Parentspanid": "f11310681322428c", "X-B3-Sampled": "1", "X-B3-Spanid": "d7d9533be9694d50", "X-B3-Traceid": "7fad3179541ed266f11310681322428c", "X-Envoy-Attempt-Count": "1", "X-Envoy-Internal": "true", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=6bbc6b64389016a1ed1dcf2219cfb8e626021e6e1d54205e586441ac15b2b7f5;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" }}

此时在k8s中分别查看httbin服务v1和v2两个版本pod的日志,发现v1有访问日志,v2没有访问日志,说明上面配置生效,目前是所有的流量都被配置路由到了httpbin v1上。

export V1_POD=$(kubectl get pod -l app=httpbin,version=v1 -o jsonpath={.items..metadata.name})kubectl logs "$V1_POD" -c httpbin127.0.0.6 - - [27/Jul/2021:14:05:19 +0000] "GET /headers HTTP/1.1" 200 599 "-" "curl/7.64.1"export V2_POD=$(kubectl get pod -l app=httpbin,version=v2 -o jsonpath={.items..metadata.name})kubectl logs "$V2_POD" -c httpbin无访问日志打印镜像流量到v2版本

接下来改变httpbin虚拟服务中的路由规则,配置镜像100%的流量到v2版本:

kubectl apply -f - <<EOFapiVersion: networking.istio.io/v1alpha3kind: VirtualServicemetadata: name: httpbinspec: gateways: - httpbin-gateway hosts: - httpbin.example.com http: - route: - destination: host: httpbin port: number: 8000 subset: v1 weight: 100 mirror: host: httpbin subset: v2 mirrorPercentage: value: 100.0EOF

现在这个是虚拟服务的路由规则是将100%的流量路由到httpbin:v1,同时将100%的相同流量镜像到httpbin:v2。 需要注意,当流量被镜像时,请求将发送到镜像服务,并在headers中的Host/Authority属性值上追加-shadow。例如cluster-1变为cluster-1-shadow, 另外注意镜像的流量是即发即弃的,就是说镜像请求的响应会被丢弃。

此时在集群外部访问https://httpbin.example.com/headers,在k8s中分别查看httbin服务v1和v2两个版本pod的日志,发现两个版本的pod都有访问日志。

总结

流量镜像(Traffic Mirroring),也称为影子流量(Traffic Shadowing), 是一种强大的、无风险的测试应用版本的方法,它将实时流量的副本发送给被镜像的服务。 使用流量镜像,可以搭建一个与原环境类似的环境以进行验收测试,从而提前发现问题。 由于镜像流量存在于主服务关键请求路径带外,终端用户在测试全过程不会受到影响。另外在使用流量镜像之前,必须确认镜像服务连接的数据状态存储(例如数据库等)是独立的,避免污染关键请求路径上的状态存储。

参考

  • https://istio.io/latest/zh/docs/tasks/traffic-management/mirroring/