跳转至

第七节 使用 Istio Dashboard

Jaeger (https://github.com/jaegertracing/jaeger)是一个用于分布式跟踪的开源软件。

微服务之间的调用关系往往比较复杂,在深度和广度方面都会有较长的调用路线,因此需要有跨服务的跟踪能力。

Istio中提供了Jaeger作为分布式跟踪组件。

Jaeger也是CNCF的成员,是一 个分布式跟踪工具,提供了原生的OpenTracing支持,向下兼容ZipKin,同时支持多种存储后端。

简单说明在Istio中如何查看调用链路,以及如何让网格中的应用支持分布

需要注念的是IstioSidecar为网格中的应用提供调用环节的数据,要支持整条链路, 还需要根据OpenTracing规范对应用进行改写

1、 启用Jaeger

Jager默认兄不启用的

因此需要使用启用Grafana的类似方式,设置tracing.enabledTrue

$ helm init
$HELM_HOME has been configured at /Users/i515190/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation

$ helm version
Client: &version.Version{SemVer:"v2.14.2", GitCommit:"a8b13cc5ab6a7dbef0a58f5061bcc7c0c61598e7", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.2", GitCommit:"a8b13cc5ab6a7dbef0a58f5061bcc7c0c61598e7", GitTreeState:"clean"}
$ cd Istio/istio-1.1.16/install/kubernetes/helm/istio

$ helm template istio --name istio --set tracing.enabled=true --namespace istio-system > default-tracing.yaml 


$ grep -C 2 "enableTracing" default-tracing.yaml 
    disablePolicyChecks: true

    # Set enableTracing to false to disable request tracing.
    enableTracing: true

    # Set accessLogFile to empty string to disable access log.

$ kubectl apply -f default-tracing.yaml 

$ kubectl get pod -n istio-system 
...
istio-tracing-555cf644d-h9hr9              1/1     Running     1          3d21
...

可以看到,该服务的Pod已经开始运行

2、 访问Jaeger

同样可以使用端口

kubectl -n istio-system get pod -l app=jaeger -o custom-columns='Name:metadata.name'
Name
istio-tracing-555cf644d-h9hr9 
$ kubectl -n istio-system port-forward istio-tracing-555cf644d-h9hr9  16686:16686

接下来既可以访问http://127.0.0.1:16686,来查看jaeger的界面, 其初始界面如图所示

Alt Image Text

可以看到Jaeger刚刚启动, service既列表中的数里是O。这同样是工作负载没有运行没有产生跟踪的数据导致

可以进人sleep Pod使用之前的方法来生成负载

$ kubectl exec -it sleep-6c9c898f6c-gvqng -c sleep bash

bash-4.4# for i in 'seq 100';do http --body http://flaskapp/env/version; done

Alt Image Text

Alt Image Text

3、跟踪参数的传递

前面是一个简单的跟踪活动包含一个服务端和一个客户端。

如果让们flaskapp再次获取另一个服务的内容则会发生什么呢,我们再引人一个httpbin服务来试试

首先启动这个服务并等待成功运行

$ cd Istio/istio-1.1.16/samples/httpbin
$ kubectl apply -f httpbin.yaml
service/httpbin created
deployment.extensions/httpbin created
$ kubectl get pods | grep httpbin
httpbin-7d9d5b55b9-kzt5k       2/2     Running   0          9m36s

接下来在sleep服务的Pod发起请求,要求flaskapp调用httpbin服务的/get 路径, 并返回httpbin给出响应, 同时要显示sleep发出的请求Header的内容

/# http --debug http://flaskapp/fetch_with_header?url=http://httpbin:8000/get 

此时会发现, httpie客户端发出的请求Header的原始内容为

requests.request(**{
    "allow_redirects": false,
    "auth": "None",
    "cert": "None",
    "data": {},
    "files": {},
    "headers": {
        "User-Agent": "HTTPie/0.9.9"
    },
    "method": "get",
    "params": {},
    "proxies": {},
    "stream": true,
    "timeout": 30,
    "url": "http://flaskapp/fetch_with_header?url=http://httpbin:8000/get",

flaskapp收到的请求要比Header的内容复杂的多

{"Content-Length": "0", 
 "Host": "flaskapp", 
 "User-Agent": "HTTPie/0.9.9", 
 "Accept-Encoding": "gzip, deflate", 
 "Accept": "*/*", 
 "X-Forwarded-Proto": "http", 
 "X-Request-Id": "999b9783-0b10-4140-8226-62ae1f5b15fd", 
 "X-Envoy-Decorator-Operation": "flaskapp.default.svc.cluster.local:80/*", 
 "X-Istio-Attributes": "...."
 "X-B3-Traceid": "efbd625ec2a1de04df63cf6195b6646f", 
 "X-B3-Spanid": "df63cf6195b6646f", 
 "X-B3-Sampled": "0"}

"X-Envoy-Decorator-Operation": "flaskapp.default.svc.cluster.local:80/*"

不难看出, 多出了一系列的X-*的请求Header, 应该是Envoy代理对该请求进行了修改其中就包含分布式跟踪所需要的Request ID等请求Header

同时, 在经过多次访问后,如果回到Japerweb界面,就会发现sleep应用的跟踪记录非常少

Alt Image Text

我们当然希望看到sleep->flaskapp->httpbin的完整跟踪信息,

但是OpenTracing所依赖Header没有传递, 因此jager无法确定调用之间的关系, 只会有sleep->flaskflaskapp->httbin两端鼓励的跟踪信息

要把孤立的跟踪信息融合起来,原则上比较简单:对于中间服务收到的请求, 在进行下一级请求时,将其中用于跟踪的Header传递下去就可以了。

简单来说,如果在请求中存在如下Header,就需要进行转发:

  • x-request-id
  • x-b3-traceid
  • x-b3-spanid
  • x-b3-parentspanid
  • x-b3-sampled
  • x-b3-flags
  • x-ot-span-context

因此,我们给flaskappPython。代码加人一点新东西,来传递这些内容:

...
TRACE_HEADERS = [
    'x-request-id',
    'x-b3-traceid',
    'x-b3-spanid',
    'x-b3-parentspanid',
    'x-b3-sampled',
    'x-b3-flags',
    'x-ot-span-context'
]
...
    req = Request(url, headers = new_header)
    res = urlopen(req).read()
...

我们新建了一个URL路径“fetch_with_trace",在flaskapp的代码中加人了、 Header的识别,一旦在接受的请求中包含特定的Header,就将其保存下来,并在下一次请求中发送出去。

下面就用这个新方法来测试一下,看看用新方法完成的调用是否会在Jaeger中展示完整的跟踪信息:

for i in 'seq 100';do http --debug http://flaskapp/fetch_with_trace?url=http://httpbin:8000/ip;done

Alt Image Text

单击进入查看详细记录

Alt Image Text

这样就可以清楚地看到sleep的调用先后引发了flaskapphttpbin的跟踪记录链路变得完整了

Alt Image Text

flaskapp中还提供了一个URL:"/fetch_with_header"。利用这一方法,可以看到Header在这个过程中发生的变化

我们可以在sleep容器中测试这个方法:

...
"X-Request-Id": "b4706d04-b01a-4b46-a8a6-49969fd69412",
"X-Envoy-Decorator-Operation": "flaskapp.default.svc.cluster.local:80/*", "X-Istio-Attributes": "..", 
"X-B3-Traceid": "bf6812da453a130b41700b913f6cd354", 
"X-B3-Spanid": "41700b913f6cd354",
"X-B3-Sampled": "0"
...
"X-B3-Parentspanid": "c47b04e9488308e5",
"X-B3-Sampled": "0"
"X-B3-Spanid": "037db9a260a2ede6",
"X-B3-Traceid": "bf6812da453a130b41700b913f6cd354"
"origin": "127.0.0.1",
"url": "http://httpbin:8000/get"

在输出内容中会包含两组HTTP Header

  • 第1组来自flaskapp,表示sleep->flaskapp的请求内容;
  • 第2组来自httpbin,表示flaskapp->httpbin的内容

不难发现 :

  • 我们指定的Header在两段路径中重复出现;
  • X-Request-IdX-B3-Traceid是直接下发的,两个服务收到的内容是一致的;
  • httpbin收到的跟踪信息件,X-B3-Parentspanid就等同于flaskapp发出 X-B3-Spanid,这表明了父子关系。

4、开放Jaeger服务

GrafanaPrometheus一样,Jaeger同样可以通过修改服务类型等方式将服务公开到网格外部;不同的是,Jaeger还直接在Chart中提供了Ingress的设置方式。

如果己经在Kubernetes集群中部署了Ingress Controller,可以在values.yaml中直接设置:

ingress:
    enabled: false
    # Used to create an Ingress record.
    hosts:
      - jaeger.local
    annotations:
      # kubernetes.io/ingress.class: nginx
      # kubernetes.io/tls-acme: "true"
    tls:
      # Secrets must be manually created in the namespace.
      # - secretName: chart-example-tls
      #   hosts:
      #     - chart-example.local

helm template命令会为这些设置生成Ingress资源从而完成Jaeger服务的开放