Cloud Native Monitoring
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:
组件:
- 抓取,读取时序数据的后端服务;
- 客户端;
- 支持短生命周期任务的
Pushgateway
; - 用于服务导出数据的
Exporter
; - 告警系统;
- 多种支持工具;
Metric DataModel
Metric Definition:
<metric name>{<label name>=<label value>, ...} value [timestamp]
# e.g.
api_http_requests_total{method="POST", handler="/messages"} 5 1395066363000
Text Data Format
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 1871.15625
文本协议基于 行
,忽略空行,使用 \n
分割,最后一行必须是换行符。
#
是注释行,但是如果后面是 HELP
和 TYPE
:
HELP
那么后面需要一个 metric 名称,其他则是相关的注释,同时一个 metric 只能有一个HELP
行;TYPE
后面需要一个 metric 名称,紧接着是 metric 类型,类型是非必填,如果不填写则默认为untyped
;
# 时间戳是UTC毫秒时间戳
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
观察到的事件总数;
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 2.83e-05
go_gc_duration_seconds{quantile="0.25"} 6.83e-05
go_gc_duration_seconds{quantile="0.5"} 8.95e-05
go_gc_duration_seconds{quantile="0.75"} 0.0001084
go_gc_duration_seconds{quantile="1"} 0.000557999
go_gc_duration_seconds_sum 0.203637424
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
中进行配置:
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
labels:
prometheus: k8s
name: k8s
namespace: monitoring
spec:
# 默认没有进行配置,可以对所有 ns 和 monitor进行监控
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorNamespaceSelector: {}
podMonitorSelector: {}
Deploy
kubernetes 部署方式支持 operator
和 kube-prometheus
,
这里使用 kube-prometheus 来进行部署。
# 安装 operator
kubectl create -f manifests/setup
# 安装 prometheus 服务端和各个组件
kubectl create -f manifests/
需要注意的是上面的配置文件创建在 monitoring
命名空间下,同时为了支持跨 ns 的监控需要修改服务端的权限配置,
prometheus-clusterRole.yaml :
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-k8s
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
- nonResourceURLs:
- /metrics
verbs:
- get
- apiGroups:
- ""
# 资源和操作权限
resources:
- services
- pods
- endpoints
verbs:
- get
- list
- watch
部署成功后默认配置了下面的 service
:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
alertmanager-main ClusterIP 10.233.43.107 <none> 9093/TCP 9d
alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 9d
grafana ClusterIP 10.233.24.21 <none> 3000/TCP 9d
kube-state-metrics ClusterIP None <none> 8443/TCP,9443/TCP 9d
node-exporter ClusterIP None <none> 9100/TCP 9d
prometheus-adapter ClusterIP 10.233.7.187 <none> 443/TCP 9d
prometheus-k8s ClusterIP 10.233.31.173 <none> 9090/TCP 9d
prometheus-operated ClusterIP None <none> 9090/TCP 9d
prometheus-operator ClusterIP None <none> 8443/TCP 9d
需要关注的是下面几个 service
:
alertmanager-main
;grafana
;node-exporter
k8s集群节点exporter
(每个节点都部署了一个);prometheus-k8s
;
先将所有的ui服务通过ingress暴露出来:
# ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: monitor-ingress
namespace: monitoring
annotations:
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: prometheus-k8s
servicePort: web
host: prome.minei.test
- http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: http
host: grafana.minei.test
- http:
paths:
- path: /
backend:
serviceName: alertmanager-main
servicePort: web
host: alert.minei.test
Querying
PromQL数据类型:
- Instant Vector 一组时间序列,每个时间序列包含一个样本,所有时间序列都共享相同的时间戳;
- Range Vector 一组时间序列,包含每个时间序列随时间变化的数据点范围
- Scalar 简单的数字浮点值
- String 字符串,尚未使用
字面量:
"
'
`
都可以用来声明字符串;23
-2.43
3.4e-9
0x8f
-Inf
NaN
浮点字面量;
选择器:
- 瞬时向量选择器
node_cpu_seconds_total{instance="master-1-145", cpu="1"}
- 运算符支持
=
!=
=~
!~
,后面两种是正则表达式; - 同时支持
__name__
来筛选metric;# 筛选所有test开头的metric {__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
# 筛选master-145上1m10s内cpu的使用时间 node_cpu_seconds_total{instance="master-1-145"}[1m10s]
offset
修饰符,将选择器中当前时间进行偏移,必须紧跟在选择器之后;# 如果当前时间是 21:00 那么下面查询的就是 20:00 之前的数据 node_cpu_seconds_total{instance="master-1-145"} offset 1h # 不合法 sum(node_cpu_seconds_total{instance="master-1-145"}) offset 1m
@
修饰符,用来选择某个时间戳的数据,也需要紧跟在选择器之后;node_cpu_seconds_total{instance="master-1-145"} @ 1609746000 # 不合法 sum(node_cpu_seconds_total{instance="master-1-145"}) @ 1609746000
Operators
- 向量匹配,
ignoring
可以在匹配时忽略指定标签,而on
可以指定匹配的标签;method_code:http_errors:rate5m{method="get", code="500"} 24 method_code:http_errors:rate5m{method="get", code="404"} 30 method_code:http_errors:rate5m{method="put", code="501"} 3 method_code:http_errors:rate5m{method="post", code="500"} 6 method_code:http_errors:rate5m{method="post", code="404"} 21 method:http_requests:rate5m{method="get"} 600 method:http_requests:rate5m{method="del"} 34 method:http_requests:rate5m{method="post"} 120
- 一对一匹配,如果有相同的标签集合和值,那么他们就是匹配的;
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m # 计算 500 请求比例 # 由于 method 为 put 和 del 的样本找不到匹配项,因此不会出现在结果当中。 {method="get"} 0.04 // 24 / 600 {method="post"} 0.05 // 6 / 120
- 一对多/多对一匹配,一侧的元素可以与另一侧的多个元素匹配上,可以使用
groupe_left
group_right
来控制以哪边为基准返回结果。
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m # 左边包含2个标签,右边包含1个标签,无法匹配 # 忽略 code 标签则能够进行匹配 # 这个时候左边是多的一边,group_left 使用左边为基准返回 {method="get", code="500"} 0.04 // 24 / 600 {method="get", code="404"} 0.05 // 30 / 600 {method="post", code="500"} 0.05 // 6 / 120 {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匹配到的元素集合,差集
- 聚合运算;
- sum
- min
- max
- avg
- group (all values in the resulting vector are 1)
- stddev 标准差
- stdvar 方差
- count 计数
- count_values 统计出现的次数
count_values("goversion", node_exporter_build_info)
- bottomk 最小k个
- topk 最大k个
- quantile q分位数
without
by
,可以理解成不按照xx分组,按照xx分组:
sum without (job) (go_goroutines) sum by (instance, job) (go_goroutines) sum by (job) (go_goroutines)
运算符优先级:
- ^
- *, /, %, atan2
- +, -
- ==, !=, <=, <, >=, >
- and, unless
- or
Functions
Counter指标增长率
increase(v range-vector)
计算范围向量内的增长量;rate(v range-vector)
计算范围向量内每秒增长率。应该只用于Counters;irate(v range-vector)
计算范围向量内每秒瞬时增长率,使用的是范围向量最后2个样本数据进行计算;
rate(go_memstats_frees_total[5m])
increase(go_memstats_frees_total[5m]) / 300
irate(go_memstats_frees_total[5m])
increase()
rate()
更偏向于平均增长率,而 irate()
是瞬时增长率,各自适合的场景不一样。
Gauge指标
predict_linear(v range-vector, t scalar)
预测向量v未来t秒内数据,使用的是 简单线性回归
predict_linear(go_memstats_alloc_bytes[10m], 3600)
Histogram指标分位数
histogram_quantile(φ scalar, b instant-vector)
计算瞬时向量b的φ分位数
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
。
配置文件:
node-exporter-clusterRole.yaml
node-exporter-clusterRoleBinding.yaml
node-exporter-daemonset.yaml
node-exporter-prometheusRule.yaml
node-exporter-service.yaml
node-exporter-serviceAccount.yaml
node-exporter-serviceMonitor.yaml
监控集群外虚拟机
node exporter 也支持安装包部署,部署成功默认在 9100
端口暴露 metric 数据。
curl localhost:9100
配置 prometheus
:
apiVersion: v1
kind: Service
metadata:
name: external-server
namespace: monitoring
labels:
k8s-app: external-server
spec:
type: ClusterIP
clusterIP: None
ports:
- name: metrics
port: 9100
protocol: TCP
targetPort: 9100
---
apiVersion: v1
kind: Endpoints
metadata:
name: external-server
labels:
k8s-app: external-server
namespace: monitoring
subsets:
- addresses:
- ip: 192.168.1.125
- ip: 192.168.1.129
- ip: 192.168.1.179
- ip: 192.168.1.119
ports:
- name: metrics
port: 9100
protocol: TCP
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: external-server
labels:
k8s-app: external-server
namespace: monitoring
spec:
endpoints:
- port: metrics
interval: 30s
scheme: http
selector:
matchLabels:
k8s-app: external-server
namespaceSelector:
matchNames:
- monitoring
可以在 service-discovery 进行查看。
JMX Exporter
JMX Exporter 是一个基于 JVM 应用的一个 exporter,
通过javaagent的方式来进行监控,同时需要配置目标应用的jmx:
# 使用启动参数配置 jmx
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.rmi.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
配置agent:
# 8080指定的是暴露metric数据的端口
-javaagent:/path/to/your/agent/jmx_prometheus_javaagent-0.16.1.jar=8080:/path/to/your/exporter/config/jmx-exporter-config.yaml"
exporter配置:
---
startDelaySeconds: 0
# 这里配置的是的目标jmx
hostPort: 127.0.0.1:9010
username:
password:
# jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:1234/jmxrmi
ssl: false
lowercaseOutputName: false
lowercaseOutputLabelNames: false
whitelistObjectNames: ["org.apache.cassandra.metrics:*"]
blacklistObjectNames: ["org.apache.cassandra.metrics:type=ColumnFamily,*"]
rules:
- pattern: 'org.apache.cassandra.metrics<type=(\w+), name=(\w+)><>Value: (\d+)'
name: cassandra_$1_$2
value: $3
valueFactor: 0.001
labels: {}
help: "Cassandra metric $1 $2"
cache: false
type: GAUGE
attrNameSnakeCase: false
配置 ServiceMonitor
:
apiVersion: v1
kind: Service
metadata:
name: less-svc
namespace: monitoring
labels:
java-app: less-svc
spec:
type: ClusterIP
clusterIP: None
ports:
- name: jmx
port: 8080
protocol: TCP
targetPort: 8080
selector:
external-app: less-svc
---
apiVersion: v1
kind: Endpoints
metadata:
name: less-svc
labels:
java-app: less-svc
external-app: less-svc
namespace: monitoring
subsets:
- addresses:
- ip: 192.168.1.39
ports:
- name: jmx
port: 8080
protocol: TCP
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: java-app
labels:
java-app: less-svc
namespace: monitoring
spec:
endpoints:
- port: jmx
interval: 30s
scheme: http
selector:
matchLabels:
java-app: less-svc
namespaceSelector:
matchNames:
- monitoring
How To Debug ServiceMonitor ?
- 检查servicemonitor标签是否成功被Prometheus成功筛选到;
- 检查service的标签是否成功被servicemonitor标签筛选到;
- 检查Prometheus对目标service是否有权限;
- 目标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
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: prome-push-gateway
name: prome-push-gateway
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: prome-push-gateway
template:
metadata:
labels:
app: prome-push-gateway
spec:
containers:
- image: prom/pushgateway:v1.4.2
name: prome-push-gateway
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9091
env:
- name: less-svc_hazelcast_kubernetes_namespace
value: "product"
---
# pod service
apiVersion: v1
kind: Service
metadata:
labels:
app: prome-push-gateway
name: prome-push-gateway
namespace: monitoring
spec:
selector:
app: prome-push-gateway
ports:
- name: push
port: 9091
targetPort: 9091
protocol: TCP
---
# ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: prome-push-gateway-ingress
namespace: monitoring
annotations:
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: prome-push-gateway
servicePort: push
host: pushgateway.minei.test
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: push-gateway
namespace: monitoring
spec:
endpoints:
- port: push
interval: 30s
scheme: http
# pushgateway 的 monitor需要将该配置设置为 true,否则 job 将会被 exported_job 替代
# 同样 instance 也会被 exported_instance 替代
honorLabels: true
selector:
matchLabels:
app: prome-push-gateway
namespaceSelector:
matchNames:
- monitoring
大部分exporters都不支持pushgateway,所以需要自己push metric数据。
Pushgateway 支持类似 restful 的metric api,同时也支持admin api。
push一个metric数据(注意所有的换行都是 \n
,结尾也需要一个 \n
可以参考官方的客户端数据格式说明:
Prometheus Client Data Exposition Format ):
# TYPE test_metric counter
test_metric{label="val1"} 42
# TYPE another_metric gauge
# HELP another_metric Just an example.
another_metric 2398.283
查询metric:
curl http://pushgateway.minei.test/api/v1/metrics
Pushgateway在 /metrics
暴露了所有的metrics数据,所以metric定义一定不能出现冲突,比如相同名称的metric必须有相同的类型和标签,如果冲突了push数据的时候会返回400。
DataStorage
Prometheus支持本地存储和远程存储系统。
容器中默认的数据存储结构:
./prometheus
├── 01BKGV7JBM69T2G1BGBGM6KB12
│ └── meta.json
├── 01BKGTZQ1SYQJTR4PB43C8PD98
│ ├── chunks
│ │ └── 000001
│ ├── tombstones
│ ├── index
│ └── meta.json
├── 01BKGTZQ1HHWHV8FBJXW1Y3W0K
│ └── meta.json
├── 01BKGV7JC0RY8A6MACW02A2PJD
│ ├── chunks
│ │ └── 000001
│ ├── tombstones
│ ├── index
│ └── meta.json
├── chunks_head
│ └── 000001
└── wal
├── 000000002
└── checkpoint.00000001
└── 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,可以用下面的公式来粗略计算存储占用:
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.
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
labels:
prometheus: k8s
name: k8s
namespace: monitoring
spec:
alerting:
alertmanagers:
- name: alertmanager-main
namespace: monitoring
port: web
image: quay.io/prometheus/prometheus:v2.22.1
nodeSelector:
kubernetes.io/os: linux
podMonitorNamespaceSelector: {}
podMonitorSelector: {}
probeNamespaceSelector: {}
probeSelector: {}
replicas: 2
resources:
requests:
memory: 400Mi
ruleSelector:
matchLabels:
prometheus: k8s
role: alert-rules
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: prometheus-k8s
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
version: v2.22.1
# 数据保留时间和最大存储配置
retention: 30d
retentionSize: 1GB
storage:
# 存储配置
volumeClaimTemplate:
spec:
storageClassName: nfs-storage
resources:
requests:
storage: 1Gi
accessModes:
- 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
AlertManager
配置告警和通知流程:
- 配置和部署 Alertmanager;
- Configure Prometheus to talk to the Alertmanager 在Prometheus中配置 Alertmanager;
- Prometheus中配置规则;
load alertmanager
Prometheus -------------------> Alertmanager
↓ alerting ↓
↓ ↓
PrometheusRule AlertmanagerConfig
Alertmanager配置包含3部分:
- 抑制(Inhibition)规则:在与另一组匹配器匹配的告警存在的情况下使另一组匹配器告警规则失效的规则,两组匹配器必须要有一组相同的标签;
- 通知接收者(receivers)配置;
- 通知路由(route)配置;
receivers支持多种通知方式,email、webhook、wechat等等。
Alertmanager通过 Alertmanager.spec.alertmanagerConfigNamespaceSelector
Alertmanager.spec.alertmanagerConfigSelector
来筛选配置。
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: alertmanager-config
namespace: monitoring
labels:
alertmanagerConfig: test
spec:
route:
groupBy: ['instance']
groupWait: 30s
groupInterval: 5m
repeatInterval: 12h
receiver: 'pushover'
matchers:
- name: app
value: less-svc
receivers:
- name: 'pushover'
pushoverConfigs:
userKey:
name: pushover-userkey
key: userkey
title: Alert
token:
name: pushover-userkey
key: token
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: pushover-userkey
namespace: monitoring
data:
userkey: xxx
token: xxx
配置Alertmanager:
apiVersion: monitoring.coreos.com/v1
kind: Alertmanager
metadata:
labels:
alertmanager: main
name: main
namespace: monitoring
spec:
# 一定要配置,否则无法正确加载到配置
alertmanagerConfigSelector:
matchLabels:
alertmanagerConfig: test
image: quay.io/prometheus/alertmanager:v0.21.0
nodeSelector:
kubernetes.io/os: linux
replicas: 3
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: alertmanager-main
version: v0.21.0
Prometheus 通过 Prometheus.spec.alerting
来配置alertmanager,通过 Prometheus.spec.ruleNamespaceSelector
和 Prometheus.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。
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: prometheus-alert-rules
namespace: monitoring
labels:
prometheus: k8s
role: alert-rules
spec:
groups:
- name: test.rules
rules:
- alert: TestAppOffline
expr: count without() (up{endpoint="jmx", job="less-svc"}) == 0
for: 1m
labels:
app: less-svc
annotations:
# 注意如果模板中需要使用标签,那么表达式最终结果也是需要带上这些标签的
description: app {{ $labels.job }} offline, instance {{ $labels.instance }}
Security
Exporters & Pushgateway
官方exporters和pushgateway支持tls和basic authentication,可以通过启动参数指定配置 --web.config.file="web-config.yml"
:
tls_server_config:
# Certificate and key files for server to use to authenticate to client.
cert_file: <filename>
key_file: <filename>
# Server policy for client authentication. Maps to ClientAuth Policies.
# For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType)
[ client_auth_type: <string> | default = "NoClientCert" ]
# CA certificate for client certificate authentication to the server.
[ client_ca_file: <filename> ]
# Minimum TLS version that is acceptable.
[ min_version: <string> | default = "TLS12" ]
# Maximum TLS version that is acceptable.
[ max_version: <string> | default = "TLS13" ]
# List of supported cipher suites for TLS versions up to TLS 1.2. If empty,
# Go default cipher suites are used. Available cipher suites are documented
# in the go documentation:
# https://golang.org/pkg/crypto/tls/#pkg-constants
[ cipher_suites:
[ - <string> ] ]
# prefer_server_cipher_suites controls whether the server selects the
# client's most preferred ciphersuite, or the server's most preferred
# ciphersuite. If true then the server's preference, as expressed in
# the order of elements in cipher_suites, is used.
[ prefer_server_cipher_suites: <bool> | default = true ]
# Elliptic curves that will be used in an ECDHE handshake, in preference
# order. Available curves are documented in the go documentation:
# https://golang.org/pkg/crypto/tls/#CurveID
[ curve_preferences:
[ - <string> ] ]
http_server_config:
# Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS.
# This can not be changed on the fly.
[ http2: <bool> | default = true ]
# Usernames and hashed passwords that have full access to the web
# server via basic authentication. If empty, no basic authentication is
# required. Passwords are hashed with bcrypt.
basic_auth_users:
[ <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,userhttp_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
采用线性插值:
计算方式:分位值=起始bucket大小+(本bucket宽度)*(目标分位数在本bucket排行/本bucket记录数)
如果bucket选择合适,那么得到的分位数误差就较小。
prometheus_http_request_duration_seconds_bucket{le="0.05"} 199881
prometheus_http_request_duration_seconds_bucket{le="0.1"} 212210
prometheus_http_request_duration_seconds_bucket{le="0.2"} 215395
prometheus_http_request_duration_seconds_bucket{le="0.4"} 319435
prometheus_http_request_duration_seconds_bucket{le="0.8"} 419576
prometheus_http_request_duration_seconds_bucket{le="1.6"} 469593
prometheus_http_request_duration_seconds_bucket{le="+Inf"} 519593
# 计算0.75分位数
0.75 * 519593 = 389694.75 位于 0.4~0.8之间
0.4 + (0.8-0.4) * ((389694.75 - 319435) / (419576 - 319435))
如何选择:
- 需要聚合选择
Histogram
- 如果了解观测值的分布那么选择
Histogram
;如果需要准确的分位数选择Summary
Grafana
Datasource
支持多种数据源,通过kube-prometheus安装的时候已经集成了Prometheus数据源。
-rw-r--r--. 1 root root 550 Oct 27 10:37 grafana-dashboardDatasources.yaml # 配置数据源
-rw-r--r--. 1 root root 1403539 Oct 27 10:37 grafana-dashboardDefinitions.yaml # 配置面板
-rw-r--r--. 1 root root 454 Oct 27 10:37 grafana-dashboardSources.yaml
-rw-r--r--. 1 root root 7629 Oct 27 10:37 grafana-deployment.yaml
-rw-r--r--. 1 root root 86 Oct 27 10:37 grafana-serviceAccount.yaml
-rw-r--r--. 1 root root 208 Oct 27 10:37 grafana-serviceMonitor.yaml
-rw-r--r--. 1 root root 201 Oct 27 10:37 grafana-service.yaml
Dashboards
支持json导入,手动配置,配置文件配置,官方面板应用商城 id导入。
Default
├── DashBoard
│ ├── panel1
│ │ └── query
| | └── alert
│ ├── panel2
│ │ └── query
| | └── alert
General
│ ├── panel3
│ │ └── query
| | └── alert
│ ├── panel4
│ │ └── query
| | └── alert
Alert
告警配置跟随面板一起配置的:
- 触发频率;
- 触发条件;
- 没有数据或者出现异常如何处理;
- 通知内容和标签设置;
- 设置receiver;