一、理解流量镜像
流量镜像(Mirroring/traffic-shadow),也叫作影子流量,是指通过一定的配置将线上的真实流量复制一份到镜像服务中去,我们通过流量镜像转发以达到在不影响线上服务的情况下对流量或请求内容做具体分析的目的,它的设计思想是只做转发而不接收响应(fire and forget)。这个功能在传统的微服务架构里是很难做到的,一方面,传统服务之间的通讯是由SDK支持的,那么对流量镜像就代表着在业务服务逻辑中有着镜像逻辑相关代码的侵入,这会影响业务服务的代码的整洁性。另一方面,流量镜像的功能是需要非常灵活的,多维度,可动态管控的一个组件。如果将这样的一个组件集成到SDK中去完成它的使命后却无法及时清除,这样的设计势必是臃肿而繁琐的。所幸的是,随着微服务架构的发展,Service Mesh登上了历史舞台,成为新一代的服务架构引领者。而Istio作为Service Mesh优秀的落地架构,利用它本身使用Envoy代理转发流量的特性,轻松的支持了流量镜像的功能,再加上它的实现不需要任何代码的侵入,只需要在配置文件中简单加上几个配置即可完成。
二、配置流量镜像
1)部署httpbin服务
➜ cat httpbin.yaml
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
➜ kubectl apply -f httpbin.yaml
deployment.apps/httpbin-v1 created
kubectl describe deploy httpbin
Name: httpbin-v1
Namespace: default
CreationTimestamp: Sun, 25 Jul 2021 17:25:28 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=httpbin,version=v1
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=httpbin
version=v1
Containers:
httpbin:
Image: docker.io/kennethreitz/httpbin
Port: 80/TCP
Host Port: 0/TCP
Command:
gunicorn
--access-logfile
-
-b
0.0.0.0:80
httpbin:app
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: httpbin-v1-75d9447d79 (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 64s deployment-controller Scaled up replica set httpbin-v1-75d9447d79 to 1
2)为httpbin服务创建service
➜ cat httpbin-service.yaml
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
➜ kubectl apply -f httpbin-service.yaml
service/httpbin configured
➜ kubectl describe svc httpbin
Name: httpbin
Namespace: default
Labels: app=httpbin
Annotations: <none>
Selector: app=httpbin
Type: ClusterIP
IP: 10.110.191.190
Port: http 8000/TCP
TargetPort: 80/TCP
Endpoints: 10.1.8.247:80
Session Affinity: None
Events: <none>
3)为httpbin服务创建虚拟服务
➜ cat httpbin-virtualservice.yaml
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
➜ kubectl apply -f httpbin-virtualservice.yaml
virtualservice.networking.istio.io/httpbin configured
destinationrule.networking.istio.io/httpbin created
➜ kubectl describe vs httpbin
Name: httpbin
Namespace: default
Labels: <none>
Annotations: <none>
API Version: networking.istio.io/v1beta1
Kind: VirtualService
Metadata:
Creation Timestamp: 2021-07-03T09:39:26Z
Generation: 1
Managed Fields:
API Version: networking.istio.io/v1alpha3
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:gateways:
f:hosts:
f:http:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2021-07-03T09:39:26Z
Resource Version: 633475
Self Link: /apis/networking.istio.io/v1beta1/namespaces/default/virtualservices/httpbin
UID: 4bf50ddd-6d1c-4e3b-948e-56d04b5f2332
Spec:
Gateways:
httpbin-gateway
Hosts:
httpbin.example.com
Http:
Match:
Uri:
Prefix: /status
Uri:
Prefix: /delay
Route:
Destination:
Host: httpbin
Port:
Number: 8000
Events: <none>
➜ kubectl describe dr httpbin
Name: httpbin
Namespace: default
Labels: <none>
Annotations: <none>
API Version: networking.istio.io/v1beta1
Kind: DestinationRule
Metadata:
Creation Timestamp: 2021-07-25T09:31:42Z
Generation: 1
Managed Fields:
API Version: networking.istio.io/v1alpha3
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:host:
f:subsets:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2021-07-25T09:31:42Z
Resource Version: 666137
Self Link: /apis/networking.istio.io/v1beta1/namespaces/default/destinationrules/httpbin
UID: 4a99e110-906a-431d-b587-b1c0eae8e4ba
Spec:
Host: httpbin
Subsets:
Labels:
Version: v1
Name: v1
Labels:
Version: v2
Name: v2
Events: <none>
4)使用sleep服务做测试,并查看httpbin v1和v2的日志输出
➜ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
➜ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl http://httpbin:8000/headers'
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/7.77.0-DEV",
"X-B3-Parentspanid": "bd6f44226089fb4b",
"X-B3-Sampled": "1",
"X-B3-Spanid": "377f317ffc2235b3",
"X-B3-Traceid": "48b8f6202e115aafbd6f44226089fb4b",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=95c72738e0374abbc3de04ac172bb19aade9e5002af28031e0b326682a903dbd;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
}
}
➜ kubectl logs -f httpbin-v1-75d9447d79-2hsxp -c httpbin
[2021-07-25 09:25:34 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2021-07-25 09:25:34 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
[2021-07-25 09:25:34 +0000] [1] [INFO] Using worker: sync
[2021-07-25 09:25:34 +0000] [9] [INFO] Booting worker with pid: 9
127.0.0.6 - - [25/Jul/2021:09:34:29 +0000] "GET /headers HTTP/1.1" 200 527 "-" "curl/7.77.0-DEV"
127.0.0.6 - - [25/Jul/2021:09:35:16 +0000] "GET /headers HTTP/1.1" 200 527 "-" "curl/7.77.0-DEV"
➜ kubectl logs -f httpbin-v2-34asd47d59-4tffx -c httpbin
[2021-07-25 09:25:34 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2021-07-25 09:25:34 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
[2021-07-25 09:25:34 +0000] [1] [INFO] Using worker: sync
[2021-07-25 09:25:34 +0000] [9] [INFO] Booting worker with pid: 9
5)创建流量镜像的虚拟服务
➜ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- '*'
gateways:
- istio-system/ingressgateway
http:
- match:
- uri:
prefix: /httpbin
rewrite:
uri: /
route:
- destination:
host: httpbin
subset: v1
weight: 100
mirror:
host: httpbin
subset: v2
mirror_percent: 100
EOF
Warning: using deprecated setting "mirrorPercent", use "mirrorPercentage" instead
virtualservice.networking.istio.io/httpbin configured
➜ kubectl describe vs httpbin | grep mirror
mirror_percent: 100
6)再次访问httpbin服务并查看v1和v2的日志
➜ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl http://httpbin:8000/headers'
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/7.77.0-DEV",
"X-B3-Parentspanid": "a54f646bc4278c3a",
"X-B3-Sampled": "1",
"X-B3-Spanid": "7c821b85706fe417",
"X-B3-Traceid": "acaf9443d7661acea54f646bc4278c3a",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=95c72738e0374abbc3de04ac172bb19aade9e5002af28031e0b326682a903dbd;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
}
}
➜ kubectl logs -f httpbin-v1-75d9447d79-2hsxp -c httpbin
[2021-07-25 09:25:34 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2021-07-25 09:25:34 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
[2021-07-25 09:25:34 +0000] [1] [INFO] Using worker: sync
[2021-07-25 09:25:34 +0000] [9] [INFO] Booting worker with pid: 9
127.0.0.6 - - [25/Jul/2021:09:34:29 +0000] "GET /headers HTTP/1.1" 200 527 "-" "curl/7.77.0-DEV"
127.0.0.6 - - [25/Jul/2021:09:43:57 +0000] "GET /headers HTTP/1.1" 200 527 "-" "curl/7.77.0-DEV"
➜ kubectl logs -f httpbin-v2-34asd47d59-4tffx -c httpbin
[2021-07-25 09:25:34 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2021-07-25 09:25:34 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
[2021-07-25 09:25:34 +0000] [1] [INFO] Using worker: sync
[2021-07-25 09:25:34 +0000] [9] [INFO] Booting worker with pid: 9
127.0.0.6 - - [25/Jul/2021:09:43:57 +0000] "GET /headers HTTP/1.1" 200 527 "-" "curl/7.77.0-DEV"
7)清理
➜ kubectl delete vs httpbin
virtualservice.networking.istio.io "httpbin" deleted
➜ kubectl delete dr httpbin
destinationrule.networking.istio.io "httpbin" deleted
➜ kubectl delete deploy httpbin-v1
deployment.apps "httpbin-v1" deleted
➜ kubectl delete deploy httpbin-v2
deployment.apps "httpbin-v2" deleted
➜ kubectl delete svc httpbin
service "httpbin" deleted