Alertmanager已经在前面Prometheus初体验(三)已经介绍过了。现在介绍一下在kube-promethues里面怎么修改alertmanager配置文件,以及怎么通过各种媒介发送信息。
一、配置 PrometheusRule(触发器)
kube-promethues把所有资源监控起来之后,就需要配置告警这一块了,而告警其实就是配置触发器。在promethues的Alert界面,已经有了很多触发器了。
那么,这些报警信息是哪里来的呢?他们应该用怎样的方式通知我们呢?我们知道之前使用二进制部署的时候,是通过自定义的方式在 Prometheus 的配置文件之中指定 AlertManager 实例和 报警的 rules 文件,现在我们通过 Operator 部署的呢?我们可以在 Prometheus Dashboard 的 Config 页面下面查看关于 AlertManager 的配置:
global: scrape_interval: 30s scrape_timeout: 10s evaluation_interval: 30s external_labels: prometheus: monitoring/k8s prometheus_replica: prometheus-k8s-0 alerting: alert_relabel_configs: - separator: ; regex: prometheus_replica replacement: $1 action: labeldrop alertmanagers: - kubernetes_sd_configs: - role: endpoints namespaces: names: - monitoring scheme: http path_prefix: / timeout: 10s api_version: v1 relabel_configs: - source_labels: [__meta_kubernetes_service_name] separator: ; regex: alertmanager-main replacement: $1 action: keep - source_labels: [__meta_kubernetes_endpoint_port_name] separator: ; regex: web replacement: $1 action: keep rule_files: - /etc/prometheus/rules/prometheus-k8s-rulefiles-0/*.yaml
上面 alertmanagers 实例的配置我们可以看到是通过角色为 endpoints 的 kubernetes 的服务发现机制获取的,匹配的是服务名为 alertmanager-main,端口名为 web 的 Service 服务,我们查看下 alertmanager-main 这个 Service:
[root@vm10-0-0-12 ~]# kubectl describe svc alertmanager-main -n monitoring Name: alertmanager-main Namespace: monitoring Labels: alertmanager=main Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"alertmanager":"main"},"name":"alertmanager-main","namespace":"... Selector: alertmanager=main,app=alertmanager Type: ClusterIP IP: 10.254.160.2 Port: web 9093/TCP TargetPort: web/TCP Endpoints: 10.8.0.21:9093,10.8.1.72:9093,10.8.2.19:9093 Session Affinity: ClientIP Events: <none>
可以看到服务名正是 alertmanager-main,Port 定义的名称也是 web,符合上面的规则,所以 Prometheus 和 AlertManager 组件就正确关联上了。而对应的报警规则文件位于:/etc/prometheus/rules/prometheus-k8s-rulefiles-0/
目录下面所有的 YAML 文件。我们可以进入 Prometheus 的 Pod 中验证下该目录下面是否有 YAML 文件:
$ kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring Defaulting container name to prometheus. Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod. /prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/ monitoring-prometheus-k8s-rules.yaml /prometheus $ cat /etc/prometheus/rules/prometheus-k8s-rulefiles-0/monitoring-prometheus-k8s-rules.yaml groups: - name: k8s.rules rules: - expr: | sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace) record: namespace:container_cpu_usage_seconds_total:sum_rate ......
这个 YAML 文件实际上就是我们之前创建的一个 PrometheusRule 文件包含的:
$ cat prometheus-rules.yaml apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: labels: prometheus: k8s role: alert-rules name: prometheus-k8s-rules namespace: monitoring spec: groups: - name: k8s.rules rules: - expr: | sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace) record: namespace:container_cpu_usage_seconds_total:sum_rate
我们这里的 PrometheusRule 的 name 为 prometheus-k8s-rules,namespace 为 monitoring,我们可以猜想到我们创建一个 PrometheusRule 资源对象后,会自动在上面的 prometheus-k8s-rulefiles-0 目录下面生成一个对应的<namespace>-<name>.yaml
文件,所以如果以后我们需要自定义一个报警选项的话,只需要定义一个 PrometheusRule 资源对象即可。
至于为什么 Prometheus 能够识别这个 PrometheusRule 资源对象呢?这就需要查看我们创建的 prometheus 这个资源对象了,里面有非常重要的一个属性 ruleSelector,用来匹配 rule 规则的过滤器,要求匹配具有 prometheus=k8s 和 role=alert-rules 标签的 PrometheusRule 资源对象,现在明白了吧?
cat prometheus-prometheus.yaml
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 baseImage: prom/prometheus nodeSelector: beta.kubernetes.io/os: linux podMonitorSelector: {} 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.11.0
所以我们要想自定义一个报警规则,只需要创建一个具有 prometheus=k8s 和 role=alert-rules 标签的 PrometheusRule 对象就行了,比如现在我们添加一个 etcd 是否可用的报警,我们知道 etcd 整个集群有一半以上的节点可用的话集群就是可用的,所以我们判断如果不可用的 etcd 数量超过了一半那么就触发报警,创建文件 prometheus-etcdRules.yaml:
apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: labels: prometheus: k8s role: alert-rules name: etcd-rules namespace: monitoring spec: groups: - name: etcd rules: - alert: EtcdClusterUnavailable annotations: summary: etcd cluster small description: If one more etcd peer goes down the cluster will be unavailable expr: | count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1) for: 3m labels: severity: critical
注意:label 标签一定至少要有 prometheus=k8s 和 role=alert-rules!
rule文件的头部都是统一的,只有spec里面不同。
创建完成后,隔一会儿再去容器中查看下 rules 文件夹:
kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring Defaulting container name to prometheus. Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod. /prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/ monitoring-etcd-rules.yaml monitoring-prometheus-k8s-rules.yaml
可以看到我们创建的 rule 文件已经被注入到了对应的 rulefiles 文件夹下面了,证明我们上面的设想是正确的。然后再去 Prometheus Dashboard 的 Rules页面下面就可以查看到上面我们新建的报警规则了:
二、配置promethuesAlert(告警媒介)
触发器配置完成后,接下来需要在kube-promethues环境里配置告警通知了。promethues支持多种告警方式:钉钉、微信、邮件、webhook。其中webhook最为灵活,可以和自研的第三方平台对接。
告警配置相关可以在alertmanager里面查看:
这些配置信息实际上是来自于我们之前在prometheus-operator/contrib/kube-prometheus/manifests
目录下面创建的 alertmanager-secret.yaml 文件:
apiVersion: v1 data: alertmanager.yaml: Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg== kind: Secret metadata: name: alertmanager-main namespace: monitoring type: Opaque
可以将 alertmanager-secret.yaml 对应的 value 值做一个 base64 解码:
echo "Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg==" | base64 -d
也就是说,如果我们需要修改告警的主配置文件,只要修改 alertmanager-secret.yaml文件就行了。而 alertmanager-secret.yaml是一个secret,所以修改过程如下:
1、新建一个alertmanager.yaml文件
2、删除之前的secret文件(alertmanager-main)
3、新建secret文件
cat alertmanager.yaml
global: resolve_timeout: 5m wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/' wechat_api_secret: '*****' wechat_api_corp_id: '*******' smtp_smarthost: 'smtp.163.com:25' smtp_from: '你的邮箱' smtp_auth_username: '邮箱用户名' smtp_auth_password: '密码或授权码' smtp_require_tls: false templates: ##消息模板 - '*.tmpl' route: group_by: ['alertname','job'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'wechat' routes: - match: job: 'prometheus' receiver: 'wechat' receivers: - name: 'email' email_configs: - to: '邮件接收人' - name: 'wechat' wechat_configs: - send_resolved: true to_party: '2' agent_id: '1' - name: 'webhook' webhook_configs: # - url: 'http://dingtalk-hook:5000' - url: 'http://webhook-dingtalk.monitoring.svc.cluster.local:8060/dingtalk/webhook1/send' send_resolved: true
# 先将之前的 secret 对象删除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 创建新的secret对象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
注意:这里--from-file可以使用多个,如果你使用多重告警方式的话。
以上过程执行完成后,就可以在alertmanager中看到最新的配置了:
三、配置promethuesAlert(邮件告警)
邮件告警是最简单的,只需要直接在alertmanager的config里面配置就行。
global: resolve_timeout: 5m smtp_smarthost: 'smtp.163.com:25' smtp_from: 'xuequn_2008@163.com' smtp_auth_username: 'xuequn_2008@163.com' smtp_auth_password: 'password' smtp_require_tls: false templates: ##消息模板 - '*.tmpl' route: group_by: ['alertname','job'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'wechat' routes: - match: job: 'prometheus' receiver: 'wechat' receivers: - name: 'email' email_configs: - to: 'xuequn_2008@163.com'
以上是一个简单的配置,完成后,将repeat-interval设置小一点,比如1m。去邮箱查看对应的告警就行了。
四、配置promethuesAlert(钉钉告警)
1、注册钉钉账号->机器人管理
2、自定义(通过webhook接入自定义服务)
3、添加->复制webhook
重点在webhook,复制webhook的url链接。
4、编写yaml
在/data/k8s-install/prometheus/alertmanager目录下,新建dingtalk-webhook.yaml
--- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: dingtalk name: webhook-dingtalk namespace: monitoring spec: replicas: 1 template: metadata: labels: run: dingtalk spec: containers: - name: dingtalk image: timonwong/prometheus-webhook-dingtalk:v0.3.0 imagePullPolicy: IfNotPresent # 设置钉钉群聊自定义机器人后,使用实际 access_token 替换下面 xxxxxx部分 args: - --ding.profile=webhook1=https://oapi.dingtalk.com/robot/send?access_token=你的token ports: - containerPort: 8060 protocol: TCP --- apiVersion: v1 kind: Service metadata: labels: run: dingtalk name: webhook-dingtalk namespace: monitoring spec: ports: - port: 8060 protocol: TCP targetPort: 8060 selector: run: dingtalk sessionAffinity: None
填上上面复制的webhook链接地址。
5、应用配置
kubectl apply -f dingtalk-webhook.yaml
应用配置后,对应的pod和service就起来了,我们可以看到侦听的端口为8060.
6、alertmanager配置告警通知
global: resolve_timeout: 5m templates: ##消息模板 - '*.tmpl' route: group_by: ['alertname','job'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'webhook' receivers: #配置邮件告警 - name: 'email' email_configs: - to: 'xuequn_2008@163.com' #配置钉钉告警的webhook - name: 'webhook' webhook_configs: - url: 'http://webhook-dingtalk.monitoring.svc.cluster.local:8060/dingtalk/webhook1/send' send_resolved: true
7、更新告警文件
# 先将之前的 secret 对象删除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 创建新的secret对象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
8、测试告警
一般情况下,没有问题的话,你就可以接收到钉钉告警拉。
五、配置promethuesAlert(微信告警)
由于wechat的强大,所以alertmanager官方直接支持wechat告警,直接配置即可。
1、注册企业微信
找到以下几个东西:
wechat_api_secret 应用ID
wechat_api_corp_id 企业ID
to_party 中心(部门的上级)
agent_id 部门ID
2、配置alertmanager
global: resolve_timeout: 5m wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/' wechat_api_secret: '应用ID' wechat_api_corp_id: '企业ID' templates: ##消息模板 - '*.tmpl' route: group_by: ['alertname','job'] group_wait: 10s group_interval: 10s repeat_interval: 1m receiver: 'wechat' receivers: - name: 'wechat' wechat_configs: - send_resolved: true to_party: '2' #中心ID agent_id: '1' #部门ID
按照以上方式配置完成后,直接测试即可,一般没有问题的情况下,你会收到如下形式的告警:
六、配置promethuesAlert(自研平台)
自研平台,就是自己开发的平台。其实也是通过webhook方式和第三方对接。前提是:自研平台有对应的API接口接受告警。
比如,我们自己开发的接口如下:
curl -X POST "http://www.baibai.com/eventhub/api/v1/failure_events/" -H "Content-Type:application/json" -H "Authorization:Token 7HNSNBqqRf6EHCBaCgDdMPYHCq9VK6RE" -d @- << EOF { "name": "告警事件名", "description":"事件描述", "project_name": "告警项目", "failure_type":"程序故障-通用应用程序故障-通用应用程序BUG" } EOF
上面对接的是一个事件系统,有一个POST接口,可以直接接受事件告警。
因为我们希望webhook同样运行在k8s环境里,方便维护和开发,所以,我们先要制作一个对应webhook的镜像文件。
1、制作镜像
编写app
import os import json import requests import datetime from flask import Flask from flask import request app = Flask(__name__) @app.route('/', methods=['POST', 'GET']) def send(): if request.method == 'POST': post_data = request.get_data() post_data = eval(str(post_data, encoding = "utf-8")) event_status = post_data.get('alerts')[0].get('status','') event_job = post_data.get('alerts')[0].get('labels','').get('job','') event_type = post_data.get('alerts')[0].get('labels','').get('alertname','') event_desc = post_data.get('alerts')[0].get('annotations','').get('message','') event_level = post_data.get('alerts')[0].get('labels','').get('severity','') event_time = post_data.get('alerts')[0].get('startsAt')[0:-11] new_data = { "alert_status": event_status, "alert_instance": event_job, "alert_type": event_type, "alert_desc": event_desc, "alert_severity": event_level, "alert_time": event_time } send_alert(new_data) return 'success' else: return 'weclome to use prometheus alertmanager events-hub webhook server!' class ComplexEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, bytes): return str(obj, encoding='utf-8') else: return json.JSONEncoder.default(self, obj) def send_alert(data): url = "http://www.baibai/eventhub/api/v1/failure_events/" headers = { "Content-Type": "application/json", "Authorization": "Token 7HNSNBqqRf6EHCBaCgDdMPYHCq9VK6RE" } send_data = { "name": data.get('alert_desc',''), "description": data, "project_name": "维护支持部", "failure_type": "程序故障-通用应用程序故障-通用应用程序BUG" } req = requests.post(url, data=json.dumps(send_data,cls=ComplexEncoder),headers=headers) print(req.text) result = req.json() if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
2、编写Dockerfile
cat Dockerfile
FROM python:3.6.4 # set working directory WORKDIR /src # add app ADD . /src # install requirements RUN pip install -r requirements.txt # run server CMD python app.py
cat requirements.txt
certifi==2018.10.15 chardet==3.0.4 Click==7.0 Flask==1.0.2 idna==2.7 itsdangerous==1.1.0 Jinja2==2.10 MarkupSafe==1.1.0 requests==2.20.1 urllib3==1.24.1 Werkzeug==0.14.1
上面其实就是写了一个简单的flask app,通过POST方法,向第三方系统的API提交数据。
3、构建镜像
docker build -t loveliuli/events-hub:v0.1 .
4、上传镜像到Dockerhub
当然,这里的前提是你得先在Dockerhub上注册了账号,并且在本地使用docker login登录。
docker push loveliuli/events-hub:v0.1
这样就方便在任何地方都可以进行使用这个镜像了。
5、alertmanager编写yaml
cat dingtalk-webhook-flask.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: dingtalk-hook namespace: monitoring spec: template: metadata: labels: app: dingtalk-hook spec: containers: - name: dingtalk-hook image: loveliuli/events-hub:v0.30 imagePullPolicy: IfNotPresent ports: - containerPort: 5000 name: http resources: requests: cpu: 50m memory: 100Mi limits: cpu: 50m memory: 100Mi --- apiVersion: v1 kind: Service metadata: name: dingtalk-hook namespace: monitoring spec: type: NodePort selector: app: dingtalk-hook ports: - name: hook port: 5000 targetPort: http
以上name命名可能有点误导,其实和钉钉毫无关系。
6、应用配置
kubectl apply -f dingtalk-webhook-flask.yaml
应用配置后,我们即可查看启动情况:
7、配置alertmanager
global: resolve_timeout: 5m templates: ##消息模板 - '*.tmpl' route: group_by: ['alertname','job'] group_wait: 10s group_interval: 10s repeat_interval: 1m receiver: 'webhook' receivers: - name: 'webhook' webhook_configs: - url: 'http://dingtalk-hook:5000' send_resolved: true
8、更新告警文件
# 先将之前的 secret 对象删除 $ kubectl delete secret alertmanager-main -n monitoring secret "alertmanager-main" deleted # 创建新的secret对象 $ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring secret "alertmanager-main" created
注意:我们每次更新alertmanager的配置文件,都必须更新告警文件,才能生成最新的配置。
9、测试告警
不出意外的话,你将会看到如下log信息,那就表示成功了。
第三方系统接收信息:
通过第三方系统和自己企业的短信、内部系统对接,就非常简单了!