一.PromQL语法
1.常用语法
PromQL Web UI 的 Graph 选项卡提供了简单的用于查询数据的入口,对于 PromQL 的编写
和校验都可以在此位置,如图所示:
输入 up,然后点击 Execute,就能查到监控正常的 Target:
通过标签选择器过滤出 job 为 node-exporter 的监控,语法为:up{job=”node-exporter”}:
注意此时是 up{job=”node-exporter”}属于绝对匹配,PromQL 也支持如下表达式:
➢ !=:不等于;
➢ =~:表示等于符合正则表达式的指标;
➢ !~:和=~类似,=~表示正则匹配,!~表示正则不匹配。
如果想要查看主机监控的指标有哪些,可以输入 node,会提示所有主机监控的指标:
假 如 想 要 查 询 Kubernetes 集 群 中 每 个 宿 主 机 的 磁 盘 总 量 , 可 以 使 用
node_filesystem_size_bytes:
查询指定分区大小 node_filesystem_size_bytes{mountpoint=”/”}:
或者是查询分区不是/boot,且磁盘是/dev/开头的分区大小(结果不再展示):
node_filesystem_size_bytes{device=~"/dev/.*", mountpoint!="/boot"}
查询主机 k8s-master01 在最近 5 分钟可用的磁盘空间变化:
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"}[5m]
目前支持的范围单位如下:
➢ s:秒
➢ m:分钟
➢ h:小时
➢ d:天
➢ w:周
➢ y:年
查询 10 分钟之前磁盘可用空间,只需要指定 offset 参数即可:
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"} offset 10m
查询 10 分钟之前,5 分钟区间的磁盘可用空间的变化:
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"}[5m] offset 10m
2.PromQL操作符
通过 PromQL 的语法查到了主机磁盘的空间数据,查询结果如下:
可以通过以下命令将字节转换为 GB 或者 MB:
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"} / 1024 / 1024 / 1024
也可以将 1024 / 1024 / 1024 改为(1024 ^ 3):
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"} / (1024 ^ 3)
查询结果如下图所示,此时为 31GB 左右:
此时可以在宿主机上比对数据是否正确:
[root@k8s-master02 ~]# df -Th | grep /dev/mapper/centos-root /dev/mapper/centos-root xfs 36G 3.9G 32G 11% /
上述使用的“/”为数学运算的“除”,“^”为幂运算,同时也支持如下运算符:
➢ +: 加
➢ -: 减
➢ *: 乘
➢ /: 除
➢ ^: 幂运算
➢ %: 求余
查询 k8s-master01 根区分磁盘可用率,可以通过如下指令进行计算:
node_filesystem_avail_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"} / node_filesystem_size_bytes{instance="k8s-master01", mountpoint="/", device="/dev/mapper/centos-root"}
查询所有主机根分区的可用率:
node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}
也可以将结果乘以 100 直接得到百分比:
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100
找到集群中根分区空间可用率大于 90%的主机,只找到一台:
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 > 60
PromQL 也支持如下判断:
➢ ==: (相等)
➢ != :(不相等)
➢ >:(大于)
➢ < :(小于) ➢ >= :(大于等于)
➢ <= :(小于等于)
磁盘可用率大于 30%小于等于 60%的主机:
30 < (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 <= 60
也可以用 and 进行联合查询:
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 > 30 and (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} ) * 100 <=60
除了 and 外,也支持 or 和 unless: ➢ and: 并且
➢ or :或者
➢ unless :排除
查询主机磁盘剩余空间,并且排除掉 shm 和 tmpfs 的磁盘:
node_filesystem_free_bytes unless node_filesystem_free_bytes{device=~"shm|tmpfs"}
当然,这个语法也可以直接写为:
node_filesystem_free_bytes{device=~"shm|tmpfs"}
3.PromQL常用函数
使用sum函数统计当前监控目标所有主机根分区剩余的空间:
sum(node_filesystem_free_bytes{mountpoint="/"}) / 1024^3
也可以用同样方式,计算所有的请求总量:
sum(http_request_total)
根据 statuscode 字段进行统计请求数据:
sum(http_request_total) by (statuscode)
根据 statuscode 和 handler 两个指标进一步统计:
sum(http_request_total) by (statuscode, handler)
找到排名前五的数据:
topk(5, sum(http_request_total) by (statuscode, handler))
取最后三个数据:
bottomk(3, sum(http_request_total) by (statuscode, handler))
找出统计结果中最小的数据:
min(node_filesystem_avail_bytes{mountpoint="/"})
最大的数据:
max(node_filesystem_avail_bytes{mountpoint="/"})
平均值:
avg(node_filesystem_avail_bytes{mountpoint="/"})
四舍五入,向上取最接近的整数,2.79 → 3:
ceil(node_filesystem_files_free{mountpoint="/"} / 1024 / 1024)
向下取整数, 2.79 → 2:
floor(node_filesystem_files_free{mountpoint="/"} / 1024 / 1024)
对结果进行正向排序:
sort(sum(http_request_total) by (handler, statuscode))
对结果进行逆向排序:
sort_desc(sum(http_request_total) by (handler, statuscode))
函数 predict_linear 可以用于预测分析和预测性告警,比如可以根据一天的数据,预测 4 个
小时后,磁盘分区的空间会不会小于 0:
predict_linear(node_filesystem_files_free{mountpoint="/"}[1d], 4*3600) < 0
下图表示:根据一天的数据,预测1350个小时后,磁盘分区的空间会不会小于 0:
除了上述的函数,还有几个比较重要的函数,比如 increase、rate、irate。其中 increase 是
计算在一段时间范围内数据的增长(只能计算 count 类型的数据),rate 和 irate 是计算增长率。
比如查询某个请求在 1 小时的时间增长了多少:
increase(http_request_total{handler="/api/datasources/proxy/:id/*",metho d="get",namespace="monitoring",service="grafana",statuscode="200"}[1h])
将 1h 增长的数量处于该时间即为增长率:
increase(http_request_total{handler="/api/datasources/proxy/:id/*",metho d="get",namespace="monitoring",service="grafana",statuscode="200"}[1h]) /3600
相对于 increase,rate 可以直接计算出某个指标在给定时间范围内的增长率,比如还是计算
1h 的增长率,可以用 rate 函数进行计算:
rate(http_request_total{handler="/api/datasources/proxy/:id/*",method="g et",namespace="monitoring",service="grafana",statuscode="200"}[1h])
二.Alertmanager告警
1.配置文件解析
官方文档:https://prometheus.io/docs/alerting/latest/configuration/
中文注释文档:https://github.com/dotbalo/k8s/blob/master/prometheus-operator/alertmanager.yaml
简易模板:https://github.com/prometheus/alertmanager/blob/main/doc/examples/simple.yml
首先看一下一个简单的 Alertmanager 的配置示例:
# global块配置下的配置选项在本配置文件内的所有配置项下可见 global: # 在Alertmanager内管理的每一条告警均有两种状态: "resolved"或者"firing". 在altermanager首次发送告警通知后, 该告警会一直处于firing状态,设置resolve_timeout可以指定处于firing状态的告警间隔多长时间会被设置为resolved状态, 在设置为resolved状态的告警后,altermanager不会再发送firing的告警通知. resolve_timeout: 1h # 邮件告警配置 smtp_smarthost: 'smtp.exmail.qq.com:25' smtp_from: 'dukuan@xxx.com' smtp_auth_username: 'dukuan@xxx.com' smtp_auth_password: 'DKxxx' # HipChat告警配置 # hipchat_auth_token: '123456789' # hipchat_auth_url: 'https://hipchat.foobar.org/' # wechat wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/' wechat_api_secret: 'JJ' wechat_api_corp_id: 'ww' # 告警通知模板 templates: - '/etc/alertmanager/config/*.tmpl' # route: 根路由,该模块用于该根路由下的节点及子路由routes的定义. 子树节点如果不对相关配置进行配置,则默认会从父路由树继承该配置选项。每一条告警都要进入route,即要求配置选项group_by的值能够匹配到每一条告警的至少一个labelkey(即通过POST请求向altermanager服务接口所发送告警的labels项所携带的),告警进入到route后,将会根据子路由routes节点中的配置项match_re或者match来确定能进入该子路由节点的告警(由在match_re或者match下配置的labelkey: labelvalue是否为告警labels的子集决定,是的话则会进入该子路由节点,否则不能接收进入该子路由节点). route: # 例如所有labelkey:labelvalue含cluster=A及altertname=LatencyHigh labelkey的告警都会被归入单一组中 group_by: ['job', 'altername', 'cluster', 'service','severity'] # 若一组新的告警产生,则会等group_wait后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在group_wait内合并为单一的告警后再发送 group_wait: 30s # 再次告警时间间隔 group_interval: 5m # 如果一条告警通知已成功发送,且在间隔repeat_interval后,该告警仍然未被设置为resolved,则会再次发送该告警通知 repeat_interval: 12h # 默认告警通知接收者,凡未被匹配进入各子路由节点的告警均被发送到此接收者 receiver: 'wechat' # 上述route的配置会被传递给子路由节点,子路由节点进行重新配置才会被覆盖 # 子路由树 routes: # 该配置选项使用正则表达式来匹配告警的labels,以确定能否进入该子路由树 # match_re和match均用于匹配labelkey为service,labelvalue分别为指定值的告警,被匹配到的告警会将通知发送到对应的receiver - match_re: service: ^(foo1|foo2|baz)$ receiver: 'wechat' # 在带有service标签的告警同时有severity标签时,他可以有自己的子路由,同时具有severity != critical的告警则被发送给接收者team-ops-mails,对severity == critical的告警则被发送到对应的接收者即team-ops-pager routes: - match: severity: critical receiver: 'wechat' # 比如关于数据库服务的告警,如果子路由没有匹配到相应的owner标签,则都默认由team-DB-pager接收 - match: service: database receiver: 'wechat' # 我们也可以先根据标签service:database将数据库服务告警过滤出来,然后进一步将所有同时带labelkey为database - match: severity: critical receiver: 'wechat' # 抑制规则,当出现critical告警时 忽略warning inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' # Apply inhibition if the alertname is the same. # equal: ['alertname', 'cluster', 'service'] # # 收件人配置 receivers: - name: 'team-ops-mails' email_configs: - to: 'dukuan@xxx.com' - name: 'wechat' wechat_configs: - send_resolved: true corp_id: 'ww' api_secret: 'JJ' to_tag: '1' agent_id: '1000002' api_url: 'https://qyapi.weixin.qq.com/cgi-bin/' message: '{{ template "wechat.default.message" . }}' #- name: 'team-X-pager' # email_configs: # - to: 'team-X+alerts-critical@example.org' # pagerduty_configs: # - service_key: # #- name: 'team-Y-mails' # email_configs: # - to: 'team-Y+alerts@example.org' # #- name: 'team-Y-pager' # pagerduty_configs: # - service_key: # #- name: 'team-DB-pager' # pagerduty_configs: # - service_key: # #- name: 'team-X-hipchat' # hipchat_configs: # - auth_token: # room_id: 85 # message_format: html # notify: true
Alertmanager 的配置主要分为五大块:
➢ Global:全局配置,主要用来配置一些通用的配置,比如邮件通知的账号、密码、SMTP
服务器、微信告警等。Global 块配置下的配置选项在本配置文件内的所有配置项下可
见,但是文件内其它位置的子配置可以覆盖 Global 配置;
➢ Templates:用于放置自定义模板的位置;
➢ Route:告警路由配置,用于告警信息的分组路由,可以将不同分组的告警发送给不同
的收件人。比如将数据库告警发送给 DBA,服务器告警发送给 OPS;
➢ Inhibit_rules:告警抑制,主要用于减少告警的次数,防止“告警轰炸”。比如某个宿主机
宕机,可能会引起容器重建、漂移、服务不可用等一系列问题,如果每个异常均有告警,
会一次性发送很多告警,造成告警轰炸,并且也会干扰定位问题的思路,所以可以使用
告警抑制,屏蔽由宿主机宕机引来的其他问题,只发送宿主机宕机的消息即可;
➢ Receivers:告警收件人配置,每个 receiver 都有一个名字,经过 route 分组并且路由后
需要指定一个 receiver,就是在此位置配置的。
2.Alertmanager路由规则
route 配置:
"route": "group_by": - "namespace" - "job" - "alertname" "group_interval": "5m" "group_wait": "30s" "receiver": "Default" "repeat_interval": "12h" "routes": - "match": "alertname": "Watchdog" "receiver": "Watchdog" - "match": "severity": "critical" "receiver": "Critical"
➢ receiver:告警的通知目标,需要和 receivers 配置中 name 进行匹配。需要注意的是
route.routes 下也可以有 receiver 配置,优先级高于 route.receiver 配置的默认接收人,
当告警没有匹配到子路由时,会使用 route.receiver 进行通知,比如上述配置中的
Default;
➢ group_by:分组配置,值类型为列表。比如配置成[‘job’, ‘severity’],代表告警信息包含
job 和 severity 标签的会进行分组,且标签的 key 和 value 都相同才会被分到一组;
➢ continue:决定匹配到第一个路由后,是否继续后续匹配。默认为 false,即匹配到第一
个子节点后停止继续匹配;
➢ match:一对一匹配规则,比如 match 配置的为 job: mysql,那么具有 job=mysql 的告
警会进入该路由;
➢ match_re:和 match 类似,只不过是 match_re 是正则匹配;
➢ group_wait:告警通知等待,值类型为字符串。若一组新的告警产生,则会等 group_wait
后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在 group_wait 内合
并为单一的告警后再发送,防止告警过多,默认值 30s;
➢ group_interval:同一组告警通知后,如果有新的告警添加到该组中,再次发送告警通
知的时间,默认值为 5m;
➢ repeat_interval:如果一条告警通知已成功发送,且在间隔 repeat_interval 后,该告警
仍然未被设置为 resolved,则会再次发送该告警通知,默认值 4h。
3.邮箱告警设置
找到 Alertmanager 的配置文件:
[root@k8s-master01 kube-prometheus]# cd manifests/ [root@k8s-master01 manifests]# vim alertmanager-secret.yaml
之后在 alertmanager-secret.yaml 文件的 global 添加配置如下:
... stringData: alertmanager.yaml: |- "global": "resolve_timeout": "5m" smtp_from: "qtorm1@163.com" smtp_smarthost: "smtp.163.com:465" smtp_hello: "163.com" smtp_auth_username: "qtorm1@163.com" smtp_auth_password: "XXXX" #SMTP邮箱密码 smtp_require_tls: false ...
之后将名称为 Default 的 receiver 配置更改为邮件通知,修改 alertmanager-secret.yaml 文件
的 receivers 配置如下:
... "receivers": - "name": "Default" "email_configs": - to: "609346246@qq.com" send_resolved: true - "name": "Watchdog" - "name": "Critical" ... ➢ email_configs:代表使用邮件通知; ➢ to:收件人,此处为 notification@163.com,可以配置多个,逗号隔开; ➢ send_resolved:告警如果被解决是否发送解决通知。
然后分析一下路由规则(默认分组只有 namespace,在此添加上 job 和 alertname,当然
不添加也是可以的):
... "route": "group_by": - "namespace" - "job" - "alertname" ...
可以通过 Alertmanager 提供的 Web UI 查看分组信息,和 Prometheus 一致,将 Alertmanager
的 Service 更改为 NodePort:
[root@k8s-master01 manifests]# kubectl edit svc -n monitoring alertmanager-main [root@k8s-master01 manifests]# kubectl get svc -n monitoring alertmanager-main NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE alertmanager-main NodePort 10.99.27.5 9093:31062/TCP 25h
然后web端访问配置文件和分组:
最后打开接收邮箱,发现能收到告警邮件
4.微信告警设置
首先登录企业微信web端:https://work.weixin.qq.com/
可以用公司的管理员账户。
企业微信配置:
注册完成后进行登录,登录后点击我的企业:
在页面的最下面找到企业 ID(corp_id)并记录,稍后会用到:
之后创建一个部门,用于接收告警通知,之后在Prom告警子部门添加相关的人员:
查看该部门 ID(to_party)并记录:
之后创建机器人应用,首先点击应用管理→应用创建:
选择一个 logo,输入应用名称和选择可见范围即可:
创建完成后,查看 AgentId 和 Secret(api_secret)并记录:
点击查看 Secret,企业微信会将 Secret 发送至企业微信:
修改 Alertmanager 配置文件,添加企业微信告警。首先修改 Global,添加一些通用配置,
wechat_api_url 是固定配置,corp_id 为企业 ID,Receivers 添加微信通知(红色字体为新添加内容):
[root@k8s-master01 manifests]# vim alertmanager-secret.yaml .... "global": "resolve_timeout": "5m" smtp_from: "qtorm1@163.com" smtp_smarthost: "smtp.163.com:465" smtp_hello: "163.com" smtp_auth_username: "qtorm1@163.com" smtp_auth_password: "IGKR*****" smtp_require_tls: false wechat_api_url: "https://qyapi.weixin.qq.com/cgi-bin/" wechat_api_corp_id: "ww68b2*****" ... "receivers": - "name": "Default" "email_configs": - to: "609346246@qq.com" send_resolved: true - name: wechat-ops wechat_configs: - send_resolved: true to_party: 2 to_user: '@all' agent_id: 1000002 api_secret: "r3D_Vk7*******" ... 此处配置的 receiver 名字为 wechat-ops,to_user 为@all,代表发送给所有人
更改路由配置,将 Watchdog 的告警发送给该部门:
"route":
"group_by":
- "namespace"
- "job"
- "alertname"
"group_interval": "12h"
"group_wait": "30s"
"receiver": "Default"
"repeat_interval": "12h"
"routes":
- "match":
"alertname": "Watchdog"
"receiver": "wechat-ops"
"repeat_interval": "10m"
配置好后可以在altermanager的web端和企业微信接收告警: