5.3.7 流量镜像
流量镜像,也称为影子流量,是一个以尽可能低的风险为生产带来变化的强大的功能。服务新版本上线时,对服务的性能和bug并没有太大把握,流量镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。
任务:把流量全部路由到v1
版本的测试服务。然后,执行规则将一部分流量镜像到v2
版本。
1.前置条件
1.安装好Istio 2.部署两个版本的httpbin服务,并开启访问日志功能
httpbin-v1
cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin-v1
spec:
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: 80
EOF
deployment.apps/httpbin-v1 created
httpbin-v2
cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin-v2
spec:
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: 80
EOF
deployment.apps/httpbin-v2 created
httpbin service
kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
EOF
service/httpbin created
3.启动sleep
服务,这样就可以使用curl
来提供负载
sleep service
cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep","3650d"]
imagePullPolicy: IfNotPresent
EOF
deployment.apps/sleep created
2.创建一个默认路由策略
默认情况下,Kubernetes在httpbin服务的两个版本之间进行负载均衡。在此步骤中会更改该行为,把所有流量都路由到v1
版本。
1.创建一个默认路由规则,将所有流量路由到服务的v1
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin
http:
- route:
- destination:
host: httpbin
subset: v1
weight: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
EOF
virtualservice.networking.istio.io/httpbin created
destinationrule.networking.istio.io/httpbin created
现在所有流量都转到httpbin:v1
服务。
2.向服务发送一部分流量
export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it "$SLEEP_POD" -c sleep -- curl -sS http://httpbin:8000/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/7.35.0",
"X-B3-Parentspanid": "91ffa12314782a09",
"X-B3-Sampled": "1",
"X-B3-Spanid": "012952154e90d7cb",
"X-B3-Traceid": "70956ad857e4bfd191ffa12314782a09",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=bc31ed168cab2d9b5e0bd47ddf3f0b3cbbc995c9323357dca0de153b4293dfe3;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
}
}
3.分别查看httpbin
pod的v1
和v2
两个版本的日志,可以看到只有v1版本的访问日志条目。
export V1_POD=$(kubectl get pod -l app=httpbin,version=v1 -o jsonpath={.items..metadata.name})
kubectl logs "$V1_POD" -c httpbin
export V2_POD=$(kubectl get pod -l app=httpbin,version=v2 -o jsonpath={.items..metadata.name})
kubectl logs "$V2_POD" -c httpbin
3.流量镜像到v2
1.改变流量规则将流量镜像到v2
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin
http:
- route:
- destination:
host: httpbin
subset: v1
weight: 100
mirror:
host: httpbin
subset: v2
mirrorPercentage:
value: 100.0
EOF
virtualservice.networking.istio.io/httpbin configured
这个路由规则发送100%流量到v1
版本。最后一节表示您将100%的相同流量镜像(即发送)到httpbin:v2
服务。当流量被镜像时,请求将发送到镜像服务中,并在headers中的Host/Authority
属性值上追加-shadow
。例如cluster-1
变为cluster-1-shadow
。
此外,重点注意这些被镜像的流量是『 即发即弃』的,就是说镜像请求的响应会被丢弃。
您可以使用mirrorPercentage
下的value
属性来设置镜像流量的百分比,而不是镜像全部请求。为了兼容老版本,如果这个属性不存在,将镜像所有流量。
2.发送流量测试
kubectl exec -it "${SLEEP_POD}" -c sleep -- curl -sS http://httpbin:8000/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/7.35.0",
"X-B3-Parentspanid": "a60a327f14ed15f3",
"X-B3-Sampled": "1",
"X-B3-Spanid": "ee6beda1c7ba4061",
"X-B3-Traceid": "1212719a8fbb98e1a60a327f14ed15f3",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=bc31ed168cab2d9b5e0bd47ddf3f0b3cbbc995c9323357dca0de153b4293dfe3;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
}
}
现在就可以看到v1
和v2
版本中都有了访问日志。v2
版本中的访问日志就是由镜像流量产生的,这些请求的实际目标是v1
版本。
kubectl logs "$V1_POD" -c httpbin
kubectl logs "$V2_POD" -c httpbin
4.清理
1.清楚规则
kubectl delete virtualservice httpbin
kubectl delete destinationrule httpbin
2.关闭Httpbin
服务和客户端
kubectl delete deploy httpbin-v1 httpbin-v2 sleep
kubectl delete svc httpbin