• kube-promethues监控告警详解(邮件、钉钉、微信、自研平台)


    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信息,那就表示成功了。

    第三方系统接收信息:

     通过第三方系统和自己企业的短信、内部系统对接,就非常简单了!

  • 相关阅读:
    kudu 存储引擎简析
    Kudu vs HBase
    HBase原理–所有Region切分的细节都在这里了
    4月第3周业务风控关注 | 文化部再次审查直播和游戏产品,已下架4939款直播应用
    知物由学 | 如何应对日益强大的零日攻击
    Apache 流框架 Flink,Spark Streaming,Storm对比分析(二)
    Apache 流框架 Flink,Spark Streaming,Storm对比分析(一)
    poj1637Sightseeing tour(混合图欧拉回路)
    计算机网络_学习笔记 第一章 概述
    [Codecademy] HTML&CSS 第三课:HTML Basic II
  • 原文地址:https://www.cnblogs.com/skyflask/p/11507017.html
Copyright © 2020-2023  润新知