在非istio的环境中,如果我们选择了zipkin作为链路追踪的解决方案,那么我们需要业务代码里对每次调用生成span/trace id,虽然大部分流行语言zipkin都提供了对应的sdk帮我们做了这些集成工作,但是我们还是要在发出请求时手动调用sdk提供的方法生成并携带相应header到业务下游,相当于要对每一种语言都要去手动做一次 request的封装,如果公司使用的语言多了那么会是一种很繁琐的工作。那么有没有一种工具能帮我们自动生成每次调用所需的信息呢? 答案当然是有的,在istio环境中,这一切都变成了可能、当envoy收到调用请求时,会自动帮我们注入所需的headers,在业务代码中我们无需做任何改动,只需要调用下游服务时传递header 就可以了。参考地址:https://istio.io/latest/zh/docs/tasks/observability/distributed-tracing/overview/
下面是一个python flask 应用在istio中接入zipkin的例子:
1.拓扑:
有三个应用,分别是 zipkin-a , zipkin-b, zipkin-c
调用关系是: zipkin-a -----> zipkin-b ----> zipkin-c
案例代码:
zipkin-a:
from flask import Flask,request import requests app = Flask(__name__) @app.route('/') def hello_worlda(): tmp_headers = {} b3_headers = ["x-request-id","x-b3-traceid","x-b3-spanid","x-b3-parentspanid","x-b3-sampled","x-b3-flags","x-ot-span-context"] for header in b3_headers: if request.headers.get(header): tmp_headers.update({header:request.headers.get(header)}) requests.get('http://zipkin-b:5001',headers=tmp_headers) return 'zipkin-a!' if __name__ == '__main__': app.run(host="0.0.0.0",port=5000)
zipkin-b:
from flask import Flask,request import requests app = Flask(__name__) @app.route('/') def hello_worlda(): tmp_headers = {} b3_headers = ["x-request-id","x-b3-traceid","x-b3-spanid","x-b3-parentspanid","x-b3-sampled","x-b3-flags","x-ot-span-context"] for header in b3_headers: if request.headers.get(header): tmp_headers.update({header:request.headers.get(header)}) requests.get('http://zipkin-c:5002', headers=tmp_headers) return 'zipkin-b' if __name__ == '__main__': app.run(host="0.0.0.0",port=5001)
zipkin-c:
from flask import Flask,request app = Flask(__name__) @app.route('/') def hello_world(): print(' ------------- ^^^ -----------') print(request.headers) return 'Hello World!' if __name__ == '__main__': app.run(host="0.0.0.0",port=5002)
对应k8s manifest:
zipkin-a:
kind: Deployment metadata: name: zipkin-a spec: selector: matchLabels: app: zipkin-a version: "v1" replicas: 1 template: metadata: labels: app: zipkin-a version: "v1" spec: containers: - name: zipkin-a image: reg.xthklocal.cn/xthk-library/zipkin_a command: ["python","/tmp/a.py"] ports: - containerPort: 5000 name: http protocol: TCP --- apiVersion: v1 kind: Service metadata: name: zipkin-a spec: ports: - name: http-5000 port: 5000 protocol: TCP targetPort: 5000 selector: app: zipkin-a type: ClusterIP
zipkin-b:
apiVersion: apps/v1 kind: Deployment metadata: name: zipkin-b spec: selector: matchLabels: app: zipkin-b version: "v1" replicas: 1 template: metadata: labels: app: zipkin-b version: "v1" spec: containers: - name: zipkin-b image: reg.xthklocal.cn/xthk-library/zipkin_b command: ["python","/tmp/b.py"] ports: - containerPort: 5001 name: http protocol: TCP --- apiVersion: v1 kind: Service metadata: name: zipkin-b spec: ports: - name: http-5000 port: 5001 protocol: TCP targetPort: 5001 selector: app: zipkin-b type: ClusterIP
zipkin-c:
apiVersion: apps/v1 kind: Deployment metadata: name: zipkin-c spec: selector: matchLabels: app: zipkin-c version: "v1" replicas: 1 template: metadata: labels: app: zipkin-c version: "v1" spec: containers: - name: zipkin-c image: reg.xthklocal.cn/xthk-library/zipkin_c command: ["python","/tmp/c.py"] ports: - containerPort: 5002 name: http protocol: TCP --- apiVersion: v1 kind: Service metadata: name: zipkin-c spec: ports: - name: http-5000 port: 5002 protocol: TCP targetPort: 5002 selector: app: zipkin-c type: ClusterIP
istio 增加以下zipkin 配置:
data: mesh: |- defaultConfig: tracing: zipkin: address: 192.168.3.100:31377 #改成zipkin server的实际地址
进入任意能与zipkin-a 容器通信的容器调用zipkin-a 服务触发链路上报 (如果采样率未设置未全部采样,需要多次调用才能看到效果)
登录zipkin查看效果