<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>prometheus | 伪架构师</title>
    <link>/tags/prometheus/</link>
      <atom:link href="/tags/prometheus/index.xml" rel="self" type="application/rss+xml" />
    <description>prometheus</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Sat, 06 Aug 2022 21:53:29 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>prometheus</title>
      <link>/tags/prometheus/</link>
    </image>
    
    <item>
      <title>在 Istio 中合并监控指标</title>
      <link>/post/merge-metrics-in-istio/</link>
      <pubDate>Sat, 06 Aug 2022 21:53:29 +0800</pubDate>
      <guid>/post/merge-metrics-in-istio/</guid>
      <description>&lt;p&gt;前些天阅读 Istio 文档的时候发现个语焉不详的东西：&lt;a href=&#34;https://istio.io/latest/docs/ops/integrations/prometheus/#option-1-metrics-merging&#34; target=&#34;_blank&#34;&gt;Metrics Merging&lt;/a&gt;，原文如下：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This option is enabled by default but can be disabled by passing &amp;ndash;set meshConfig.enablePrometheusMerge=false during installation. When enabled, appropriate prometheus.io annotations will be added to all data plane pods to set up scraping. If these annotations already exist, they will be overwritten. With this option, the Envoy sidecar will merge Istio’s metrics with the application metrics. The merged metrics will be scraped from /stats/prometheus:15020.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;大致翻译一下：这是一个缺省开放的功能，可以在安装时用 &lt;code&gt;--set meshConfig.enablePrometheusMerge=false&lt;/code&gt; 参数停用这个功能。这个功能启用后，相对应的 &lt;code&gt;prometheus.io&lt;/code&gt; 注解就会被加入到所有数据面 Pod 上，以启用 Prometheus 的指标抓取能力。如果这些注解已经存在，那么就会被覆盖。有了这样的功能，Envoy Sidecar 就会把应用指标和 Istio 指标进行合并，Prometheus 可以从 &lt;code&gt;:15020/stats/prometheus&lt;/code&gt; 拉取合并后的指标。&lt;/p&gt;

&lt;p&gt;看完之后，一头雾水。翻翻代码看到另一番说辞：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;applyPrometheusMerge configures prometheus scraping annotations for the &amp;ldquo;metrics merge&amp;rdquo; feature. This moves the current prometheus.io annotations into an environment variable and replaces them pointing to the agent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这段代码实现了指标合并功能。它会把当前的 &lt;code&gt;prometheus.io&lt;/code&gt; 注解保存到环境变量之中，并且将原有注解替换为指向 Agent 的内容。&lt;/p&gt;

&lt;p&gt;再结合相关代码，大概可以推断其功能大致如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;网格化微服务在网格化之前使用 &lt;code&gt;prometheus.io&lt;/code&gt; 注解标注的抓取方法，会被保存到 Sidecar 的环境变量之中；&lt;/li&gt;
&lt;li&gt;合并指标功能，能够将被网格劫持的微服务输出的 Promethues 指标和 Sidecar 自身指标进行合并，输出到 &lt;code&gt;:15020/stats/prometheus&lt;/code&gt; 端点，供 Prometheus 拉取。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我们用 Python 的 &lt;a href=&#34;https://github.com/prometheus/client_python#custom-collectors&#34; target=&#34;_blank&#34;&gt;Prometheus Exporter SDK&lt;/a&gt; 中的测试代码做一个示例应用，并使用如下 Dockerfile 进行打包：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM python:3.9.13-slim-buster
RUN pip install prometheus-client &amp;amp;&amp;amp; mkdir app
COPY server.py /app/server.py
WORKDIR /app
EXPOSE 8000
CMD [ &amp;quot;python3&amp;quot;, &amp;quot;server.py&amp;quot; ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;使用 Docker 运行一下，可以看到他输出的简单指标：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ docker run -p 8000:8000 dustise/promclient:v0.1
Unable to find image &#39;dustise/promclient:v0.1&#39; locally
v0.1: Pulling from dustise/promclient
...
Status: Downloaded newer image for dustise/promclient:v0.1
$ curl http://127.0.0.1:8000
...
# HELP request_processing_seconds_created Time spent processing request
# TYPE request_processing_seconds_created gauge
request_processing_seconds_created 1.6597804647800276e+09
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;会看到指标中是一些请求相关和 Python 特定的内容，这正像我们一个提供了监控指标的微服务，那么如何将这些“业务”指标和 Sidecar 合并输出呢？根据上文，需要加上 Prometheus 的注解，因此我们准备这样一个 YAML：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: apps/v1
kind: Deployment
...
  template:
    metadata:
...
      annotations:
        prometheus.io/path: /
        prometheus.io/port: 8000
        prometheus.io/scrape: true
    spec:
...
---
apiVersion: v1
kind: Service
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注入 Sidecar 并提交到集群：&lt;code&gt;istioctl kube-inject -f promclient.yaml | kubectl apply -f  -&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;成功后，可以看看新 Pod 是不是发生了像文档所说的变化：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl describe po promclient-6c74596f4f-r5z29 | grep prometheus.io
              prometheus.io/path: /stats/prometheus
              prometheus.io/port: 15020
              prometheus.io/scrape: true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;看到我们原有的注解的确被替换为缺省内容，那原有内容是不是出现在环境变量之中？&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl exec -it [pod] -c istio-proxy -- env |  | grep ANNO
ISTIO_PROMETHEUS_ANNOTATIONS={&amp;quot;scrape&amp;quot;:&amp;quot;true&amp;quot;,&amp;quot;path&amp;quot;:&amp;quot;/&amp;quot;,&amp;quot;port&amp;quot;:&amp;quot;8000&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;果然出现在这里了。那么指标是否完成合并了？采集一下 Pod 的 15020 端口：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ http 10.52.1.11:15020/stats/prometheus | grep python | more
# HELP python_gc_objects_collected_total Objects collected during gc
# TYPE python_gc_objects_collected_total counter
python_gc_objects_collected_total{generation=&amp;quot;0&amp;quot;} 101.0
python_gc_objects_collected_total{generation=&amp;quot;1&amp;quot;} 273.0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，指标已经被合并到了 Sidecar 指标中之中。&lt;/p&gt;

&lt;p&gt;方法固然简单，还是存在一些不适用的场景，例如：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;用 mTLS 抓取指标&lt;/li&gt;
&lt;li&gt;应用指标和 Sidecar 指标重名&lt;/li&gt;
&lt;li&gt;Prometheus 未配置按照标准注解进行抓取&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;遇到上述问题，可能就需要关掉合并功能，采用自定义抓取的方式了。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Prometheus 和 Pod 标签</title>
      <link>/post/prometheus-and-pod-label/</link>
      <pubDate>Fri, 22 Jul 2022 09:48:06 +0800</pubDate>
      <guid>/post/prometheus-and-pod-label/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://5pi.de/2017/11/09/use-prometheus-vector-matching-to-get-kubernetes-utilization-across-any-pod-label/&#34; target=&#34;_blank&#34;&gt;Use Prometheus Vector Matching to get Kubernetes Utilization across any Pod Label&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://5pi.de/&#34; target=&#34;_blank&#34;&gt;Johannes Ziemke&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注：这里实际上涉及到两种标签，一个是 Pod 的，一个是 Metrics 的，非常容易混淆，所以会分别写成 Pod 标签和指标标签。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Prometheus 是为 Kubernetes 这样的动态环境而生的。它的服务发现能力和查询语言非常强大，Kubernetes 运维过程中，用户可以借 Prometheus 解决监控问题。&lt;/p&gt;

&lt;p&gt;相对其它竞品来说，这种弹性直接提高了 Prometheus 的使用门槛，&lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/operators/#vector-matching&#34; target=&#34;_blank&#34;&gt;向量匹配&lt;/a&gt; 就是众多拦路虎中的一个。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/operators/#vector-matching&#34; target=&#34;_blank&#34;&gt;Prometheus 文档&lt;/a&gt;中在这个主题上做了非常精彩的阐述，所以本文中不会做过多的细节阐述，而是会围绕资源使用率这个主题进行一些场景化的尝试。&lt;/p&gt;

&lt;h2 id=&#34;用标签聚合内存用量&#34;&gt;用标签聚合内存用量&lt;/h2&gt;

&lt;p&gt;Kubernetes 提供了一个 &lt;code&gt;container_memory_usage_bytes&lt;/code&gt; 指标，用于表达 Pod 的内存用量：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;...
container_memory_usage_bytes{beta_kubernetes_io_arch=&amp;quot;amd64&amp;quot;,beta_kubernetes_io_fluentd_ds_ready=&amp;quot;true&amp;quot;,beta_kubernetes_io_instance_type=&amp;quot;g1-small&amp;quot;,beta_kubernetes_io_os=&amp;quot;linux&amp;quot;,cloud_google_com_gke_nodepool=&amp;quot;small-preemptible&amp;quot;,cloud_google_com_gke_preemptible=&amp;quot;true&amp;quot;,container_name=&amp;quot;POD&amp;quot;,failure_domain_beta_kubernetes_io_region=&amp;quot;us-east1&amp;quot;,failure_domain_beta_kubernetes_io_zone=&amp;quot;us-east1-c&amp;quot;,id=&amp;quot;/kubepods/burstable/pod13d4221c-c484-11e7-bff5-42010af0018b/67e5bb069ab9881ff8a55b8628ef4935b0d1ace09c18df20db059522bdfd5b7d&amp;quot;,image=&amp;quot;gcr.io/google_containers/pause-amd64:3.0&amp;quot;,instance=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,job=&amp;quot;kubernetes-cadvisor&amp;quot;,kubernetes_io_hostname=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,name=&amp;quot;k8s_POD_latency-api-971504058-jzs5h_default_13d4221c-c484-11e7-bff5-42010af0018b_0&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod_name=&amp;quot;latency-api-971504058-jzs5h&amp;quot;}	389120
container_memory_usage_bytes{beta_kubernetes_io_arch=&amp;quot;amd64&amp;quot;,beta_kubernetes_io_fluentd_ds_ready=&amp;quot;true&amp;quot;,beta_kubernetes_io_instance_type=&amp;quot;g1-small&amp;quot;,beta_kubernetes_io_os=&amp;quot;linux&amp;quot;,cloud_google_com_gke_nodepool=&amp;quot;small-preemptible&amp;quot;,cloud_google_com_gke_preemptible=&amp;quot;true&amp;quot;,container_name=&amp;quot;POD&amp;quot;,failure_domain_beta_kubernetes_io_region=&amp;quot;us-east1&amp;quot;,failure_domain_beta_kubernetes_io_zone=&amp;quot;us-east1-c&amp;quot;,id=&amp;quot;/kubepods/burstable/pod81d0f651-c500-11e7-bff5-42010af0018b/309e05b118e618122c70ccf88538d13ca41c3b5a770d5d67882426854391c23c&amp;quot;,image=&amp;quot;gcr.io/google_containers/pause-amd64:3.0&amp;quot;,instance=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,job=&amp;quot;kubernetes-cadvisor&amp;quot;,kubernetes_io_hostname=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,name=&amp;quot;k8s_POD_latency-api-971504058-gszpw_default_81d0f651-c500-11e7-bff5-42010af0018b_0&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod_name=&amp;quot;latency-api-971504058-gszpw&amp;quot;}	372736
container_memory_usage_bytes{beta_kubernetes_io_arch=&amp;quot;amd64&amp;quot;,beta_kubernetes_io_fluentd_ds_ready=&amp;quot;true&amp;quot;,beta_kubernetes_io_instance_type=&amp;quot;g1-small&amp;quot;,beta_kubernetes_io_os=&amp;quot;linux&amp;quot;,cloud_google_com_gke_nodepool=&amp;quot;small-preemptible&amp;quot;,cloud_google_com_gke_preemptible=&amp;quot;true&amp;quot;,container_name=&amp;quot;latency-api&amp;quot;,failure_domain_beta_kubernetes_io_region=&amp;quot;us-east1&amp;quot;,failure_domain_beta_kubernetes_io_zone=&amp;quot;us-east1-c&amp;quot;,id=&amp;quot;/kubepods/burstable/pod13d4221c-c484-11e7-bff5-42010af0018b/497e6fdf2217771cb3f52e6fef93734d023f0e7f23f92c58d22139fc18dc5f13&amp;quot;,image=&amp;quot;registry.gitlab.com/latency.at/latencyat@sha256:8ea057e064b64cc9c8459a68ef3f6d0fc26169b4f57aef193831779e1fe713d4&amp;quot;,instance=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,job=&amp;quot;kubernetes-cadvisor&amp;quot;,kubernetes_io_hostname=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,name=&amp;quot;k8s_latency-api_latency-api-971504058-jzs5h_default_13d4221c-c484-11e7-bff5-42010af0018b_1&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod_name=&amp;quot;latency-api-971504058-jzs5h&amp;quot;}	11014144
container_memory_usage_bytes{beta_kubernetes_io_arch=&amp;quot;amd64&amp;quot;,beta_kubernetes_io_fluentd_ds_ready=&amp;quot;true&amp;quot;,beta_kubernetes_io_instance_type=&amp;quot;g1-small&amp;quot;,beta_kubernetes_io_os=&amp;quot;linux&amp;quot;,cloud_google_com_gke_nodepool=&amp;quot;small-preemptible&amp;quot;,cloud_google_com_gke_preemptible=&amp;quot;true&amp;quot;,container_name=&amp;quot;latency-api&amp;quot;,failure_domain_beta_kubernetes_io_region=&amp;quot;us-east1&amp;quot;,failure_domain_beta_kubernetes_io_zone=&amp;quot;us-east1-c&amp;quot;,id=&amp;quot;/kubepods/burstable/pod81d0f651-c500-11e7-bff5-42010af0018b/7b438a8e9df0cf1ab29d067fd36c97099f9f5e7e9257f6187c5be6bff846a62c&amp;quot;,image=&amp;quot;registry.gitlab.com/latency.at/latencyat@sha256:8ea057e064b64cc9c8459a68ef3f6d0fc26169b4f57aef193831779e1fe713d4&amp;quot;,instance=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,job=&amp;quot;kubernetes-cadvisor&amp;quot;,kubernetes_io_hostname=&amp;quot;gke-latency-at-small-preemptible-0c981b61-9489&amp;quot;,name=&amp;quot;k8s_latency-api_latency-api-971504058-gszpw_default_81d0f651-c500-11e7-bff5-42010af0018b_0&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod_name=&amp;quot;latency-api-971504058-gszpw&amp;quot;}	11448320
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;但是很不幸，这其中并不包含 Pod 标签。还好，&lt;a href=&#34;https://github.com/kubernetes/kube-state-metrics&#34; target=&#34;_blank&#34;&gt;kube-state-metrics&lt;/a&gt; 提供了一个 &lt;code&gt;kube_pod_labels&lt;/code&gt; 指标，这个指标包含一个静态时序，其中表达了 Pod 标签和 Pod 名称的关系：&lt;/p&gt;

&lt;p&gt;可以用 &lt;code&gt;(pod_name=&amp;quot;latency-api-971504058-jzs5h&amp;quot;)&lt;/code&gt; 来查询 Pod 的标签：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;kube_pod_labels{instance=&amp;quot;10.116.0.12:8080&amp;quot;,job=&amp;quot;kubernetes-service-endpoints&amp;quot;,k8s_app=&amp;quot;kube-state-metrics&amp;quot;,kubernetes_name=&amp;quot;kube-state-metrics&amp;quot;,kubernetes_namespace=&amp;quot;kube-system&amp;quot;,label_app=&amp;quot;latency-api&amp;quot;,label_pod_template_hash=&amp;quot;971504058&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod=&amp;quot;latency-api-971504058-jzs5h&amp;quot;} 1
kube_pod_labels{instance=&amp;quot;10.116.1.26:8080&amp;quot;,job=&amp;quot;kubernetes-service-endpoints&amp;quot;,k8s_app=&amp;quot;kube-state-metrics&amp;quot;,kubernetes_name=&amp;quot;kube-state-metrics&amp;quot;,kubernetes_namespace=&amp;quot;kube-system&amp;quot;,label_app=&amp;quot;latency-api&amp;quot;,label_pod_template_hash=&amp;quot;971504058&amp;quot;,namespace=&amp;quot;default&amp;quot;,pod=&amp;quot;latency-api-971504058-jzs5h&amp;quot;} 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;因为有两个 &lt;code&gt;kube-state-metrics&lt;/code&gt; 实例在运行，所以出现了两条结果。这两个指标可以用向量匹配的方式进行合并。他们的值是一致的，所以用 &lt;code&gt;min&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt; 都可以。后面的内容会用 &lt;code&gt;label_app&lt;/code&gt; 进行聚合，所以需要保留这个指标标签。另外 &lt;code&gt;pod&lt;/code&gt; 标签也是需要保留的，用于进行连接。因为在 &lt;code&gt;kube_pod_labels&lt;/code&gt; 中，Pod 的指标标签是 &lt;code&gt;pod&lt;/code&gt;，而在 &lt;code&gt;containers_memory_usage_bytes&lt;/code&gt; 中则变成了 &lt;code&gt;pod_name&lt;/code&gt;。因此需要用一个 &lt;code&gt;label_replace&lt;/code&gt; 进行重命名：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;max by (pod_name,label_app) (
  label_replace(kube_pod_labels{label_app!=&amp;quot;&amp;quot;},&amp;quot;pod_name&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;pod&amp;quot;,&amp;quot;(.*)&amp;quot;)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;返回内容大致如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;{label_app=&amp;quot;latency-api&amp;quot;,pod_name=&amp;quot;latency-api-971504058-n8k6d&amp;quot;}  1
{label_app=&amp;quot;latency-api&amp;quot;,pod_name=&amp;quot;latency-api-971504058-jzs5h&amp;quot;}  1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来就可以用向量匹配的方式来把 &lt;code&gt;container_memory_usage_bytes&lt;/code&gt; 和前面的表达式进行合并了。这里用到了 &lt;code&gt;*&lt;/code&gt;，他把内存用量乘以 &lt;code&gt;kube_pod_labels&lt;/code&gt; 里面的匹配值，然而这个值总是 1，所以其实没什么作用。&lt;/p&gt;

&lt;p&gt;每个 Pod 会有多个容器，也就是说可能有多个 &lt;code&gt;container_memory_usage_bytes&lt;/code&gt;，因此需要用到 &lt;code&gt;group_left&lt;/code&gt;。因为要保留 &lt;code&gt;label_app&lt;/code&gt; 这一指标标签，所以用它作为 &lt;code&gt;group_left&lt;/code&gt; 的参数。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;container_memory_usage_bytes * on (pod_name) group_left(label_app)
max by (pod_name,label_app) (
label_replace(kube_pod_labels{label_app!=&amp;quot;&amp;quot;},&amp;quot;pod_name&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;pod&amp;quot;,&amp;quot;(.*)&amp;quot;)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;用下面的表达式，可以聚合所有 Pod 的内存用量指标：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;sum by (label_app,namespace) (
  container_memory_usage_bytes * on (pod_name) group_left(label_app)
  max by (pod_name,label_app) (
    label_replace(kube_pod_labels{label_app!=&amp;quot;&amp;quot;},&amp;quot;pod_name&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;pod&amp;quot;,&amp;quot;(.*)&amp;quot;)
  )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;images/mem_per_app.png&#34; alt=&#34;mem_per_app&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;用-pod-标签-对-cpu-和-io-指标进行聚合&#34;&gt;用 Pod 标签 对 CPU 和 IO 指标进行聚合&lt;/h2&gt;

&lt;p&gt;既然已经能把 &lt;code&gt;kube_pod_labels&lt;/code&gt; 和 cadvisor 连接起来，那么这个能力范围就不仅限于内存了。&lt;/p&gt;

&lt;h3 id=&#34;cpu&#34;&gt;CPU&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;sum by (label_app,namespace) (
  rate(container_cpu_usage_seconds_total[2m]) * on (pod_name) group_left(label_app)
  max by (pod_name,label_app) (
    label_replace(kube_pod_labels{label_app!=&amp;quot;&amp;quot;},&amp;quot;pod_name&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;pod&amp;quot;,&amp;quot;(.*)&amp;quot;)
  )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;images/cpu_per_app.png&#34; alt=&#34;cpu per app&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;磁盘-io&#34;&gt;磁盘 IO&lt;/h3&gt;

&lt;p&gt;我曾经想要展示一些磁盘 IO 统计，很不幸，这个功能又出&lt;a href=&#34;https://github.com/kubernetes/kubernetes/issues/55397&#34; target=&#34;_blank&#34;&gt;问题&lt;/a&gt;了。&lt;/p&gt;

&lt;h3 id=&#34;网络&#34;&gt;网络&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;sum by (label_app,namespace) (
  rate(container_network_transmit_bytes_total[2m]) * on (pod_name) group_left(label_app)
  max by (pod_name,label_app) (
    label_replace(kube_pod_labels{label_app!=&amp;quot;&amp;quot;},&amp;quot;pod_name&amp;quot;,&amp;quot;$1&amp;quot;,&amp;quot;pod&amp;quot;,&amp;quot;(.*)&amp;quot;)
  )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;images/net_per_app.png&#34; alt=&#34;net_per_app&#34; /&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Promethues 的 Agent 模式：高效转发云原生指标</title>
      <link>/post/prometheus-agent-beta-blog/</link>
      <pubDate>Mon, 22 Nov 2021 20:16:53 +0800</pubDate>
      <guid>/post/prometheus-agent-beta-blog/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://prometheus.io/blog/2021/11/16/agent/&#34; target=&#34;_blank&#34;&gt;Introducing Prometheus Agent Mode, an Efficient and Cloud-Native Way for Metric Forwarding&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://twitter.com/bwplotka&#34; target=&#34;_blank&#34;&gt;Bartlomiej Plotka&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bartek Plotka 是红帽的首席软件工程师，从 2019 年开始担任 Prometheus 项目的维护者，也是 CNCF Thanos 项目的共同作者之一，同时还担任 CNCF 大使以及 CNCF 可观察性 TAG 的技术领导者。他在业余和 O&amp;rsquo;Reilly 出版了《Efficient Go》一书。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Promethues 对于目标的极度专注是我喜欢并加入这个项目的原因。Prometheus 用务实、可靠、经济的方式，推出了无价的指标监控系统。Prometheus 提供了极其稳定和健壮的 API、查询语言和用于进行集成的协议（例如远端写入和 &lt;a href=&#34;https://openmetrics.io/&#34; target=&#34;_blank&#34;&gt;OpenMetrics&lt;/a&gt;），这一稳固的基础，让云原生的监控生态欣欣向荣：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;社区提供了包罗万象的 Exporter，例如&lt;a href=&#34;https://github.com/google/cadvisor&#34; target=&#34;_blank&#34;&gt;容器&lt;/a&gt;、&lt;a href=&#34;https://github.com/cloudflare/ebpf_exporter&#34; target=&#34;_blank&#34;&gt;eBPF&lt;/a&gt;、&lt;a href=&#34;https://github.com/sladkoff/minecraft-prometheus-exporter&#34; target=&#34;_blank&#34;&gt;我的世界&lt;/a&gt;甚至还有针对&lt;a href=&#34;https://megamorf.gitlab.io/2019/07/14/monitoring-plant-health-with-prometheus/&#34; target=&#34;_blank&#34;&gt;园艺的健康监测&lt;/a&gt;；&lt;/li&gt;
&lt;li&gt;现在多数 CNCF 项目都会提供基于 HTTP/HTTPS 的 &lt;code&gt;/metrics&lt;/code&gt; 端点，让 Prometheus 可以读取指标数据。这原本是 Google 内部秘而不宣的一个概念，Prometheus 项目将其公诸于世；&lt;/li&gt;
&lt;li&gt;可观察性的范式发生了变化。从一开始 SRE 和开发者就非常依赖指标数据，对软件的韧性、排障能力以及数据驱动的决策过程产生了很好的推动作用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最后，我们极少会看到没有运行 Prometheus 的 Kubernetes。&lt;/p&gt;

&lt;p&gt;备受瞩目的 Prometheus 社区让其它项目也同步成长，让 Prometheus 脱离了单节点部署的局限性（例如 &lt;a href=&#34;https://cortexmetrics.io/&#34; target=&#34;_blank&#34;&gt;Context&lt;/a&gt;、&lt;a href=&#34;https://thanos.io/&#34; target=&#34;_blank&#34;&gt;Thanos&lt;/a&gt; 等等），更有采用 Promethues API 和数据模型的云供应商（例如&lt;a href=&#34;https://aws.amazon.com/prometheus/&#34; target=&#34;_blank&#34;&gt;亚马逊&lt;/a&gt;和&lt;a href=&#34;https://cloud.google.com/stackdriver/docs/managed-prometheus&#34; target=&#34;_blank&#34;&gt;谷歌&lt;/a&gt;的托管 Promethues、&lt;a href=&#34;https://grafana.com/products/cloud/&#34; target=&#34;_blank&#34;&gt;Grafana 云&lt;/a&gt;等）。如果 Prometheus 只有一个原因，那么这个原因只能是——把监控社区的焦点聚集在重要的事情上面。&lt;/p&gt;

&lt;p&gt;本文中将会介绍 Prometheus 的新特性：“Agent”。这一特性内置于 Prometheus 之中。Agent 模式禁用了 Prometheus 的一些特性，优化了指标抓取和远程写入的能力。这一特性使得一种新的应用模式成为可能。本文中我会陈述该功能让 CNCF 生态中游戏规则发生的变化——是的他让我非常兴奋。&lt;/p&gt;

&lt;h2 id=&#34;转发模式的历史&#34;&gt;转发模式的历史&lt;/h2&gt;

&lt;p&gt;Prometheus 的核心设计从未变更。这是一个向 &lt;a href=&#34;https://sre.google/sre-book/practical-alerting/#the-rise-of-borgmon&#34; target=&#34;_blank&#34;&gt;Google Borgmon 监控系统&lt;/a&gt; 致敬的产品，要监控一个应用，就随应用部署一个 Prometheus 服务，告知 Promethues 如何联系到这个服务，允许 Prometheus 定期抓取当前的指标数据。这种工作方式通常被称为拉取模型，&lt;a href=&#34;https://prometheus.io/blog/2016/07/23/pull-does-not-scale-or-does-it/&#34; target=&#34;_blank&#34;&gt;这种模型保障 Promethues 的轻量和韧性&lt;/a&gt;。另外它还极大简化了应用监控和 Exporter——只需要提供一个简单易读的 HTTP 端点，在其中提供 OpenMetrics 格式的当前指标值即可。这其中没有用到复杂的推送机制，也没有客户端库。一个简单的 Prometheus 监控部署如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/prom.png&#34; alt=&#34;simple&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这种方式工作良好，过去几年中我们看到了上百万的部署案例，其中或长或短的留存了大量的监控数据。其中的指标数据可以进行查询、告警，并记录管理员和开发者都关注的数据指标。&lt;/p&gt;

&lt;p&gt;然而云原生世界一直在发展和进化。随着托管 Kubernetes 方案的成长，几秒钟就能随需创建 Kubernetes 集群，我们已经能够把集群当做牲畜而非宠物（换句话说，我们不再关注特定的实例）。在 &lt;a href=&#34;https://github.com/kcp-dev/kcp&#34; target=&#34;_blank&#34;&gt;kcp&lt;/a&gt; 和 &lt;a href=&#34;https://aws.amazon.com/fargate/&#34; target=&#34;_blank&#34;&gt;Fargate&lt;/a&gt; 中这样的产品中甚至没有了集群的概念。&lt;/p&gt;

&lt;p&gt;另一个有意思的概念就是经常被用在电信、汽车和 IoT 领域的边缘集群和网络。我们会看到越来越多资源有限的小集群。规模限制导致他们无法在本地进行保存，包含监控数据在内的大量数据都需要被传送到远端的更大的节点上。&lt;/p&gt;

&lt;p&gt;这意味着必须对必须对监控数据进行聚合，向用户进行呈现，甚至需要有全局级别的存储。这通常被称为全局视角。&lt;/p&gt;

&lt;p&gt;要实现全局视角，最直接的办法就是在全局层次部署 Prometheus，通过远程网络抓去指标，或者从远端应用直接写入监控数据。我认为两种办法都烂透了，原因如下：&lt;/p&gt;

&lt;p&gt;跨越网络边界的抓取行为会在监控管线中引入不确定因素。本地的拉取模型让 Prometheus 能够清晰获知待抓取目标的问题，例如宕机或者配置错误、重启、抓取缓慢（CPU 耗尽）、无法进行服务发现、缺乏访问凭据、DNS 故障，网络甚至整个集群失灵。外置抓取端引发的不稳定性可能让我们丢失信息。如果网络中断，可能会丧失可见性，相信我，不要这样做。&lt;/p&gt;

&lt;p&gt;应用从远端直接向中心推送数据也不是什么好办法——尤其是在监控目标数量巨大时。得到指标之前，无法得到任何远端应用的信息，这个应用活着吗？是我的管线故障了吗？也许应用认证失败了？和前面的办法一样，跨网络的传输总面临着更大的风险。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Serverless 应用以及类似的短寿命容器经常会让我们将远端推送方式当做救命稻草。这种情况下我们希望把细碎的事件和指标能够聚合到一个较长存活期的时间序列里。我们对这一主题也进行了&lt;a href=&#34;https://groups.google.com/g/prometheus-developers/c/FPe0LsTfo2E/m/yS7up2YzAwAJ&#34; target=&#34;_blank&#34;&gt;讨论&lt;/a&gt;，欢迎加入，一起完善这个方案。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Prometheus 用三种方式来支持全局视图，每种都有不同的优缺点。注意下图橘色部分：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/prom-remote.png&#34; alt=&#34;prom-remote&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;联邦&lt;/strong&gt;：这是第一种用于聚合目的的方案。这种方案里，全局级的 Prometheus 服务器或从基层 Prometheus 中抓取指标的子集。这种级联方式里，联邦节点暴露的指标中包含了原始采样的时间戳，因此降低了跨网络抓取的风险，但是如果网络间的时延达到分钟级，可能就无法在不损失数据的情况下完成数据联合了。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prometheus 远程读取&lt;/strong&gt;：从远端 Prometheus 服务器的数据库中绕过 PromQL，直接提取原始数据。可以在全局一级部署 Prometheus 或者 Thanos 方案，用抓取自多个站点的远程数据来执行 PromQL 查询。这种方式很强大——数据存储在“本地”，还可以按需访问。不幸的是，这种方式也有缺点，如果没有 &lt;a href=&#34;https://github.com/thanos-io/thanos/issues/305&#34; target=&#34;_blank&#34;&gt;Query Pushdown&lt;/a&gt;，一个简单的查询可能就要拉取上 GB 的压缩数据。类似地，如果网络失联，服务就不可用了，另外有些集群只允许 Egress，禁止 Ingress&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;最后一种就是&lt;strong&gt;远程写入&lt;/strong&gt;：这似乎是目前最流行的选择。Agent 模式也是聚焦于远程写入的，因此我们要详细描述一下这个模式&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;远程写入&#34;&gt;远程写入&lt;/h3&gt;

&lt;p&gt;Prometheus 远程写入协议让用户可以把部分或者全部指标数据写入到远端，可以对 Prometheus 进行配置，将一些指标（其中甚至可以代入所有的元数据和范例）转发给一个或多个远端的写入 API。实际上 Prometheus 是同时支持远端接收和写入的，所以可以部署全局级的 Prometheus 来接收跨集群的聚合数据。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1LPhVRSFkGNSuU1fBd81ulhsCPR4hkSZyyBj1SZ8fWOM/edit&#34; target=&#34;_blank&#34;&gt;Prometheus 远程写入 API 规范还在评审阶段&lt;/a&gt;，但整个生态接受了远端写入协议作为缺省指标导出协议。例如 Cortext、Thanos、OpenTelemetry 以及 Amazon、Google、Grafana、Logz.io 等云厂商，都支持这一协议的写入。&lt;/p&gt;

&lt;p&gt;Prometheus 官方提供了官方的 API 兼容性测试，能通过&lt;a href=&#34;https://github.com/prometheus/compliance/tree/main/remote_write_sender&#34; target=&#34;_blank&#34;&gt;远程写入合规性&lt;/a&gt;测试的方案，就可以提供远程写入的客户端能力。对于自行实现的工具来说这个功能非常有帮助，能帮助自实现工具确认协议实现的正确性。&lt;/p&gt;

&lt;p&gt;抓取得到的流数据进行中心化存储之后，就有了全局视图的实现基础。这样也实现了关注点的分离。应用程序不受可观察性团队的管理的情况下，这种方式很有优势。这种方式让服务商们能够将这种工作从客户侧剥离开来，因此得以广泛采用。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;但是 Bartek 你刚刚说过，从应用推送指标不是个好主意！&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;没错，不过有意思的是，远程写入的情况下，Prometheus 还是使用拉取模式从应用端获得指标数据的，然后对取样和序列进行批处理，把数据进行导出，推送到远程写入端点，有效地降低了中心点在应用失联时面临的风险。&lt;/p&gt;

&lt;p&gt;远程写入的可靠性和效率，是一个亟待解决的难题。普罗米修斯社区花了大约三年的时间完成了稳定和可扩展的实现。WAL（写前日志）经过多次重构后，增加了内部队列、分片、智能备份等等。所有这些对用户来说都是隐藏的，用户可以在集中存储的场景下得到良好的流性能和数据量支持。&lt;/p&gt;

&lt;h3 id=&#34;katacoda-教程-远程写入&#34;&gt;Katacoda 教程：远程写入&lt;/h3&gt;

&lt;p&gt;在 Prometheus 中这些都不新鲜，很多用户都在使用这种抓取应用信息后向远端进行写入的方式。&lt;/p&gt;

&lt;p&gt;要体验这种远端写入能力，推荐使用 Katacoda 提供的 &lt;a href=&#34;https://katacoda.com/thanos/courses/thanos/3-receiver&#34; target=&#34;_blank&#34;&gt;Prometheus 远程写入 Thanos 教程&lt;/a&gt;，其中解释了 Prometheus 远程转发的所有步骤。这个课程是免费的，注册账号尝试一下就好。&lt;/p&gt;

&lt;p&gt;这里用接收模式的 Thanos 作为远程存储。现在还可以使用大量与远程写入 API 兼容的其它项目。&lt;/p&gt;

&lt;p&gt;远程写入这么好，为什么还要给 Prometheus 加入 Agent 模式？&lt;/p&gt;

&lt;h2 id=&#34;prometheus-的-agent-模式&#34;&gt;Prometheus 的 Agent 模式&lt;/h2&gt;

&lt;p&gt;Prometheus v2.32.0 开始，用户可以使用测试版参数 &lt;code&gt;--enable-feature=agent&lt;/code&gt; 来启动启动 Prometheus。&lt;/p&gt;

&lt;p&gt;Agent 模式优化了远程写入的用例。它禁止了查询、告警和本地存储，取而代之的是一个自定义的 TSDB WAL。其它部分原封不动：抓取逻辑、服务发现和相关的配置。如果只是想把数据转发到远端的 Prometheus 服务器或其它兼容的项目，这种方式非常值得一试。工作方式如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/agent.png&#34; alt=&#34;agent&#34; /&gt;&lt;/p&gt;

&lt;p&gt;如果你不想在本地进行查询和告警，只是把指标输出到外部，使用 Agent 有什么好处呢？&lt;/p&gt;

&lt;p&gt;第一个就是效率。Agent 中使用的 TSDB WAL 在转发成功后会立刻删除数据。如果远程端点无法连接，就会将数据保存起来，等待端点恢复。这种行为很像非 Agent 模式的 Prometheus，目前的缓冲有效期是两个小时，&lt;a href=&#34;https://github.com/prometheus/prometheus/issues/9607&#34; target=&#34;_blank&#34;&gt;未来可能打破&lt;/a&gt;这个限制。这样一来我们就无需分配大块内存，也不用为查询准备完全索引。代理模式的资源消耗比标准服务实例低得多。&lt;/p&gt;

&lt;p&gt;在边缘或者类似的环境中，CPU 和内存资源可能会很有限，效率是个非常重要的问题。另外目前使用指标进行监控的模式已经非常成熟。这意味着同样成本之下，能获得越多的监控指标，就越有性价比。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agent 模式是针对特定使用场景的，标准模式的 Promethues Server 更稳定、更易维护，仍是缺省建议；Agent 模式的远端存储引入了更高的复杂性，还需谨慎使用。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;另外，Agent 模式便于搭建纵向伸缩的数据接收架构。&lt;/p&gt;

&lt;h3 id=&#34;指标接收端的弹性伸缩&#34;&gt;指标接收端的弹性伸缩&lt;/h3&gt;

&lt;p&gt;数据抓取侧的自动伸缩方案需要根据抓取目标和指标数量进行判断。抓取的数据越多，就要自动部署更多实例。如果目标和指标数量下降了，就应该进行缩容，移除部分实例。自动伸缩能够降低 Promethues 规模调整造成的手工操作负担，并防止低谷期间浪费系统资源。&lt;/p&gt;

&lt;p&gt;Server 模式的 Prometheus 是有状态的，很难应对这种需求。这种模式下搜集的数据保存在本地，缩容过程需要在中止实例之前将数据进行备份。接下来还要面对指标重叠、误导性的过期标记等问题。&lt;/p&gt;

&lt;p&gt;这种场景下，我们需要能够聚合所有实例所有数据的全局视图（例如 Thanos Query 或者 Promxy）来进行查询。普通模式下的 Prometheus 的职责不仅限于指标采集，还包含了告警、录制、查询、压缩、远程写入等，这些任务都会消耗资源。&lt;/p&gt;

&lt;p&gt;Agent 模式将服务发现、指标抓取和远程写入放到一个单独的服务中，如此就将工作焦点集中到了指标搜集上面。Agent 模式的 Prometheus 变得更加的“无状态”。是的为了防止数据丢失，我们需要部署一对 HA 实例，并挂接持久存储。但是技术上来说，我们有几千个目标（容器），我们可以部署多个 Prometheus Agent，安全地把抓取目标分配给特定实例。这么做的根本原因就是这些数据都会被推送给同一个中央存储。&lt;/p&gt;

&lt;p&gt;总的说来，Agent 模式的 Prometheus 让自动的水平伸缩成为可能，从而有了针对监控指标规模变更进行应对的能力。我们将会和 &lt;a href=&#34;https://github.com/prometheus-operator/prometheus-operator&#34; target=&#34;_blank&#34;&gt;Prometheus Kubernetes Operator&lt;/a&gt; 社区一起在这个方向努力。&lt;/p&gt;

&lt;p&gt;那么 Agent 模式的 Prometheus 是否真的可用呢？&lt;/p&gt;

&lt;h3 id=&#34;agent-模式得到了大规模验证&#34;&gt;Agent 模式得到了大规模验证&lt;/h3&gt;

&lt;p&gt;Prometheus 会把 Agent 模式作为实验性功能加入下一个版本。参数、API 以及 WAL 的格式会发生变更。但是这种实现的性能已经在 &lt;a href=&#34;https://grafana.com/&#34; target=&#34;_blank&#34;&gt;Grafana Lab&lt;/a&gt; 的帮助下得到了实际验证。&lt;/p&gt;

&lt;p&gt;Agent 的自定义 WAL 最初的实现是受到了 &lt;a href=&#34;https://github.com/rfratto&#34; target=&#34;_blank&#34;&gt;Robert Fratto&lt;/a&gt; 在 2019 年为 TSDB 实现的 WAL 的启发，期间得到了 Prometheus Maintainer &lt;a href=&#34;https://twitter.com/tom_wilkie&#34; target=&#34;_blank&#34;&gt;Tom Wilkie&lt;/a&gt; 的指导。这个格式后来被用于 &lt;a href=&#34;https://github.com/grafana/agent&#34; target=&#34;_blank&#34;&gt;Grafana Agent&lt;/a&gt; 项目，得到了很多 Grafana 云的用户的采用。这一方案的成熟后，捐献给了 Promethues，希望得到集成和更多的发展和采用。Grafana 实验室的 Robert 在 Redhat 的 Srikrishna 以及社区帮助下，把这些代码移植到了 Prometheus，然后只用了半个月就合并进入到 &lt;code&gt;main&lt;/code&gt; 分支。&lt;/p&gt;

&lt;p&gt;有些 Prometheus Maintainer 也曾经为 Grafana Agent 项目贡献过代码，Grafana 的新 WAL 格式也是受到了 Prometheus WAL 格式的启发，捐献的过程非常平滑，并且目前的 Prometheus TSDB Maintainer 也能够方便的进行管理。并且 Robot 已经加入 Prometheus 团队，成为 TSDB 的 Maintainer。&lt;/p&gt;

&lt;p&gt;接下来讲讲如何使用。&lt;/p&gt;

&lt;h3 id=&#34;如何使用-agent-模式&#34;&gt;如何使用 Agent 模式&lt;/h3&gt;

&lt;p&gt;Prometheus 的帮助（&lt;code&gt;--help&lt;/code&gt; 参数）内容中会看到类似内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;usage: prometheus [&amp;lt;flags&amp;gt;]

The Prometheus monitoring server

Flags:
  -h, --help                     Show context-sensitive help (also try --help-long and --help-man).
      (... other flags)
      --storage.tsdb.path=&amp;quot;data/&amp;quot;
                                 Base path for metrics storage. Use with server mode only.
      --storage.agent.path=&amp;quot;data-agent/&amp;quot;
                                 Base path for metrics storage. Use with agent mode only.
      (... other flags)
      --enable-feature= ...      Comma separated feature names to enable. Valid options: agent, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-at-modifier, promql-negative-offset, remote-write-receiver,
                                 extra-scrape-metrics, new-service-discovery-manager. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Agent 模式是需要用 &lt;code&gt;--enable-feature=agent&lt;/code&gt; 参数的启用的。这种模式下能够使用同样的指标抓取配置以及远程写入能力。Agent 模式下，Web UI 的查询功能是被禁用的，只能用于展示构建信息、配置内容、抓取指标和服务发现信息。&lt;/p&gt;

&lt;h3 id=&#34;在-katacoda-上尝试-prometheus-agent&#34;&gt;在 Katacoda 上尝试 Prometheus Agent&lt;/h3&gt;

&lt;p&gt;可以&lt;a href=&#34;https://katacoda.com/thanos/courses/thanos/4-receiver-agent&#34; target=&#34;_blank&#34;&gt;在 Katacoda 上尝试 Promtheus Agent&lt;/a&gt;，真切体会其中的易用性。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>（空想场景）使用 Prometheus 监控特定日志行数</title>
      <link>/post/line-count-to-promethes/</link>
      <pubDate>Wed, 11 Aug 2021 20:06:06 +0800</pubDate>
      <guid>/post/line-count-to-promethes/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;感谢 @云原生小白 提供线索&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在系统的监控过程中，有时我们只是想要知道一些特定内容的出现数量或者频度，并不关心他的具体内容，而且也不想特意部署一个 Loki 或者 Elasticsearch，这时就可以使用 Fluentd 花里胡哨的插件功能来完成任务了。&lt;/p&gt;

&lt;p&gt;Fluentd 有一个 &lt;a href=&#34;https://docs.fluentd.org/monitoring-fluentd/monitoring-prometheus&#34; target=&#34;_blank&#34;&gt;Prometheus 插件&lt;/a&gt;，能够提供 Prometheus 接口提供采集数据，插件需要用 &lt;code&gt;fluent-gem&lt;/code&gt; 进行安装，如果在 Docker 中的话，可以使用下列 Dockerfile：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM fluentd:v1.9.1-1.0
USER root
RUN fluent-gem install fluent-plugin-prometheus
USER fluent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这个插件的基本配置方式是，提供一个 &lt;code&gt;promethues&lt;/code&gt; 的类型，包含一个 &lt;code&gt;&amp;lt;metric&amp;gt;&lt;/code&gt; 元素用于对指标结构进行定义。例如文档中使用的：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;  @type prometheus
  &amp;lt;metric&amp;gt;
    name fluentd_input_status_num_records_total
    type counter
    desc The total number of incoming records
    &amp;lt;labels&amp;gt;
      tag ${tag}
      hostname ${hostname}
    &amp;lt;/labels&amp;gt;
  &amp;lt;/metric&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这种指标放在 &lt;code&gt;&amp;lt;filter&amp;gt;&lt;/code&gt; 用于指示输入数量，而放在 &lt;code&gt;&amp;lt;match&amp;gt;&lt;/code&gt; 中则可以监控输出数量。&lt;/p&gt;

&lt;p&gt;这里定义了一个名为 &lt;code&gt;fluentd_input_status_num_records_total&lt;/code&gt; 的指标，其类型为 &lt;code&gt;counter&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;定义指标之后，还要将其暴露给 Prometheus：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;&amp;lt;source&amp;gt;
  @type prometheus
  bind 0.0.0.0
  port 24231
  metrics_path /metrics
&amp;lt;/source&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这段配置定义了一个监听 &lt;code&gt;24231&lt;/code&gt; 端口的 Prometheus 端点，路径为 &lt;code&gt;/metrics&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&#34;举个栗子&#34;&gt;举个栗子&lt;/h2&gt;

&lt;p&gt;接下来用一个完整场景来展示这个例子，假设我们要监控 &lt;code&gt;/logs/input.txt&lt;/code&gt; 中的 &lt;code&gt;warning&lt;/code&gt; 数量，会采用文末的完整配置，分段解释如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; 段定义采集文件名称&lt;/li&gt;
&lt;li&gt;第一个 &lt;code&gt;&amp;lt;filter&amp;gt;&lt;/code&gt; 中使用 &lt;code&gt;@type promethues&lt;/code&gt; 来监控输入数量，生成指标 &lt;code&gt;fluentd_input_status_num_records_total&lt;/code&gt;，类型为 &lt;code&gt;counter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第二个 &lt;code&gt;&amp;lt;filter&amp;gt;&lt;/code&gt; 用 &lt;code&gt;@type grep&lt;/code&gt; 的正则表达式插件对输入进行过滤&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;match&amp;gt;&lt;/code&gt; 节中使用 &lt;code&gt;@type copy&lt;/code&gt; 对输出进行分流&lt;/li&gt;
&lt;li&gt;第一个 &lt;code&gt;&amp;lt;store&amp;gt;&lt;/code&gt; 输出 &lt;code&gt;fluentd_output_status_num_records_total&lt;/code&gt; 的 Promethues 指标，对过滤出来的文本进行计数&lt;/li&gt;
&lt;li&gt;第二个 &lt;code&gt;&amp;lt;store&amp;gt;&lt;/code&gt; 将输出内容展示在 &lt;code&gt;stdout&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;配置结束之后启动采集过程，可以使用类似如下脚本：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/sh
docker run -it --rm \
        -v $(pwd)/etc:/etc/fluentd \
        -v $(pwd)/log:/data \
        -p 12345:12345 \
        fluentd:prom \
        fluentd -c /etc/fluentd/fluentd.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;启动之后，我们向日志中输出内容，例如 &lt;code&gt;echo &amp;quot;warn&amp;quot; &amp;gt;&amp;gt; input.txt&lt;/code&gt;，会看到 &lt;code&gt;fluentd&lt;/code&gt; 日志输出了类似 &lt;code&gt;2021-08-14 07:06:55.688191458 +0000 custom.log: {&amp;quot;message&amp;quot;:&amp;quot;warn&amp;quot;}&lt;/code&gt; 的内容，如果使用 &lt;code&gt;curl&lt;/code&gt; 访问开放出来的 &lt;code&gt;:12345/metrics&lt;/code&gt;，会看到输出中的如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;fluentd_input_status_num_records_total{tag=&amp;quot;custom.log&amp;quot;,hostname=&amp;quot;757214c8a91a&amp;quot;} 2.0      │➜  log  vim fluentd.conf
fluentd_output_status_num_records_total{tag=&amp;quot;custom.log&amp;quot;,hostname=&amp;quot;757214c8a91a&amp;quot;} 1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这是很常见的指标格式，如果在 Kubernetes 中，对 Pod 进行注解，纳入采集范围，就可以像其它监控指标一样使用了。&lt;/p&gt;

&lt;h2 id=&#34;fluentd-conf&#34;&gt;fluentd.conf&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;&amp;lt;source&amp;gt;
  @type tail
  path /data/input.txt
  pos_file /data/input.pos
  tag custom.log
  &amp;lt;parse&amp;gt;
    @type none
  &amp;lt;/parse&amp;gt;
&amp;lt;/source&amp;gt;
&amp;lt;filter custom.**&amp;gt;
  @type prometheus
  &amp;lt;metric&amp;gt;
    name fluentd_input_status_num_records_total
    type counter
    desc The total number of incoming records
    &amp;lt;labels&amp;gt;
      tag ${tag}
      hostname ${hostname}
    &amp;lt;/labels&amp;gt;
  &amp;lt;/metric&amp;gt;
&amp;lt;/filter&amp;gt;
&amp;lt;filter custom.**&amp;gt;
  @type grep
  &amp;lt;regexp&amp;gt;
    key message
    pattern /warn/
  &amp;lt;/regexp&amp;gt;
&amp;lt;/filter&amp;gt;
&amp;lt;match custom.**&amp;gt;
  @type copy
  &amp;lt;store&amp;gt;
    @type prometheus
    &amp;lt;metric&amp;gt;
      name fluentd_output_status_num_records_total
      type counter
      desc The total number of outgoing records
      &amp;lt;labels&amp;gt;
        tag ${tag}
        hostname ${hostname}
      &amp;lt;/labels&amp;gt;
    &amp;lt;/metric&amp;gt;
  &amp;lt;/store&amp;gt;
  &amp;lt;store&amp;gt;
    @type stdout
&amp;lt;/match&amp;gt;

&amp;lt;source&amp;gt;
  @type prometheus
  bind 0.0.0.0
  port 12345
  metrics_path /metrics
&amp;lt;/source&amp;gt;

&amp;lt;source&amp;gt;
  @type prometheus_output_monitor
  interval 10
  &amp;lt;labels&amp;gt;
    hostname ${hostname}
  &amp;lt;/labels&amp;gt;
&amp;lt;/source&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>介绍一个小工具：KubeNurse——集群网络监控</title>
      <link>/post/cn-toolkit-kubenurse/</link>
      <pubDate>Mon, 01 Mar 2021 15:57:30 +0800</pubDate>
      <guid>/post/cn-toolkit-kubenurse/</guid>
      <description>

&lt;h2 id=&#34;地址&#34;&gt;地址&lt;/h2&gt;

&lt;p&gt;Kubenurse：&lt;code&gt;https://github.com/postfinance/kubenurse&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;

&lt;p&gt;在 Kubernetes 集群运行中，一个常见故障就是集群内网络故障，经常会因为临时策略变更或者网络抖动导致一些古怪问题，而实际场景里的虚拟机和网络的监控经常是由其它部门管理的，如果从业务和 Kubernetes 这样的上层设施着手，可能需要一些时间才能解决问题。&lt;code&gt;kubenurse&lt;/code&gt; 项目使用 HTTP 检测的方式提供了常用的几个监控指标。&lt;/p&gt;

&lt;p&gt;这个工具的实现也很直接，用 Daemonset 的形式部署在每个集群节点上，每个 Pod 都会通过 HTTP 检测的方式对上述几种目标分别进行访问，最后用 Prometheus Summary 指标的形式暴露出来用于监控。检测机制如图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/nurse.png&#34; alt=&#34;nurse&#34; /&gt;&lt;/p&gt;

&lt;p&gt;每个 Pod 都开放了 8080 的 http 端口，包含以下端点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; 或者 &lt;code&gt;/alive&lt;/code&gt;：返回本节点信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/alwayshappy&lt;/code&gt;：返回 HTTP 200 用于心跳&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/metrics&lt;/code&gt;：暴露 Prometheus 指标数据&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/alive&lt;/code&gt; 返回的节点信息如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;api_server_direct&amp;quot;: &amp;quot;ok&amp;quot;,
  &amp;quot;api_server_dns&amp;quot;: &amp;quot;ok&amp;quot;,
  &amp;quot;me_ingress&amp;quot;: &amp;quot;ok&amp;quot;,
  &amp;quot;me_service&amp;quot;: &amp;quot;ok&amp;quot;,
  &amp;quot;hostname&amp;quot;: &amp;quot;kubenurse-1234-x2bwx&amp;quot;,
  &amp;quot;neighbourhood_state&amp;quot;: &amp;quot;ok&amp;quot;,
  &amp;quot;neighbourhood&amp;quot;: [
   {
    &amp;quot;PodName&amp;quot;: &amp;quot;kubenurse-1234-8fh2x&amp;quot;,
    &amp;quot;PodIP&amp;quot;: &amp;quot;10.10.10.67&amp;quot;,
    &amp;quot;HostIP&amp;quot;: &amp;quot;10.12.12.66&amp;quot;,
    &amp;quot;NodeName&amp;quot;: &amp;quot;k8s-66.example.com&amp;quot;,
    &amp;quot;Phase&amp;quot;: &amp;quot;Running&amp;quot;
   },
   {
    &amp;quot;PodName&amp;quot;: &amp;quot;kubenurse-1234-ffjbs&amp;quot;,
    &amp;quot;PodIP&amp;quot;: &amp;quot;10.10.10.138&amp;quot;,
    &amp;quot;HostIP&amp;quot;: &amp;quot;10.12.12.89&amp;quot;,
    &amp;quot;NodeName&amp;quot;: &amp;quot;k8s-89.example.com&amp;quot;,
    &amp;quot;Phase&amp;quot;: &amp;quot;Running&amp;quot;
   }
  ],
  &amp;quot;headers&amp;quot;: {
   &amp;quot;Accept&amp;quot;: [
    &amp;quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8&amp;quot;
   ],
   &amp;quot;Accept-Encoding&amp;quot;: [
    &amp;quot;gzip, deflate, br&amp;quot;
   ],
   ...
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，其中包含了上述所说的几个检测结果。&lt;/p&gt;

&lt;h2 id=&#34;部署&#34;&gt;部署&lt;/h2&gt;

&lt;p&gt;源码中包含了一个 &lt;code&gt;example&lt;/code&gt; 目录，简单地 &lt;code&gt;kubectl apply&lt;/code&gt; 就可以完成部署，这里有两个可能需要修改的地方：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;缺省命名空间是 &lt;code&gt;kube-system&lt;/code&gt;，建议查找替换，并要注意调整 RBAC 授权。&lt;/li&gt;
&lt;li&gt;涉及 Ingress 检测，因此要注意提供正确的域名。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;监控&#34;&gt;监控&lt;/h2&gt;

&lt;p&gt;部署成功之后，Prometheus 会根据 Daemonset 中的注解采集数据：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;...
      annotations:
        prometheus.io/path: &amp;quot;/metrics&amp;quot;
        prometheus.io/port: &amp;quot;8080&amp;quot;
        prometheus.io/scheme: &amp;quot;http&amp;quot;
        prometheus.io/scrape: &amp;quot;true&amp;quot;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;访问任意 Pod 的 &lt;code&gt;:8080/metrics&lt;/code&gt; 端点，会看到如下指标：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubenurse_errors&lt;/code&gt;：如果检测过程中出现错误，这个计数器会进行累加。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubenurse_request&lt;/code&gt;：一个 Summary 类型的指标，正常检测结果的时间消耗分布。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这两个指标使用 &lt;code&gt;type&lt;/code&gt; 标签对结果进行标识，对应几种不同的检测目标：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;api_server_direct&lt;/code&gt;：从节点直接检测 API Server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;api_server_dns&lt;/code&gt;：从节点通过 DNS 检测 API Server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;me_ingress&lt;/code&gt;：通过 Ingress 检测本服务 Service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;me_service&lt;/code&gt;：使用 Service 检测本服务 Service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path_$KUBELET_HOSTNAME&lt;/code&gt;：节点之间的互相检测&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如此一来，我们就可以根据各种延迟时间的分布情况，以及返回错误的数量来确认集群网络状况了。&lt;/p&gt;

&lt;h2 id=&#34;注意&#34;&gt;注意&lt;/h2&gt;

&lt;p&gt;节点较多时，每次采集可能会产生 &lt;code&gt;n*(n-1)&lt;/code&gt; 次访问，会造成较重负载，可以给 Pod 打标签，并使用标签过滤的方式来减少请求，但是这样一来，就会导致检测结果不够全面的问题，因此还需对实际应用进行权衡。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>给 Node Exporter 加上 Basic 认证</title>
      <link>/post/node_exp_basic_auth/</link>
      <pubDate>Thu, 09 Apr 2020 22:30:05 +0800</pubDate>
      <guid>/post/node_exp_basic_auth/</guid>
      <description>&lt;p&gt;前两天在成老师群里问了个无聊的问题——Node Exporter 输出的数据，是不是就应该匿名获取呢？本着 0 信任原则，缺省情况下使用 Host Network 的 Node Exporter 暴露的端口的确是令人稍有不安的，那么如何改善呢？&lt;/p&gt;

&lt;p&gt;Node Exporter 新版本中提供了一个 TLS 认证的实验性功能，恰好 Prometheus 也是支持双向 TLS 认证的。不过很多服务会通过 Endpoint 方式提供 Exporter 服务，用 Nginx Sidecar 会是个更加通用的方式。下面举个简单的例子，其他的 Exporter 也可以照猫画虎，并且 Nginx 很成熟，完全可以提供其他更丰富的认证能力。&lt;/p&gt;

&lt;p&gt;首先使用 Helm 安装 Prometheus：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;helm install stable/prometheus \
--generate-name \
--set alertmanager.enabled=false\
--set nodeExporter.hostNetwork=false \
--set pushgateway.enabled=false \
--set server.persistentVolume.enabled=false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;启动之后，会生成一组 Prometheus 组件的资源对象， 要修改的包括几个项目：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;生成 Basic 认证所需的文件&lt;/li&gt;
&lt;li&gt;为 Nginx 编写反向代理配置&lt;/li&gt;
&lt;li&gt;以 Sidecar 的形式把 Nginx 加入 Node Exporter 的 Pod 中&lt;/li&gt;
&lt;li&gt;变更 Node Exporter 的抓取配置&lt;/li&gt;
&lt;li&gt;变更 Prometheus 的采集参数&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;可以使用 htpasswd 工具生成密码文件，例如：&lt;code&gt;htpasswd -c -m passwd.dat admin&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;接下来编写一个配置文件片段：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;server {
    listen  9101;
    server_name localhost;
    auth_basic   &amp;quot;login&amp;quot;;
    auth_basic_user_file /etc/nginx/conf.d/passwd.dat;

    location / {
        root   /usr/share/nginx/html;
        proxy_pass http://127.0.0.1:9100;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里使用一个非常简单的配置，引用前面生成的密码文件进行验证，并且对来自 9091 端口的请求，转发到同一个 Pod 中 9100 端口的 Node Exporter 上。&lt;/p&gt;

&lt;p&gt;用前面的两个文件生成 Configmap 供容器引用：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl create configmap nginx-config \
--from-file=proxy.conf --from-file=passwd.dat
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;生成 Nginx 配置之后，就需要把 Nginx 加入 NodeExporter 了，可以使用 kubectl edit 在线编辑，或者导出 YAML，加入如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;    spec:
      containers:
        ...
        - image: nginx:stable-alpine
          ports:
          - containerPort: 9101
            name: proxy
            protocol: TCP
          name: nginx
          volumeMounts:
            - mountPath: /etc/nginx/conf.d
              name: nginx-config
              readOnly: true
      ...
      volumes:
        ...
        - name: nginx-config
          configMap:
            name: nginx-config
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;因为端口发生了变化，所以还需要修改 Service 的抓取标签，注解中加入：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  annotations:
    prometheus.io/port: &amp;quot;9101&amp;quot;
    prometheus.io/scrape: &amp;quot;true&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后修改 Prometheus 的配置，在 &lt;code&gt;kubernetes-service-endpoints&lt;/code&gt; 加入如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;    - job_name: kubernetes-service-endpoints
      basic_auth:
        username: admin
        password: password
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重启 Prometheus，之后，可以看到工作还是继续进行，但是使用 CURL 访问会得到 401：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ curl http://192.168.14.252:9101/metrics
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;401 Authorization Required&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;401 Authorization Required&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;
&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;nginx/1.16.1&amp;lt;/center&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;以此类推，如果在 Nginx 中引入 TLS 双向认证，还可以使用 CA 的方式对认证过程进行进一步的集中管理，让更多的 Exporter 进入管理范围。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Kubernetes 1.7 下的 Prometheus 监控</title>
      <link>/post/prometheus-in-k8s-1.7/</link>
      <pubDate>Mon, 28 Aug 2017 01:59:06 +0800</pubDate>
      <guid>/post/prometheus-in-k8s-1.7/</guid>
      <description>

&lt;p&gt;在 Kubernetes 的标准 Heapster + InfluxDB 的监控方案之外，还有一个监控工具就是 Prometheus 了，相比 InfluxDB 来说，Prometheus 有更集中的检测能力，更多的 Exporter（数据源）支持（不过好像还是打不过 Zabbix？），以及更新潮。。&lt;/p&gt;

&lt;p&gt;另外不少新的软件方案缺省开始支持 Prometheus 的数据抓取，所以，早上早填坑。下面是日前在一个 Kubernetes 1.7.3 集群中部署 Prometheus 监控遇到的两个坑，分享一下：&lt;/p&gt;

&lt;h2 id=&#34;cadvisor&#34;&gt;cAdvisor&lt;/h2&gt;

&lt;p&gt;官方示例解释如下：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics
(those whose names begin with &amp;lsquo;container_&amp;lsquo;) have been removed from the
Kubelet metrics endpoint.  This job scrapes the cAdvisor endpoint to
retrieve those metrics.&lt;/p&gt;

&lt;p&gt;In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor
HTTP endpoint; use &amp;ldquo;replacement: /api/v1/nodes/${1}:4194/proxy/metrics&amp;rdquo;
in that case (and ensure cAdvisor&amp;rsquo;s HTTP server hasn&amp;rsquo;t been disabled with
the &amp;ndash;cadvisor-port=0 Kubelet flag).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 Kubernetes 1.7.3 和后续版本中，命名前缀为&lt;code&gt;container_&lt;/code&gt; 的 cAdvisor 指标被从 Kubelet
中移除，这一个 Job 从 cAdvisor 端点中抓取数据。&lt;/p&gt;

&lt;p&gt;在 Kubernetes 1.7.0 - 1.7.2 中，这些指标只暴露在 cAdvisor 的 http 端点中，需要使用
&lt;code&gt;eplacement: /api/v1/nodes/${1}:4194/proxy/metrics&lt;/code&gt;。（注意保证 cAdvisor 的 http
服务没有被&lt;code&gt;--cadvisor-port=0&lt;/code&gt;禁用）。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- job_name: &#39;kubernetes-cadvisor&#39;
  scheme: https
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  kubernetes_sd_configs:
  - role: node
  relabel_configs:
  - action: labelmap
    regex: __meta_kubernetes_node_label_(.+)
  - target_label: __address__
    replacement: kubernetes.default.svc:443
  - source_labels: [__meta_kubernetes_node_name]
    regex: (.+)
    target_label: __metrics_path__
    replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;kube-state-metrics&#34;&gt;kube-state-metrics&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;https://github.com/kubernetes/kube-state-metrics&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;网址就能看出，这一服务和 Kubernetes 有点亲密。运行之后，能够为 Prometheus 提供大量详细指标，
而且这一服务的指标相对来说更具逻辑性，更方便从服务/应用的角度进行监控。&lt;/p&gt;

&lt;p&gt;目前容器地址为(不过能 pull 到最新的 v1.0.0，可能是 README 没有同步)：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcr.io/google_containers/kube-state-metrics:v0.5.0&lt;/code&gt;&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
