zoukankan      html  css  js  c++  java
  • 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信息,那就表示成功了。

    第三方系统接收信息:

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

  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/skyflask/p/11507017.html
Copyright © 2011-2022 走看看