12

Cloud Native Monitoring Notes

 2 years ago
source link: https://minei.me/archives/cloud-native-monitoring-notes.html
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

Cloud Native Monitoring Notes

boyizmen
2022-05-25
notes 

Cloud Native Monitoring

Observability and Analysis

Observability 是指一种 从系统外部输出能够理解到系统的程度 的 系统特性。
比如我们可以从系统的cpu占用,内存使用量等来观察计算机。

Analysis 指的是分析这些可观测数据并进行理解。

为了确保系统不中断,需要对系统的各个方面进行观测和分析。
Observability和Analysis工具涵盖了logging, monitoring, tracing, 和 chaos engineering。

Monitoring

监控是指对系统进行检测以收集、汇总和分析日志和指标,以提高我们对其行为的理解。
而一个好的监控能够让操作人员快速响应异常,甚至能够自动的进行处理,同时也能够监控系统的健康程度,甚至系统的任何变动。

同时,监控是一个高效系统重要的组成部分。

Buzzwords CNCF Projects
Monitoring
Time series
Alerting
Metrics
Prometheus (graduated)
Cortex (incubating)
Thanos (incubating)
Fonio (sandbox)
Kuberhealthy (sandbox)
OpenMetrics (sandbox)
Pixie (sandbox)
Skooner (sandbox)
Trickster (sandbox)

Prometheus

Overview

Architecture:

architecture.png
  • 抓取,读取时序数据的后端服务;
  • 支持短生命周期任务的 Pushgateway
  • 用于服务导出数据的 Exporter
  • 告警系统;
  • 多种支持工具;

Metric DataModel

Metric Definition:

  1. <metric name>{<label name>=<label value>, ...} value [timestamp]
  2. # e.g.
  3. api_http_requests_total{method="POST", handler="/messages"} 5 1395066363000

Text Data Format

  1. # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
  2. # TYPE process_cpu_seconds_total counter
  3. process_cpu_seconds_total 1871.15625

文本协议基于 ,忽略空行,使用 \n 分割,最后一行必须是换行符。

# 是注释行,但是如果后面是 HELPTYPE

  • HELP 那么后面需要一个 metric 名称,其他则是相关的注释,同时一个 metric 只能有一个 HELP 行;
  • TYPE 后面需要一个 metric 名称,紧接着是 metric 类型,类型是非必填,如果不填写则默认为 untyped
  1. # 时间戳是UTC毫秒时间戳
  2. metric_name [ "{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}" ] value [ timestamp ]

Metric Types

Counter

是一个逐渐累加的metric数据,比如已完成请求数量等等,不能使用counter来表示一个可以减少的数据,比如当前线程数量。

Gauge

是一个可任意增减的metric数据,且仅能是一个数字,比如内存使用量、温度等等。

Histogram

Histogram包含了一个时间段内以同一个前缀命名的多个时序数据:

  • <basename>_bucket{le="<upper inclusive bound>"} 观察到的累计计数,可以理解成小于某个值的统计数量;
  • <basename>_sum 观察值总和;
  • <basename>_count 观察到的事件总数;

Summary

Summary包含一个时间段内以同一个前缀命名的多个时序数据:

  • <basename>{quantile="<p>"} q-quantiles (0 ≤ q ≤ 1) 观察到事件的q分位数
  • <basename>_sum 观察值总和;
  • <basename>_count 观察到的事件总数;
  1. # HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
  2. # TYPE go_gc_duration_seconds summary
  3. go_gc_duration_seconds{quantile="0"} 2.83e-05
  4. go_gc_duration_seconds{quantile="0.25"} 6.83e-05
  5. go_gc_duration_seconds{quantile="0.5"} 8.95e-05
  6. go_gc_duration_seconds{quantile="0.75"} 0.0001084
  7. go_gc_duration_seconds{quantile="1"} 0.000557999
  8. go_gc_duration_seconds_sum 0.203637424
  9. go_gc_duration_seconds_count 1894

Histogram 和 Summary 差异:

  • 都包含了sum和count指标;
  • Summary直接存储分位值,而Histogram需要进行计算;

JOBS AND INSTANCES

instance 是指一个可以抓取数据的 endpoint,通常也是对应一个进程。

具有相同目的的 instance 称为一个 job

  • job: api-server
    • instance 1: 1.2.3.4:5670
    • instance 2: 1.2.3.4:5671
    • instance 3: 5.6.7.8:5670
    • instance 4: 5.6.7.8:5671

ServiceMonitor & PodMonitor

prometheus通过 ServiceMonitor 监控 service,通过 PodMonitor 来监控 pod。

默认配置的是可以获取集群中所有的monitor资源,前提是配置好权限,如果需要限制prometheus监控的monitor范围,
可以在 prometheus-prometheus.yaml
中进行配置:

  1. apiVersion: monitoring.coreos.com/v1
  2. kind: Prometheus
  3. metadata:
  4. labels:
  5. prometheus: k8s
  6. name: k8s
  7. namespace: monitoring
  8. spec:
  9. # 默认没有进行配置,可以对所有 ns 和 monitor进行监控
  10. serviceMonitorNamespaceSelector: {}
  11. serviceMonitorSelector: {}
  12. podMonitorNamespaceSelector: {}
  13. podMonitorSelector: {}

Deploy

kubernetes 部署方式支持 operatorkube-prometheus
这里使用 kube-prometheus 来进行部署。

  1. # 安装 operator
  2. kubectl create -f manifests/setup
  3. # 安装 prometheus 服务端和各个组件
  4. kubectl create -f manifests/

需要注意的是上面的配置文件创建在 monitoring 命名空间下,同时为了支持跨 ns 的监控需要修改服务端的权限配置,
prometheus-clusterRole.yaml

  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: ClusterRole
  3. metadata:
  4. name: prometheus-k8s
  5. rules:
  6. - apiGroups:
  7. resources:
  8. - nodes/metrics
  9. verbs:
  10. - nonResourceURLs:
  11. - /metrics
  12. verbs:
  13. - apiGroups:
  14. # 资源和操作权限
  15. resources:
  16. - services
  17. - pods
  18. - endpoints
  19. verbs:
  20. - list
  21. - watch

部署成功后默认配置了下面的 service

  1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  2. alertmanager-main ClusterIP 10.233.43.107 <none> 9093/TCP 9d
  3. alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 9d
  4. grafana ClusterIP 10.233.24.21 <none> 3000/TCP 9d
  5. kube-state-metrics ClusterIP None <none> 8443/TCP,9443/TCP 9d
  6. node-exporter ClusterIP None <none> 9100/TCP 9d
  7. prometheus-adapter ClusterIP 10.233.7.187 <none> 443/TCP 9d
  8. prometheus-k8s ClusterIP 10.233.31.173 <none> 9090/TCP 9d
  9. prometheus-operated ClusterIP None <none> 9090/TCP 9d
  10. prometheus-operator ClusterIP None <none> 8443/TCP 9d

需要关注的是下面几个 service

  • alertmanager-main
  • grafana
  • node-exporter k8s集群节点 exporter (每个节点都部署了一个);
  • prometheus-k8s

先将所有的ui服务通过ingress暴露出来:

  1. # ingress
  2. apiVersion: extensions/v1beta1
  3. kind: Ingress
  4. metadata:
  5. name: monitor-ingress
  6. namespace: monitoring
  7. annotations:
  8. spec:
  9. rules:
  10. - http:
  11. paths:
  12. - path: /
  13. backend:
  14. serviceName: prometheus-k8s
  15. servicePort: web
  16. host: prome.minei.test
  17. - http:
  18. paths:
  19. - path: /
  20. backend:
  21. serviceName: grafana
  22. servicePort: http
  23. host: grafana.minei.test
  24. - http:
  25. paths:
  26. - path: /
  27. backend:
  28. serviceName: alertmanager-main
  29. servicePort: web
  30. host: alert.minei.test

Querying

PromQL数据类型:

  • Instant Vector 一组时间序列,每个时间序列包含一个样本,所有时间序列都共享相同的时间戳;
  • Range Vector 一组时间序列,包含每个时间序列随时间变化的数据点范围
  • Scalar 简单的数字浮点值
  • String 字符串,尚未使用
  • " ' ` 都可以用来声明字符串;
  • 23 -2.43 3.4e-9 0x8f -Inf NaN 浮点字面量;
  • 瞬时向量选择器
    1. node_cpu_seconds_total{instance="master-1-145", cpu="1"}
    • 运算符支持 = != =~ !~,后面两种是正则表达式
    • 同时支持 __name__ 来筛选metric;
      1. # 筛选所有test开头的metric
      2. {__name__=~"test.*"}
  • 范围向量选择器,[] 来声明时间范围,选择声明范围内的数据:
    • ms - milliseconds
    • s - seconds
    • m - minutes
    • h - hours
    • d - days - assuming a day has always 24h
    • w - weeks - assuming a week has always 7d
    • y - years - assuming a year has always 365d
    1. # 筛选master-145上1m10s内cpu的使用时间
    2. node_cpu_seconds_total{instance="master-1-145"}[1m10s]
  • offset 修饰符,将选择器中当前时间进行偏移,必须紧跟在选择器之后;
    1. # 如果当前时间是 21:00 那么下面查询的就是 20:00 之前的数据
    2. node_cpu_seconds_total{instance="master-1-145"} offset 1h
    3. sum(node_cpu_seconds_total{instance="master-1-145"}) offset 1m
  • @ 修饰符,用来选择某个时间戳的数据,也需要紧跟在选择器之后;
    1. node_cpu_seconds_total{instance="master-1-145"} @ 1609746000
    2. sum(node_cpu_seconds_total{instance="master-1-145"}) @ 1609746000

Operators

  • 向量匹配,ignoring 可以在匹配时忽略指定标签,而 on 可以指定匹配的标签;
    1. method_code:http_errors:rate5m{method="get", code="500"} 24
    2. method_code:http_errors:rate5m{method="get", code="404"} 30
    3. method_code:http_errors:rate5m{method="put", code="501"} 3
    4. method_code:http_errors:rate5m{method="post", code="500"} 6
    5. method_code:http_errors:rate5m{method="post", code="404"} 21
    6. method:http_requests:rate5m{method="get"} 600
    7. method:http_requests:rate5m{method="del"} 34
    8. method:http_requests:rate5m{method="post"} 120
    • 一对一匹配,如果有相同的标签集合和值,那么他们就是匹配的;
    1. method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
    2. # 计算 500 请求比例
    3. # 由于 method 为 put 和 del 的样本找不到匹配项,因此不会出现在结果当中。
    4. {method="get"} 0.04 // 24 / 600
    5. {method="post"} 0.05 // 6 / 120
    • 一对多/多对一匹配,一侧的元素可以与另一侧的多个元素匹配上,可以使用 groupe_left group_right 来控制以哪边为基准返回结果。
    1. method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
    2. # 左边包含2个标签,右边包含1个标签,无法匹配
    3. # 忽略 code 标签则能够进行匹配
    4. # 这个时候左边是多的一边,group_left 使用左边为基准返回
    5. {method="get", code="500"} 0.04 // 24 / 600
    6. {method="get", code="404"} 0.05 // 30 / 600
    7. {method="post", code="500"} 0.05 // 6 / 120
    8. {method="post", code="404"} 0.175 // 21 / 120
  • 算数运算符,+ - * / % ^,算数计算只能用于标量/标量,瞬时向量/标量,瞬时向量/瞬时向量;
    • 标量/标量
    • 瞬时向量/标量:向量每个值都和标量作运算
    • 瞬时向量/瞬时向量
  • 比较运算符,== != < > >= <=
  • 逻辑运算符,and or unless,只用于瞬时向量;
    • v1 and v2 返回v1中完全匹配v2的元素集合,交集
    • v1 or v2 返回v1和v2中没有与v1匹配上的元素集合,并集
    • v1 unless v2 返回v1中没有与v2匹配到的元素集合,差集
  • 聚合运算;
    • group (all values in the resulting vector are 1)
    • stddev 标准差
    • stdvar 方差
    • count 计数
    • count_values 统计出现的次数
      1. count_values("goversion", node_exporter_build_info)
    • bottomk 最小k个
    • topk 最大k个
    • quantile q分位数
    • without by,可以理解成不按照xx分组,按照xx分组:
    1. sum without (job) (go_goroutines)
    2. sum by (instance, job) (go_goroutines)
    3. sum by (job) (go_goroutines)

运算符优先级:

  1. *, /, %, atan2
  2. ==, !=, <=, <, >=, >
  3. and, unless

Functions

Counter指标增长率

  • increase(v range-vector) 计算范围向量内的增长量;
  • rate(v range-vector) 计算范围向量内每秒增长率。应该只用于Counters;
  • irate(v range-vector) 计算范围向量内每秒瞬时增长率,使用的是范围向量最后2个样本数据进行计算;
  1. rate(go_memstats_frees_total[5m])
  2. increase(go_memstats_frees_total[5m]) / 300
  3. irate(go_memstats_frees_total[5m])

increase() rate() 更偏向于平均增长率,而 irate() 是瞬时增长率,各自适合的场景不一样。

Gauge指标

  • predict_linear(v range-vector, t scalar) 预测向量v未来t秒内数据,使用的是 简单线性回归
  1. predict_linear(go_memstats_alloc_bytes[10m], 3600)

Histogram指标分位数

  • histogram_quantile(φ scalar, b instant-vector) 计算瞬时向量b的φ分位数
  1. histogram_quantile(0.9, rate(apiserver_response_sizes_bucket[10m]))

聚合函数

<aggregation>_over_time()

  • avg_over_time(range-vector) : 平均值
  • min_over_time(range-vector) : 最小值
  • max_over_time(range-vector) : 最大值
  • sum_over_time(range-vector) : 求和
  • count_over_time(range-vector) : 计数
  • quantile_over_time(scalar, range-vector) : φ分位数
  • stddev_over_time(range-vector) : 总标准差
  • stdvar_over_time(range-vector) : 总标准方差
  • last_over_time(range-vector) : 最近一个采样点数据
  • present_over_time(range-vector) : 范围内值为1的时间序列

Exporters

官方支持多种硬件、数据库、消息系统、存储等等的支持,可查看官方 支持列表

exporter 用于导出 metric 数据,prometheus 服务来拉取。

Node Exporter

上面提到的 kube-prometheus 部署方式已经默认在集群内部部署了集群节点个数的 node-exporter
配置文件:

  1. node-exporter-clusterRole.yaml
  2. node-exporter-clusterRoleBinding.yaml
  3. node-exporter-daemonset.yaml
  4. node-exporter-prometheusRule.yaml
  5. node-exporter-service.yaml
  6. node-exporter-serviceAccount.yaml
  7. node-exporter-serviceMonitor.yaml

监控集群外虚拟机

node exporter 也支持安装包部署,部署成功默认在 9100 端口暴露 metric 数据。

  1. curl localhost:9100

配置 prometheus

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: external-server
  5. namespace: monitoring
  6. labels:
  7. k8s-app: external-server
  8. spec:
  9. type: ClusterIP
  10. clusterIP: None
  11. ports:
  12. - name: metrics
  13. port: 9100
  14. protocol: TCP
  15. targetPort: 9100
  16. apiVersion: v1
  17. kind: Endpoints
  18. metadata:
  19. name: external-server
  20. labels:
  21. k8s-app: external-server
  22. namespace: monitoring
  23. subsets:
  24. - addresses:
  25. - ip: 192.168.1.125
  26. - ip: 192.168.1.129
  27. - ip: 192.168.1.179
  28. - ip: 192.168.1.119
  29. ports:
  30. - name: metrics
  31. port: 9100
  32. protocol: TCP
  33. apiVersion: monitoring.coreos.com/v1
  34. kind: ServiceMonitor
  35. metadata:
  36. name: external-server
  37. labels:
  38. k8s-app: external-server
  39. namespace: monitoring
  40. spec:
  41. endpoints:
  42. - port: metrics
  43. interval: 30s
  44. scheme: http
  45. selector:
  46. matchLabels:
  47. k8s-app: external-server
  48. namespaceSelector:
  49. matchNames:
  50. - monitoring

可以在 service-discovery 进行查看。

JMX Exporter

JMX Exporter 是一个基于 JVM 应用的一个 exporter,
通过javaagent的方式来进行监控,同时需要配置目标应用的jmx:

  1. # 使用启动参数配置 jmx
  2. -Dcom.sun.management.jmxremote
  3. -Dcom.sun.management.jmxremote.port=9010
  4. -Dcom.sun.management.jmxremote.rmi.port=9010
  5. -Dcom.sun.management.jmxremote.local.only=false
  6. -Dcom.sun.management.jmxremote.authenticate=false
  7. -Dcom.sun.management.jmxremote.ssl=false

配置agent:

  1. # 8080指定的是暴露metric数据的端口
  2. -javaagent:/path/to/your/agent/jmx_prometheus_javaagent-0.16.1.jar=8080:/path/to/your/exporter/config/jmx-exporter-config.yaml"

exporter配置:

  1. startDelaySeconds: 0
  2. # 这里配置的是的目标jmx
  3. hostPort: 127.0.0.1:9010
  4. username:
  5. password:
  6. # jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:1234/jmxrmi
  7. ssl: false
  8. lowercaseOutputName: false
  9. lowercaseOutputLabelNames: false
  10. whitelistObjectNames: ["org.apache.cassandra.metrics:*"]
  11. blacklistObjectNames: ["org.apache.cassandra.metrics:type=ColumnFamily,*"]
  12. rules:
  13. - pattern: 'org.apache.cassandra.metrics<type=(\w+), name=(\w+)><>Value: (\d+)'
  14. name: cassandra_$1_$2
  15. value: $3
  16. valueFactor: 0.001
  17. labels: {}
  18. help: "Cassandra metric $1 $2"
  19. cache: false
  20. type: GAUGE
  21. attrNameSnakeCase: false

配置 ServiceMonitor

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: less-svc
  5. namespace: monitoring
  6. labels:
  7. java-app: less-svc
  8. spec:
  9. type: ClusterIP
  10. clusterIP: None
  11. ports:
  12. - name: jmx
  13. port: 8080
  14. protocol: TCP
  15. targetPort: 8080
  16. selector:
  17. external-app: less-svc
  18. apiVersion: v1
  19. kind: Endpoints
  20. metadata:
  21. name: less-svc
  22. labels:
  23. java-app: less-svc
  24. external-app: less-svc
  25. namespace: monitoring
  26. subsets:
  27. - addresses:
  28. - ip: 192.168.1.39
  29. ports:
  30. - name: jmx
  31. port: 8080
  32. protocol: TCP
  33. apiVersion: monitoring.coreos.com/v1
  34. kind: ServiceMonitor
  35. metadata:
  36. name: java-app
  37. labels:
  38. java-app: less-svc
  39. namespace: monitoring
  40. spec:
  41. endpoints:
  42. - port: jmx
  43. interval: 30s
  44. scheme: http
  45. selector:
  46. matchLabels:
  47. java-app: less-svc
  48. namespaceSelector:
  49. matchNames:
  50. - monitoring

How To Debug ServiceMonitor ?

custom-metrics-elements.png
  1. 检查servicemonitor标签是否成功被Prometheus成功筛选到;
  2. 检查service的标签是否成功被servicemonitor标签筛选到;
  3. 检查Prometheus对目标service是否有权限;
  4. 目标service是否能够正常访问到pod,endpoint是否工作正常;

ServiceMonitor 是否被 Prometheus 筛选到?

查看 配置 中是否有你配置的 job。

Push Metrics

Pushgateway 允许临时和批量任务向prometheus推送 metric 数据。

When to use pushgateway

  • 捕获服务级别的批量任务处理结果,比如获取批量删除一大批的用户的结果;

使用 Pushgateway 的缺陷:

  • 容易单点故障,可能会成为瓶颈;
  • 没有Prometheus示例健康检查;
  • 永远不会删除收到的数据,一直暴露给 Prometheus ,除非手动调用api删除。而正常的拉方式当实例消失的时候会自动删除 metric数据;

备选方案

如果是防火墙或者是NAT导致prometheus无法拉取数据,可以使用 PushProx 让 Prometheus穿透NAT或者防火墙,正常的拉取数据。

Deploy Pushgateway & Push metrics

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. labels:
  5. app: prome-push-gateway
  6. name: prome-push-gateway
  7. namespace: monitoring
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: prome-push-gateway
  13. template:
  14. metadata:
  15. labels:
  16. app: prome-push-gateway
  17. spec:
  18. containers:
  19. - image: prom/pushgateway:v1.4.2
  20. name: prome-push-gateway
  21. imagePullPolicy: IfNotPresent
  22. ports:
  23. - containerPort: 9091
  24. - name: less-svc_hazelcast_kubernetes_namespace
  25. value: "product"
  26. # pod service
  27. apiVersion: v1
  28. kind: Service
  29. metadata:
  30. labels:
  31. app: prome-push-gateway
  32. name: prome-push-gateway
  33. namespace: monitoring
  34. spec:
  35. selector:
  36. app: prome-push-gateway
  37. ports:
  38. - name: push
  39. port: 9091
  40. targetPort: 9091
  41. protocol: TCP
  42. # ingress
  43. apiVersion: extensions/v1beta1
  44. kind: Ingress
  45. metadata:
  46. name: prome-push-gateway-ingress
  47. namespace: monitoring
  48. annotations:
  49. spec:
  50. rules:
  51. - http:
  52. paths:
  53. - path: /
  54. backend:
  55. serviceName: prome-push-gateway
  56. servicePort: push
  57. host: pushgateway.minei.test
  58. apiVersion: monitoring.coreos.com/v1
  59. kind: ServiceMonitor
  60. metadata:
  61. name: push-gateway
  62. namespace: monitoring
  63. spec:
  64. endpoints:
  65. - port: push
  66. interval: 30s
  67. scheme: http
  68. # pushgateway 的 monitor需要将该配置设置为 true,否则 job 将会被 exported_job 替代
  69. # 同样 instance 也会被 exported_instance 替代
  70. honorLabels: true
  71. selector:
  72. matchLabels:
  73. app: prome-push-gateway
  74. namespaceSelector:
  75. matchNames:
  76. - monitoring

大部分exporters都不支持pushgateway,所以需要自己push metric数据。

Pushgateway 支持类似 restful 的metric api,同时也支持admin api。

push一个metric数据(注意所有的换行都是 \n ,结尾也需要一个 \n 可以参考官方的客户端数据格式说明:
Prometheus Client Data Exposition Format ):

  1. # TYPE test_metric counter
  2. test_metric{label="val1"} 42
  3. # TYPE another_metric gauge
  4. # HELP another_metric Just an example.
  5. another_metric 2398.283

查询metric:

  1. curl http://pushgateway.minei.test/api/v1/metrics

Pushgateway在 /metrics 暴露了所有的metrics数据,所以metric定义一定不能出现冲突,比如相同名称的metric必须有相同的类型和标签,如果冲突了push数据的时候会返回400。

Java Client

DataStorage

Prometheus支持本地存储和远程存储系统。

容器中默认的数据存储结构:

  1. ./prometheus
  2. ├── 01BKGV7JBM69T2G1BGBGM6KB12
  3. │ └── meta.json
  4. ├── 01BKGTZQ1SYQJTR4PB43C8PD98
  5. │ ├── chunks
  6. │ │ └── 000001
  7. │ ├── tombstones
  8. │ ├── index
  9. │ └── meta.json
  10. ├── 01BKGTZQ1HHWHV8FBJXW1Y3W0K
  11. │ └── meta.json
  12. ├── 01BKGV7JC0RY8A6MACW02A2PJD
  13. │ ├── chunks
  14. │ │ └── 000001
  15. │ ├── tombstones
  16. │ ├── index
  17. │ └── meta.json
  18. ├── chunks_head
  19. │ └── 000001
  20. └── wal
  21. ├── 000000002
  22. └── checkpoint.00000001
  23. └── 00000000
  • 数据按照2h分为一组(block);
    • chunks 文件夹里存储的是实际时序数据,默认512m为一个文件进行存储( segment );
    • 通过api删除的数据存储在 tombstones
    • metadata;
    • index索引文件,索引的是chunks文件夹里metric名称和标签;
  • 当前采集到的数据是在内存中,并未完全持久化到文件,使用 WAL (wirte-ahead log) 加密存储在 wal 文件夹中,即使服务崩溃或者重启也能恢复内存中的数据;
    • wal 中 128m 为一个文件,并且尚未经过压缩,
  • 数据保留时间,operator配置在 Prometheus.spec.retention 下,默认24h;
  • block占用空间大小,operator配置在 Prometheus.spec.retentionSize 下;
  • wal压缩,operator配置在 Prometheus.spec.walCompression 下,稍微占用cpu;

如果保留时间和大小同时配置了,哪个先触发就先使用哪个,过期的Block清理发生在后台。同时,Block只有在完全过期了才会被移除。

Prometheus每个数据平均占用空间为 1-2 bytes,可以用下面的公式来粗略计算存储占用:

  1. needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample

数据抓取频率可以在servicemonitor中进行配置:ServiceMonitor.spec.endpoints.interval

If your local storage becomes corrupted for whatever reason, the best strategy to address the problem is to shut down Prometheus then remove the entire storage directory. You can also try removing individual block directories, or the WAL directory to resolve the problem. Note that this means losing approximately two hours data per block directory. Again, Prometheus’s local storage is not intended to be durable long-term storage; external solutions offer extended retention and data durability.

  1. apiVersion: monitoring.coreos.com/v1
  2. kind: Prometheus
  3. metadata:
  4. labels:
  5. prometheus: k8s
  6. name: k8s
  7. namespace: monitoring
  8. spec:
  9. alerting:
  10. alertmanagers:
  11. - name: alertmanager-main
  12. namespace: monitoring
  13. port: web
  14. image: quay.io/prometheus/prometheus:v2.22.1
  15. nodeSelector:
  16. kubernetes.io/os: linux
  17. podMonitorNamespaceSelector: {}
  18. podMonitorSelector: {}
  19. probeNamespaceSelector: {}
  20. probeSelector: {}
  21. replicas: 2
  22. resources:
  23. requests:
  24. memory: 400Mi
  25. ruleSelector:
  26. matchLabels:
  27. prometheus: k8s
  28. role: alert-rules
  29. securityContext:
  30. fsGroup: 2000
  31. runAsNonRoot: true
  32. runAsUser: 1000
  33. serviceAccountName: prometheus-k8s
  34. serviceMonitorNamespaceSelector: {}
  35. serviceMonitorSelector: {}
  36. version: v2.22.1
  37. # 数据保留时间和最大存储配置
  38. retention: 30d
  39. retentionSize: 1GB
  40. storage:
  41. # 存储配置
  42. volumeClaimTemplate:
  43. spec:
  44. storageClassName: nfs-storage
  45. resources:
  46. requests:
  47. storage: 1Gi
  48. accessModes:
  49. - ReadWriteOnce

Pushgateway Storage

Pushgateway默认不持久化数据,可以使用 --persistence.file 来配置持久化的文件。

Remote Storage

  • remote write,配置位于 Prometheus.spec.remoteRead
  • remote read,配置位于 Prometheus.spec.remoteRead
    • 远程读取只读取了原始数据和标签,所有的操作还是在Prometheus服务器进行的。
  • receive from other Prometheus server,内置receiver通过 --enable-feature=remote-write-receiver 来开启,路径是:/api/v1/write

Remote Storage List

AlertManager

配置告警和通知流程:

  1. 配置和部署 Alertmanager;
  2. Configure Prometheus to talk to the Alertmanager 在Prometheus中配置 Alertmanager;
  3. Prometheus中配置规则;
  1. load alertmanager
  2. Prometheus -------------------> Alertmanager
  3. ↓ alerting ↓
  4. PrometheusRule AlertmanagerConfig

Alertmanager配置包含3部分:

  • 抑制(Inhibition)规则:在与另一组匹配器匹配的告警存在的情况下使另一组匹配器告警规则失效的规则,两组匹配器必须要有一组相同的标签;
  • 通知接收者(receivers)配置;
  • 通知路由(route)配置;

receivers支持多种通知方式,email、webhook、wechat等等。
Alertmanager通过 Alertmanager.spec.alertmanagerConfigNamespaceSelector Alertmanager.spec.alertmanagerConfigSelector 来筛选配置。

  1. apiVersion: monitoring.coreos.com/v1alpha1
  2. kind: AlertmanagerConfig
  3. metadata:
  4. name: alertmanager-config
  5. namespace: monitoring
  6. labels:
  7. alertmanagerConfig: test
  8. spec:
  9. route:
  10. groupBy: ['instance']
  11. groupWait: 30s
  12. groupInterval: 5m
  13. repeatInterval: 12h
  14. receiver: 'pushover'
  15. matchers:
  16. - name: app
  17. value: less-svc
  18. receivers:
  19. - name: 'pushover'
  20. pushoverConfigs:
  21. userKey:
  22. name: pushover-userkey
  23. key: userkey
  24. title: Alert
  25. token:
  26. name: pushover-userkey
  27. key: token
  28. apiVersion: v1
  29. kind: Secret
  30. type: Opaque
  31. metadata:
  32. name: pushover-userkey
  33. namespace: monitoring
  34. data:
  35. userkey: xxx
  36. token: xxx

配置Alertmanager:

  1. apiVersion: monitoring.coreos.com/v1
  2. kind: Alertmanager
  3. metadata:
  4. labels:
  5. alertmanager: main
  6. name: main
  7. namespace: monitoring
  8. spec:
  9. # 一定要配置,否则无法正确加载到配置
  10. alertmanagerConfigSelector:
  11. matchLabels:
  12. alertmanagerConfig: test
  13. image: quay.io/prometheus/alertmanager:v0.21.0
  14. nodeSelector:
  15. kubernetes.io/os: linux
  16. replicas: 3
  17. securityContext:
  18. fsGroup: 2000
  19. runAsNonRoot: true
  20. runAsUser: 1000
  21. serviceAccountName: alertmanager-main
  22. version: v0.21.0

Prometheus 通过 Prometheus.spec.alerting 来配置alertmanager,通过 Prometheus.spec.ruleNamespaceSelectorPrometheus.spec.ruleSelector 来配置rule。

Prometheus Rules

Prometheus 包含两种规则,一种是 RecordingRules, 一种是 AlertingRules。

RecordingRules

记录规则提供了 提前计算经常需要用的数据 或者 计算量大 的表达式,并且把计算结果保存到新的时序数据中,常见的就是一些复杂的监控面板数据。

AlertingRules

通过Prome表达式来定义报警条件,同时发送通知。

PrometheusRule.spec.groups.rules

Field Description Scheme Required For
record record rules metric name string false Recording
alert alerting rules name string false Alerting
expr 表达式 intstr.IntOrString true Both
for 触发表达式后告警前等待时间 string false Alerting
labels 标签,覆盖方式添加到metric或者alert map[string]string false Both
annotations 添加到alert map[string]string false Alerting

Templates

告警中使用的模板基于 Go templating

  1. apiVersion: monitoring.coreos.com/v1
  2. kind: PrometheusRule
  3. metadata:
  4. name: prometheus-alert-rules
  5. namespace: monitoring
  6. labels:
  7. prometheus: k8s
  8. role: alert-rules
  9. spec:
  10. groups:
  11. - name: test.rules
  12. rules:
  13. - alert: TestAppOffline
  14. expr: count without() (up{endpoint="jmx", job="less-svc"}) == 0
  15. for: 1m
  16. labels:
  17. app: less-svc
  18. annotations:
  19. # 注意如果模板中需要使用标签,那么表达式最终结果也是需要带上这些标签的
  20. description: app {{ $labels.job }} offline, instance {{ $labels.instance }}

Security

Exporters & Pushgateway

官方exporters和pushgateway支持tls和basic authentication,可以通过启动参数指定配置 --web.config.file="web-config.yml"

  1. tls_server_config:
  2. # Certificate and key files for server to use to authenticate to client.
  3. cert_file: <filename>
  4. key_file: <filename>
  5. # Server policy for client authentication. Maps to ClientAuth Policies.
  6. # For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType)
  7. [ client_auth_type: <string> | default = "NoClientCert" ]
  8. # CA certificate for client certificate authentication to the server.
  9. [ client_ca_file: <filename> ]
  10. # Minimum TLS version that is acceptable.
  11. [ min_version: <string> | default = "TLS12" ]
  12. # Maximum TLS version that is acceptable.
  13. [ max_version: <string> | default = "TLS13" ]
  14. # List of supported cipher suites for TLS versions up to TLS 1.2. If empty,
  15. # Go default cipher suites are used. Available cipher suites are documented
  16. # in the go documentation:
  17. # https://golang.org/pkg/crypto/tls/#pkg-constants
  18. [ cipher_suites:
  19. [ - <string> ] ]
  20. # prefer_server_cipher_suites controls whether the server selects the
  21. # client's most preferred ciphersuite, or the server's most preferred
  22. # ciphersuite. If true then the server's preference, as expressed in
  23. # the order of elements in cipher_suites, is used.
  24. [ prefer_server_cipher_suites: <bool> | default = true ]
  25. # Elliptic curves that will be used in an ECDHE handshake, in preference
  26. # order. Available curves are documented in the go documentation:
  27. # https://golang.org/pkg/crypto/tls/#CurveID
  28. [ curve_preferences:
  29. [ - <string> ] ]
  30. http_server_config:
  31. # Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS.
  32. # This can not be changed on the fly.
  33. [ http2: <bool> | default = true ]
  34. # Usernames and hashed passwords that have full access to the web
  35. # server via basic authentication. If empty, no basic authentication is
  36. # required. Passwords are hashed with bcrypt.
  37. basic_auth_users:
  38. [ <string>: <secret> ... ]

同时在servicemonitor中 servicemonitor.spec.endpoints.tlsConfig 配置抓取的tls信息,servicemonitor.spec.endpoints.basicAuth 配置basic authentication。

API Security

管理相关的API旨在使用简单的cURL工具访问,所以并没有做CSRF保护。在向外部不可信用户暴露的时候可以使用反向代理来避免CSRF,
对一些不信任的输入进行进行转义。

Pushgateway

由于一般都开启了 honor_labels ,所以能够访问到Pushgateway的用户都能创建任意的时间序列。
如果开启了 --web.enable-admin-api 则可以通过admin api操作任意的数据。

Best Practices

Naming

指标命名:

  • 符合模型 定义
  • 有一个单词前缀,这个单词可以是应用名称、ns、也可以是某一类通用标准指标,比如:prometheus_api_remote_read_queries process_cpu_seconds_total http_request_duration_seconds
  • 必须有一个复数单位作为后缀,或者是 total 后缀作为计数:http_request_duration_seconds node_memory_usage_bytes http_requests_total foobar_build_info
  • 应该代表在所有标签维度上测量的相同逻辑事物

使用标签来区分被观测事物的特征:

  • node_cpu_seconds_total 区分不同状态:idle,iowait,irq,nice,softirq,steal,system,user
  • http_request_duration_milliseconds 区分不同的状态码:200,302等
  • 不能使用标签来存储无限制的值集合,比如用户id,邮箱等等

基础单位:

Family Base unit Remark
Time seconds
Temperature celsius celsius is preferred over kelvin for practical reasons. kelvin is acceptable as a base unit in special cases like color temperature or where temperature has to be absolute.
Length meters
Bytes bytes
Bits bytes To avoid confusion combining different metrics, always use bytes, even where bits appear more common.
Percent ratio Values are 0–1 (rather than 0–100). ratio is only used as a suffix for names like disk_usage_ratio. The usual metric name follows the pattern A_per_B.
Voltage volts
Electric current amperes
Energy joules
Power Prefer exporting a counter of joules, then rate(joules[5m]) gives you power in Watts.
Mass grams grams is preferred over kilograms to avoid issues with the kilo prefix.

Recording rules

复合 level:metric:operations 的命名规则:

  • level代表聚合级别和标签
  • metric代表指标名称,除了使用 rate()irate() 的时候应该保持不变
  • operations代表的是操作列表,使用最新的操作

HISTOGRAMS AND SUMMARIES

/ Histogram Summary
配置 选择适合观察值的预期范围的bucket 选择所需的 φ 分位数和滑动窗口。 其他未选择的 φ 分位数和滑动窗口无法稍后计算。
客户端性能 由于只需要counters,所以不怎么消耗性能 计算流分位数非常消耗性能
服务器性能 需要服务器来计算q分位数,很消耗性能,但是可以使用recording rules来预计算 性能消耗小
时间序列数量 (除了 _sum 和 _count 序列) 每一个bucket都有一个序列 每一个配置的分位数都有一个序列
分位数误差 (see below for details) 选择合适的buckets Error is limited in the dimension of φ by a configurable value.
φ分位数和滑动窗口定义 通过PromeQL定义 通过客户端定义
聚合 可通过PromeQL聚合 一般不可聚合
查询方式 histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) http_request_duration_seconds_summary{quantile="0.95"}

histogram_quantile 采用线性插值:

70043870-3a2a1600-15fc-11ea-92a1-c3cbdcbaa785.png

计算方式:分位值=起始bucket大小+(本bucket宽度)*(目标分位数在本bucket排行/本bucket记录数)

如果bucket选择合适,那么得到的分位数误差就较小。

  1. prometheus_http_request_duration_seconds_bucket{le="0.05"} 199881
  2. prometheus_http_request_duration_seconds_bucket{le="0.1"} 212210
  3. prometheus_http_request_duration_seconds_bucket{le="0.2"} 215395
  4. prometheus_http_request_duration_seconds_bucket{le="0.4"} 319435
  5. prometheus_http_request_duration_seconds_bucket{le="0.8"} 419576
  6. prometheus_http_request_duration_seconds_bucket{le="1.6"} 469593
  7. prometheus_http_request_duration_seconds_bucket{le="+Inf"} 519593
  8. # 计算0.75分位数
  9. 0.75 * 519593 = 389694.75 位于 0.4~0.8之间
  10. 0.4 + (0.8-0.4) * ((389694.75 - 319435) / (419576 - 319435))

92f416a6f45dd28ad7711e745b66d8c747817855

如何选择:

  • 需要聚合选择 Histogram
  • 如果了解观测值的分布那么选择 Histogram;如果需要准确的分位数选择 Summary

Grafana

Datasource

支持多种数据源,通过kube-prometheus安装的时候已经集成了Prometheus数据源。

  1. -rw-r--r--. 1 root root 550 Oct 27 10:37 grafana-dashboardDatasources.yaml # 配置数据源
  2. -rw-r--r--. 1 root root 1403539 Oct 27 10:37 grafana-dashboardDefinitions.yaml # 配置面板
  3. -rw-r--r--. 1 root root 454 Oct 27 10:37 grafana-dashboardSources.yaml
  4. -rw-r--r--. 1 root root 7629 Oct 27 10:37 grafana-deployment.yaml
  5. -rw-r--r--. 1 root root 86 Oct 27 10:37 grafana-serviceAccount.yaml
  6. -rw-r--r--. 1 root root 208 Oct 27 10:37 grafana-serviceMonitor.yaml
  7. -rw-r--r--. 1 root root 201 Oct 27 10:37 grafana-service.yaml

Dashboards

支持json导入,手动配置,配置文件配置,官方面板应用商城 id导入。

  1. Default
  2. ├── DashBoard
  3. │ ├── panel1
  4. │ │ └── query
  5. | | └── alert
  6. │ ├── panel2
  7. │ │ └── query
  8. | | └── alert
  9. General
  10. │ ├── panel3
  11. │ │ └── query
  12. | | └── alert
  13. │ ├── panel4
  14. │ │ └── query
  15. | | └── alert

Alert

告警配置跟随面板一起配置的:

  • 触发频率;
  • 触发条件;
  • 没有数据或者出现异常如何处理;
  • 通知内容和标签设置;
  • 设置receiver;

版权所有丨转载请注明出处:https://minei.me/archives/cloud-native-monitoring-notes.html

Build with ♥

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK