113

为 Jaeger 安装环境搭建监控基础设施

 4 years ago
source link: https://www.tuicool.com/articles/iyu2YfU
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文最初发表于 RedHat 开发者博客 ,经原作者 Juraci Paixão Kröhling 和 RedHat 授权由 InfoQ 中文站翻译分享。

在生产环境中部署 Jaeger 时,持续观察 Jaeger 实例,保证它的行为符合预期是非常重要的。毕竟,Jaeger 停机将会意味着跟踪数据的丢失,这样的话,我们很难理解生产环境的应用中究竟出现了什么问题。

本文将会介绍如何为 Jaeger 安装环境构建监控基础设施。首先,我们会为那些急切想监控 Jaeger 的读者提供现成资源的链接。

在第二部分中,我们会深入了解如何在 Kubernetes 集群中安装所有的工具,包括 PrometheusGrafana 和 Jaeger 本身,同时还会学习如何安装所需的工具,从而基于 Jaeger 官方的监控 mixin 自定义告警规则和 dashboard。

提示:如果你已经具有 Grafana、Prometheus 和 Jaeger 组成的可运行环境的话,那么你可能只关心基础 dashboard 和告警定义在什么地方,它们的地址如下:

如果你已经熟悉 mixin 的话,Jaeger 的官方监控 mixin 就可以在 主资源仓库获取

预备条件

本指南假设你具备 Kubernetes 的 admin 访问权限。如果以测试为目的的话,有一种了解 Kubernetes 集群的简便方式,那就是在本地运行 Minikube

本指南还需要用到 jsonnetjb (jsonnet-bundler) 。它们可以借助 go get,在本地机器通过如下命令安装:

1.  $ go get github.com/google/go-jsonnet/cmd/jsonnet
2.  $ go get github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb

安装 Prometheus、Alertmanager 和 Grafana

在 Kubernetes 之上安装 Prometheus 可以通过多种方式来实现。其中一种方式是使用 kube-prometheus 项目,但是也可以直接使用 Prometheus Operator ,还可以使用 Prometheus Operator 的社区 Helm chart 。在本指南中,我们会使用 kube-prometheus 来获取 Prometheus、Alertmanager 和 Grafana 实例。

首先,我们使用 jb 生成一个基础 jsonnet 文件,该文件描述了我们的安装需求,将 kube-prometheus 作为依赖添加进来:

1.  $ jb init
2.  $ jb install \
3.   github.com/jaegertracing/jaeger/monitoring/jaeger-mixin@master \
4.   github.com/grafana/jsonnet-libs/grafana-builder@master \
5.   github.com/coreos/kube-prometheus/jsonnet/kube-prometheus@master

完成之后,我们需要有一个名为 jsonnetfile.json 的 manifest 文件,它大致如下所示:

1.  {
2.     "dependencies": [
3.         {
4.             "name": "mixin",
5.             "source": {
6.                 "git": {
7.                     "remote": "https://github.com/jpkrohling/jaeger",
8.                     "subdir": "monitoring/mixin"
9.                 }
10.             },
11.             "version": "1668-Move-Jaeger-mixing-to-main-repo"
12.         },
13.         {
14.             "name": "grafana-builder",
15.             "source": {
16.                 "git": {
17.                     "remote": "https://github.com/grafana/jsonnet-libs",
18.                     "subdir": "grafana-builder"
19.                 }
20.             },
21.             "version": "master"
22.         },
23.         {
24.             "name": "kube-prometheus",
25.             "source": {
26.                 "git": {
27.                     "remote": "https://github.com/coreos/kube-prometheus",
28.                     "subdir": "jsonnet/kube-prometheus"
29.                 }
30.             },
31.             "version": "master"
32.         }
33.     ]
34.  }

install 命令应该还会创建一个名为 vendor 的目录,其中包含了所有的 jsonnet 依赖。现在,我们所需要就是一个 deployment 描述符:创建一个名为 monitoring-setup.jsonnet 的文件,内容如下:

1.  local kp =
2.   (import 'kube-prometheus/kube-prometheus.libsonnet') +
3.   {
4.     _config+:: {
5.       namespace: 'monitoring',
6.     },
7.   };
8.  
9.  { ['00namespace-' + name + '.json']: kp.kubePrometheus[name] for name in std.objectFields(kp.kubePrometheus) } +
10.  { ['0prometheus-operator-' + name + '.json']: kp.prometheusOperator[name] for name in std.objectFields(kp.prometheusOperator) } +
11.  { ['node-exporter-' + name + '.json']: kp.nodeExporter[name] for name in std.objectFields(kp.nodeExporter) } +
12.  { ['kube-state-metrics-' + name + '.json']: kp.kubeStateMetrics[name] for name in std.objectFields(kp.kubeStateMetrics) } +
13.  { ['alertmanager-' + name + '.json']: kp.alertmanager[name] for name in std.objectFields(kp.alertmanager) } +
14.  { ['prometheus-' + name + '.json']: kp.prometheus[name] for name in std.objectFields(kp.prometheus) } +
15.  { ['prometheus-adapter-' + name + '.json']: kp.prometheusAdapter[name] for name in std.objectFields(kp.prometheusAdapter) } +
16.  { ['grafana-' + name + '.json']: kp.grafana[name] for name in std.objectFields(kp.grafana) }

这样,我们就能生成所需的 deployment manifest,并应用它们:

1.  $ jsonnet -J vendor -cm manifests/ monitoring-setup.jsonnet
2.  $ kubectl apply -f manifests/

第一次使用的时候,自定义资源定义(Custom Resource Definition,CRD)可能尚未就绪,这会导致如下的信息:

1.  no matches for kind "ServiceMonitor" in version "monitoring.coreos.com/v1"

如果出现这种情况的话,只需要再次应用一下这些 manifest 即可,因为它们是幂等的。

几分钟之后,我们应该就会有几个可用的 _Deployment_ 和 _Statefulset_ 资源了:

1.  $ kubectl get deployments -n monitoring 
2.  NAME                  READY     UP-TO-DATE   AVAILABLE   AGE
3.  grafana               1/1       1            1           56s
4.  kube-state-metrics    1/1       1            1           56s
5.  prometheus-adapter    1/1       1            1           56s
6.  prometheus-operator   1/1       1            1           57s
7.  
8.  $ kubectl get statefulsets -n monitoring
9.  NAME                READY     AGE
10.  alertmanager-main   3/3       60s
11.  prometheus-k8s      2/2       50s

我们可以直接连接服务的端口,检查一下 Prometheus 是否已经启动:

1.  $ kubectl port-forward -n monitoring service/prometheus-k8s 9090:9090
2.  $ firefox http://localhost:9090

对 Grafana 执行相同的检查,默认凭证的用户名和密码都是 _admin_:

1.  $ kubectl port-forward -n monitoring service/grafana 3000:3000`
2.  `$ firefox http://localhost:3000`

安装 Jaeger

Jaeger Operator 默认会安装到“observability”命名空间中。在本指南中,我们会将它放到“monitoring”命名空间中,与 Prometheus 和 Grafana 放到一起。为了实现这一点,我们需要通过 curl 获取 manifest,并将“observability”替换为“monitoring”,然后将输出提供给 kubectl:

1.  $ kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/crds/jaegertracing_v1_jaeger_crd.yaml
2.  $ curl -s https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/service_account.yaml | sed 's/observability/monitoring/gi' | kubectl apply -f -
3.  $ curl -s https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/role.yaml | sed 's/observability/monitoring/gi' | kubectl apply -f -
4.  $ curl -s https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/role_binding.yaml | sed 's/observability/monitoring/gi' | kubectl apply -f -
5.  $ curl -s https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/operator.yaml | sed 's/observability/monitoring/gi' | kubectl apply -f -

在撰写本文的时候,最新版本为 v1.13.1,所以你可以修改上述 URL 以匹配所需的版本。几分钟之后,Jaeger Operator 就能启动并运行了:

1.  $ kubectl get deployment/jaeger-operator -n monitoring
2.  NAME              READY     UP-TO-DATE   AVAILABLE   AGE
3.  jaeger-operator   1/1       1            1           23s

Jaeger Operator 准备就绪之后,我们就可以创建名为 tracing 的 Jaeger 实例了:

1.  kubectl apply -f - <
<eof 2="" piversion:="" jaegertracing="" io="" v1="" 3="" ind:="" jaeger="" 4="" etadata:="" 5="" ame:="" tracing="" 6="" amespace:="" monitoring="" 7="" of="">
 <="" pre="">

 <p>稍等片刻,Jaeger 实例就会准备就绪:</p>

 <pre data-anchor-id="d5es">1.  $ kubectl get deployment/tracing -n monitoring 
2.  NAME      READY     UP-TO-DATE   AVAILABLE   AGE
3.  tracing   1/1       1            1           17s
4.  
5.  $ kubectl get ingress -n monitoring 
6.  NAME            HOSTS     ADDRESS           PORTS     AGE
7.  tracing-query   \*         192.168.122.181   80        26s
</pre>

 <p>我们可以在 Web 浏览器中通过给定的 IP 地址访问 Jaeger UI。在本例中,也就是 http://192.168.122.181/,但是你的 IP 可能会有所不同。</p>

 <p>现在,所有的内容都运行起来了,接下来我们安装业务应用,并通过 instrument 操作让它为接收到的每个请求都创建 span:</p>

 <pre data-anchor-id="yd5l">1.  $ kubectl apply -n default -f https://raw.githubusercontent.com/jaegertracing/jaeger-operator/v1.13.1/deploy/examples/business-application-injected-sidecar.yaml
</pre>

 <p>部署完成之后,我们可以直接打开一个到 Pod 的连接并向其发送请求:</p>

 <pre data-anchor-id="p0vw">1.  $ kubectl get -n default deployment/myapp 
2.  NAME      READY     UP-TO-DATE   AVAILABLE   AGE
3.  myapp     1/1       1            1           26s
4.  
5.  $ kubectl port-forward deployment/myapp 8080:8080
6.  $ watch -n 0.5 curl localhost:8080
</pre>

 <p>这样每秒钟会生成两个 HTTP 请求,在 Jaeger UI 中,我们应该会看到每个 HTTP 请求都会有一个 trace。</p>

 <h2>创建 PodMonitor</h2>

 <p>现在,我们已经有了一组功能齐全的监控服务:Prometheus、Grafana、Alertmanager 和 Jaeger。但是,Jaeger deployment 所生成的指标并没有被 Prometheus 所捕获:我们需要创建一个 ServiceMonitor 或 PodMonitor,以便于告诉 Prometheus 到哪里获取数据。</p>

 <p>根据组件的不同,指标会由不同的端口来提供:</p>

 <table>

  <thead>

   <tr>

    <th>组件</th>

    <th>端口</th>

   </tr>

  </thead>

  <tbody>

   <tr>

    <td>Agent</td>

    <td>14271</td>

   </tr>

   <tr>

    <td>Collector</td>

    <td>14269</td>

   </tr>

   <tr>

    <td>Query</td>

    <td>16687</td>

   </tr>

   <tr>

    <td>All in one</td>

    <td>14269</td>

   </tr>

  </tbody>

 </table>

 <p>我们所创建的 Jaeger 实例并没有指定<a href="https://www.jaegertracing.io/docs/1.13/operator/#deployment-strategies" rel="noopener nofollow" target="_blank"> strategy </a>,所以将会使用默认的 strategy,即 allInOne。我们的 PodMonitor 要告诉 Prometheus 从 14269 端口获取指标:</p>

 <pre data-anchor-id="hu4l">1.  $ kubectl apply -f - <
  <eof 2="" piversion:="" monitoring="" coreos="" com="" v1="" 3="" ind:="" podmonitor="" 4="" etadata:="" 5="" ame:="" tracing="" 6="" amespace:="" 7="" pec:="" 8="" odmetricsendpoints:="" 9="" nterval:="" 5s="" 10="" argetport:="" 14269="" 11="" elector:="" 12="" atchlabels:="" 13="" pp:="" jaeger="" 14="" of="">
   <="" pre="">

   <p>Prometheus 可能需要花费几分钟的时间才能找到这个新的 target。进入 Targets 页面,查找 monitoring/tracing/0 这个 target。Prometheus 捕获到 Jaeger 的指标端点之后,我们就可以在 Prometheus Graph 视图中看到 Jaeger 的指标了。例如,进入 jaeger_collector_traces_saved_by_svc_total 并点击 Execute。图中显示的 trace 数量应该随着时间的推移而增加,它反映了前面步骤中针对业务应用程序运行的 HTTP 请求的数量。</p>

   <p><img src="https://static001.infoq.cn/resource/image/68/45/6887090b622a69218cf3d5228d022945.png" alt="" /></p>

   <h2>适配 mixin</h2>

   <p>现在,我们已经在 Prometheus 中获得了来自 Jaeger 实例的指标数据,但是应该在 dashboard 上显示哪些指标,在什么情况下应该生成哪些告警呢?</p>

   <p>很难找到一个通用的、适合所有情况的答案来回答这些问题,但是我们在 Grafana 实验室的朋友们为 Jaeger 设计了一个 mixin,它可以作为你自己的 dashboard 和告警的一个起点。此后,该 mixin 贡献了给 Jaeger 项目,并且可以在主存储库下访问。</p>

   <p>让我们回到最初的 monitoring-setup.jsonnet,并添加 Jaeger 特定的 dashboard 和告警规则:</p>

   <pre data-anchor-id="r853">1.  local jaegerAlerts = (import 'jaeger-mixin/alerts.libsonnet').prometheusAlerts;
2.  local jaegerDashboard = (import 'jaeger-mixin/mixin.libsonnet').grafanaDashboards;
3.  
4.  local kp =
5.   (import 'kube-prometheus/kube-prometheus.libsonnet') +
6.   {
7.     _config+:: {
8.       namespace: 'monitoring',
9.     },
10.     grafanaDashboards+:: {
11.       'jaeger.json': jaegerDashboard['jaeger.json'],
12.     },
13.     prometheusAlerts+:: jaegerAlerts,
14.   };
15.  
16.  { ['00namespace-' + name + '.json']: kp.kubePrometheus[name] for name in std.objectFields(kp.kubePrometheus) } +
17.  { ['0prometheus-operator-' + name + '.json']: kp.prometheusOperator[name] for name in std.objectFields(kp.prometheusOperator) } +
18.  { ['node-exporter-' + name + '.json']: kp.nodeExporter[name] for name in std.objectFields(kp.nodeExporter) } +
19.  { ['kube-state-metrics-' + name + '.json']: kp.kubeStateMetrics[name] for name in std.objectFields(kp.kubeStateMetrics) } +
20.  { ['alertmanager-' + name + '.json']: kp.alertmanager[name] for name in std.objectFields(kp.alertmanager) } +
21.  { ['prometheus-' + name + '.json']: kp.prometheus[name] for name in std.objectFields(kp.prometheus) } +
22.  { ['prometheus-adapter-' + name + '.json']: kp.prometheusAdapter[name] for name in std.objectFields(kp.prometheusAdapter) } +
23.  { ['grafana-' + name + '.json']: kp.grafana[name] for name in std.objectFields(kp.grafana) }
</pre>

   <p>接下来,生成新的 manifest:</p>

   <p>$ jsonnet -J vendor -cm manifests/ monitoring-setup.jsonnet</p>

   <p>这里只会改变几个 manifest,但是我们可以安全地再次应用所有的 manifest:</p>

   <pre data-anchor-id="431k">1.  $ kubectl apply -f manifests/
</pre>

   <p>稍等片刻之后,将会有一个新的 Grafana pod 替代之前的:</p>

   <pre data-anchor-id="rfe7">1.  $ kubectl get pods -n monitoring -l app=grafana
2.  NAME                       READY     STATUS    RESTARTS   AGE
3.  grafana-558647b59-fkmr4    1/1       Running   0          11m
4.  grafana-7bcb7f5b9b-6rv2w   0/1       Pending   0          8s
</pre>

   <p><strong>注意</strong>:当使用 Minikube 时,新 pod 可能会由于 Insufficient cpu 而处于 Pending 状态。我们可以通过运行 kubectl describe -n monitoring pod POD_NAME 来检查原因,并使用 kubectl delete -n monitoring pod POD_NAME 手动删除旧的 pod,或者使用标记–cpus 以更高的值来启动 minikube。</p>

   <p>新的 Grafana pod 启动并运行之后,我们应该会看到 Grafana 有一个新的 Jaeger 仪表板,显示 Prometheus 提供的数据。类似地,Prometheus 中也会有一个新的告警规则:查找名称中带有“Jaeger”的规则,比如 JaegerCollectorQueueNotDraining:</p>

   <p><img src="https://static001.infoq.cn/resource/image/bc/d9/bc859d730c68e2e04e399a0a73e179d9.png" alt="" /></p>

   <h2>总结</h2>

   <p>在云原生微服务领域中,部署可观察性工具为业务应用程序提供洞察能力是必备的,另外,监视这些工具本身的行为也是必要的。本文展示了在 Kubernetes 中搭建完整技术栈并运行起来的一种方法,最终目标是使用 Jaeger 自己的内部指标来监视 Jaeger。相同的方式可以扩展至让 Prometheus 获取业务应用的指标,并以 Grafana 作为 dashboard 工具来对数据进行可视化。</p>

  </eof></pre>
</eof>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK