Istio 通过整合很多开源工具,如 Kiali、Grafana、Prometheus、 Jaeger,来完成对微服务应用的监控和调式。这些工具开箱即用,Istio 默认安装,且完成了配置。

1.1 使用 Kiali 观测微服务

由于微服务之间的调用关系错综复杂,排查问题就更加困难了,为了使服务之间的关系更加清晰明了,了解应用的行为和状态,我们有必要使用一些可视化的方案来观测我们的微服务应用,其中 Kiali 就是这样的一个工具。

Kiali 是 Istio 的一个可观测工具,提供服务拓扑展示服务网格的结构,提供网格的健康状态视图,配置信息验证功能,此外还具有服务网格配置的功能。

默认情况下,Kiali 服务已经安装了,可以通过 istioctl 命令来访问,比如我们可以使用如下命令来打开 kiali 的 web UI (Kiali Service 类型未修改),然后就可以通过 44759 端口访问到 kiali 服务了:

  1. $ istioctl dashboard kiali --address=0.0.0.0
  2. http://localhost:44759/kiali

也可以通过修改 Kiali 的服务为 NodePort 类型来访问。

默认的用户名和密码存储在名为 kiali 的 Secret 对象之中,需要将其中的 username 与 passphrase 做 base64 解码获得用户名和密码(admin/admin):

  1. $ kubectl get secret -n istio-system kiali -o yaml
  2. apiVersion: v1
  3. data:
  4. passphrase: YWRtaW4=
  5. username: YWRtaW4=
  6. kind: Secret
  7. ......

Kiali 服务能为我们做什么:

(1) 可以在 Graph 页面下面查看微服务应用的整个调用链:

image.png

(2) 在 Istio Config 模块下面可以查看整个网格中的配置校验情况:

红色标记的表示验证未通过的配置,可以点击进去编辑错误的配置。
image.png

(3) 在 Istio Config 模块下创建 Istio 资源配置:

image.png

1.2 使用 Jaeger 进行分布式追踪

(1) 启用 Jaeger 追踪服务

这里安装 Istio 的时候使用的是 demo 这个 profile:

  • 默认情况下已经安装了 Jaeger,查看:

    1. $ kubectl get pods -l app=jaeger -n istio-system
    2. NAME READY STATUS RESTARTS AGE
    3. istio-tracing-8584b4d7f9-vmcdx 1/1 Running 0 40d
    4. $ kubectl get svc -l app=jaeger -n istio-system
    5. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    6. jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 40d
    7. jaeger-collector ClusterIP 10.97.9.74 <none> 14267/TCP,14268/TCP,14250/TCP 40d
    8. jaeger-collector-headless ClusterIP None <none> 14250/TCP 40d
    9. jaeger-query ClusterIP 10.105.127.27 <none> 16686/TCP 40d
    10. tracing ClusterIP 10.101.132.125 <none> 80/TCP 40d
    11. zipkin ClusterIP 10.108.118.19 <none> 9411/TCP 40d
  • 如果没有安装可以在使用 istioctl 命令初始化的时候添加 --set values.tracing.enabled=true 参数进行开启:

    1. $ istioctl manifest apply --set values.tracing.enabled=true
  • 也可以使用命令将集群中现有的 Jaeger 服务关联到 Istio:

    1. $ istioctl manifest apply --set values.global.tracer.zipkin.address=<jaeger-collector-service>.<jaeger-collector-namespace>:9411

(2) 访问 Jaeger 的 Dashboard

通过 tracing 这个 Service 来访问 Jaeger 的 Dashboard 页面,同样为了方便测试将其修改为 NodePort 类型:

  1. $ kubectl edit svc tracing -n istio-system
  2. ......
  3. spec:
  4. type: NodePort
  5. ......
  6. service/tracing edited
  7. $ kubectl get svc tracing -n istio-system
  8. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  9. tracing NodePort 10.101.132.125 <none> 80:31755/TCP 40d

修改完成后就可以在浏览器中通过 http://<NodeIP>:31755 访问 Jaeger 的 Dashboard 页面了:
学习 Istio 的 Observability 特性 - 图4

(3) 测试 Jaeger 的流量追踪功能

通过访问 BookInfo 应用来产生流量,在 Jaeger 的 Dashboard 中测试这个请求生成的追踪数据。

  • 在左侧 Servcie 区域选择一个我们要追踪的服务,比如 details.default,点击 “Find Traces” 按钮查看追踪结果:学习 Istio 的 Observability 特性 - 图5
  • 点击列表项目还可以查看追踪详细信息,记录了一次请求涉及到的 Services、深度、Span 总数、请求总时长等信息,也可以对下方的单项服务展开,观察每一个服务的请求耗时和详情:

学习 Istio 的 Observability 特性 - 图6

  • 还可以切换 Trace 的显示方式为 Graph,在右上角点击 Trace Timeline 切换为 Trace Graph 模式,该模式下可以更加清晰查看到每一个调用详细信息:

学习 Istio 的 Observability 特性 - 图7

  • Jaeger 还可以展示服务依赖,点击顶部的 Dependencies 菜单查看,该页面可以查看服务的完整依赖调用关系:

学习 Istio 的 Observability 特性 - 图8

  • 还可以对比两个 Trace,在顶部 Compare 菜单中,输入两个不同的 Trace ID 即可进行对比,这可以帮助我们发现不同 Trace 之间的差异:

学习 Istio 的 Observability 特性 - 图9

:::info 注意:Istio 默认提供的 Jaeger 采用内存的存储方式,Pod 被销毁后数据也就丢失了。在生产环境中需要单独配置持久化存储数据库,具体可查看 Jaeger 官方文档。 :::

1.3 查看 Envoy 日志进行 Debug 分析

Istio 借助 Envoy 可以监测到网格内的服务通信的流转情况,同时我们也可以通过访问 Envoy 的日志来进行调试分析。

Envoy 代理会打印访问日志信息到标准输出,然后我们就可以通过 kubectl logs 命令打印出来查看了。

(1) 启动 Envoy 日志

默认情况下 Istio 已经开启了 Envoy 访问日志。

(2) 修改 Envoy 日志格式

可以通过 Istio 的 ConfigMap 配置来修改日志的格式:

  • 默认情况下日志就是输出到 stdout 上的 TEXT 文本格式,为了方便显示,这里我们将其设置为 JSON 格式;
  • 如果要想修改访问日志的格式可以设置 accessLogFormat 属性,具体的访问日志格式可以查看 Envoy 官方文档了解配置规则。

    1. $ kubectl edit cm istio -n istio-system
    2. apiVersion: v1
    3. data:
    4. mesh: |-
    5. accessLogEncoding: JSON
    6. accessLogFile: /dev/stdout
    7. accessLogFormat: ""
    8. outboundTrafficPolicy:
    9. mode: REGISTRY_ONLY
    10. defaultConfig:
    11. ......

    学习 Istio 的 Observability 特性 - 图10

    (3) 测试

  • 访问 BookInfo 服务,同时来查看 productpage 的 sidecar 日志:

    • 收到3条 JSON 格式的日志,productpage 服务会调用 details 与 reviews 服务,所以我们可以看到一条访问 /reviews/0 与 /details/0 的 outbound 请求,和最终的 /productpage 的 inbound 请求记录。 ```shell $ kubectl get pods -l app=productpage NAME READY STATUS RESTARTS AGE productpage-v1-5f96867467-nsclh 2/2 Running 0 8d

$ kubectl logs -f productpage-v1-5f96867467-nsclh -c istio-proxy {“useragent”:”Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36”,”response_code”:”200”,”response_flags”:”-“,”start_time”:”2020-07-19T06:48:44.074Z”,”method”:”GET”,”request_id”:”6df02877-0e8d-99f4-a9ee-0f9479d648dd”,”upstream_host”:”10.244.8.180:9080”,”x_forwarded_for”:”-“,”requested_server_name”:”-“,”bytes_received”:”0”,”istio_policy_status”:”-“,”bytes_sent”:”178”,”upstream_cluster”:”outbound|9080||details.default.svc.cluster.local”,”downstream_remote_address”:”10.244.8.227:47244”,”authority”:”details:9080”,”path”:”/details/0”,”protocol”:”HTTP/1.1”,”upstream_service_time”:”17”,”upstream_local_address”:”10.244.8.227:42248”,”duration”:”18”,”upstream_transport_failure_reason”:”-“,”route_name”:”default”,”downstream_local_address”:”10.109.179.166:9080”} {“user_agent”:”Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36”,”response_code”:”200”,”response_flags”:”-“,”start_time”:”2020-07-19T06:48:44.104Z”,”method”:”GET”,”request_id”:”6df02877-0e8d-99f4-a9ee-0f9479d648dd”,”upstream_host”:”10.244.8.182:9080”,”x_forwarded_for”:”-“,”requested_server_name”:”-“,”bytes_received”:”0”,”istio_policy_status”:”-“,”bytes_sent”:”295”,”upstream_cluster”:”outbound|9080||reviews.default.svc.cluster.local”,”downstream_remote_address”:”10.244.8.227:36718”,”authority”:”reviews:9080”,”path”:”/reviews/0”,”protocol”:”HTTP/1.1”,”upstream_service_time”:”20”,”upstream_local_address”:”10.244.8.227:42884”,”duration”:”21”,”upstream_transport_failure_reason”:”-“,”route_name”:”default”,”downstream_local_address”:”10.99.31.144:9080”} {“bytes_sent”:”4183”,”upstream_cluster”:”inbound|9080|http|productpage.default.svc.cluster.local”,”downstream_remote_address”:”10.244.0.0:0”,”authority”:”k8s.qikqiak.com:32193”,”path”:”/productpage”,”protocol”:”HTTP/1.1”,”upstream_service_time”:”70”,”upstream_local_address”:”127.0.0.1:36436”,”duration”:”71”,”upstream_transport_failure_reason”:”-“,”route_name”:”default”,”downstream_local_address”:”10.244.8.227:9080”,”user_agent”:”Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36”,”response_code”:”200”,”response_flags”:”-“,”start_time”:”2020-07-19T06:48:44.061Z”,”method”:”GET”,”request_id”:”6df02877-0e8d-99f4-a9ee-0f9479d648dd”,”upstream_host”:”127.0.0.1:9080”,”x_forwarded_for”:”10.244.0.0”,”requested_server_name”:”outbound.9080..productpage.default.svc.cluster.local”,”bytes_received”:”0”,”istio_policy_status”:”-“}

  1. :::info
  2. 这里我们查询的容器名 `istio-proxy` 其实就是 `Envoy sidecar` 代理,Envoy 将请求和响应日志都进行了打印并输出至 stdout ,所以可以通过 kubectl logs 查询。
  3. :::
  4. <a name="tfKIp"></a>
  5. #### (4) 分析日志
  6. - 为了方便查看,这里我们将第一条日志进行格式化,如下所示:
  7. ![](https://cdn.nlark.com/yuque/0/2021/png/1471554/1623739545405-66c0c2a0-de42-40db-9667-258135736ab7.png#clientId=u3861bdd5-8274-4&from=paste&id=ua6c49bcc&margin=%5Bobject%20Object%5D&originHeight=1080&originWidth=1416&originalType=url&ratio=2&status=done&style=shadow&taskId=ue4159f88-ef36-43e9-80b8-0255a192ccc)
  8. - Envoy 流量模型中重要的几个信息:
  9. - DownStream:请求的发起端;
  10. - downstream_local_address
  11. - downstream_remote_address
  12. - UpStream:请求的接收端;
  13. - upstream_cluster:符合条件的转发目的主机的集合;
  14. - upstream_host:从 upstream_cluster 集合中选择一个 host 作为流量转发的接收端点;
  15. - upstream_local_address
  16. - request_id:用于链路追踪,可以将一条请求在不同的服务中的调用串联起来;
  17. - response_flags:查看当前请求的状态,用于调试请求的时候非常有用:
  18. - UHupstream cluster 中没有健康的 host503
  19. - UFupstream 连接失败,503
  20. - UOupstream overflow(熔断);
  21. - NR:没有路由配置,404
  22. - URX:请求被拒绝因为限流或最大连接次数;
  23. :::info
  24. **注意:**
  25. - Pod 被销毁后,旧的日志将不复存在,也无法通过 kubectl logs 就行查看了。
  26. - 如果要查看历史的的日志数据,我们可以使用 EFK 方案将日志进行收集
  27. :::
  28. <a name="RHB3O"></a>
  29. ### 1.4 使用 Prometheus 收集监控指标
  30. 默认情况下 Istio 就部署了用于收集监控指标的 Prometheus 应用:
  31. ```shell
  32. $ kubectl get pods -n istio-system -l app=prometheus
  33. NAME READY STATUS RESTARTS AGE
  34. prometheus-6dd77d88cf-nmsl7 2/2 Running 0 32d
  35. $ kubectl get svc -n istio-system -l app=prometheus
  36. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  37. prometheus ClusterIP 10.98.118.202 <none> 9090/TCP 32d

为了测试方便我们可以将 Prometheus 的 Service 更改为 NodePort 类型:

  1. $ kubectl edit svc prometheus -n istio-system
  2. ......
  3. spec:
  4. type: NodePort
  5. ......
  6. $ kubectl get svc -n istio-system -l app=prometheus
  7. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  8. prometheus NodePort 10.98.118.202 <none> 9090:31128/TCP 32d

然后我们就可以通过 http://<NodeIP>:31128 访问 Prometheus 页面,默认情况下就已经有了很多抓取任务了:
学习 Istio 的 Observability 特性 - 图11
默认就已经收集了很多网格的指标,包括服务级别和代理级别(sidecar)的数据,自 Istio 1.5 起,Istio 标准指标由 Envoy 代理直接获取,之前是通过 Mixer 组件生成的。

1.5 使用 Grafana 可视化系统监控

Istio 网格中默认通过 Prometheus 收集了很多服务和代理相关的指标数据,此外 Istio 还默认开启了 Grafana 工具,我们可以通过 Grafana 来可视化查看网格的监控状态。

  1. $ kubectl get pods -n istio-system -l app=grafana
  2. NAME READY STATUS RESTARTS AGE
  3. grafana-74dc798895-mns2v 1/1 Running 0 32d
  4. $ kubectl get svc -n istio-system -l app=grafana
  5. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  6. grafana ClusterIP 10.96.52.254 <none> 3000/TCP 32d

同样我们这里将 grafana 的 Service 对象修改为 NodePort 类型的服务:

  1. $ kubectl edit svc grafana -n istio-system
  2. ......
  3. spec:
  4. type: NodePort
  5. ......
  6. $ kubectl get svc -n istio-system -l app=grafana
  7. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  8. grafana NodePort 10.96.52.254 <none> 3000:30692/TCP 32d

然后就可以通过 http://<NodeIP>:30692 访问 Grafana 应用了:
学习 Istio 的 Observability 特性 - 图12
默认情况下 Grafana 中就已经导入了 Istio 的几个 Dashboard:

  • Mesh Dashboard:主要是查看应用的数据,包括网格数据总览、服务视图、工作负载视图等
  • Performance Dashboard:主要是用于查看 Istio 本身的监控数据。

学习 Istio 的 Observability 特性 - 图13