k8s安装Prometheus并配置钉钉告警

官网文档链接:https://prometheus.io/docs/introduction/overview/

1 prometheus简介

    普罗米修斯是一个开源系统监控和警报工具包,最初由SoundCloud构建。自 2012 年启动以来,许多公司和组织都采用了 Prometheus,该项目拥有非常活跃的开发者和用户社区。它现在是一个独立的开源项目,独立于任何公司进行维护。为了强调这一点,并明确项目的治理结构,Prometheus  2016 年作为继Kubernetes之后的第二个托管项目加入了。Prometheus 将其指标收集并存储为时间序列数据,即指标信息与记录时的时间戳以及称为标签的可选键值对一起存储。

普罗米修斯的主要特点是:

  • 具有由指标名称和键/值对标识的时间序列数据的多维数据·模型
  • PromQL,一种灵活的查询语言 来利用这个维度
  • 不依赖分布式存储;单个服务器节点是自治的
  • 时间序列收集通过 HTTP 上的拉模型进行
  • 通过中间网关支持推送时间序列
  • 通过服务发现或静态配置发现目标
  • 多种图形和仪表板支持模式

prometheus架构图

各组件介绍

  • Prometheus Server

Prometheus 的核心组件,负责从被监控服务中采集度量指标数据,并存储和查询这些数据。它的主要功能包括指标的拉取、存储和查询等。Prometheus Server本身就是一个时序数据库,将采集到的监控数据按照时间序列的方式存储在本地磁盘当中。最后Prometheus Server对外提供了自定义的PromQL语言,实现对数据的查询以及分析。

  • Exporters

是一种特殊类型的客户端库,用于支持采集和转换不同的监控源的数据格式,使得 Prometheus 能够拉取这些数据并处理。例如,Prometheus 社区提供了一些标准的 Exporters,如 Prometheus Node Exporter、MySQL Exporter 等。

  • PushGateway

由于Prometheus数据采集基于Pull模型进行设计,因此在网络环境的配置上必须要让Prometheus Server能够直接与Exporter进行通信。 当这种网络需求无法直接满足时,就可以利用PushGateway来进行中转。可以通过PushGateway将内部网络的监控数据主动Push到Gateway当中。而Prometheus Server则可以采用同样Pull的方式从PushGateway中获取到监控数据。

  • Service Discovery

Service Discovery(服务发现)是 Prometheus 的一个重要功能,可以自动发现和管理被监控的服务,而无需手动配置每个服务的详细信息。这让 Prometheus 更加灵活和易于扩展。

Service Discovery 支持多种不同的服务发现机制,例如:

  1. 静态配置:通过一个配置文件手动编写每个被监控的服务器和其对应的指标数据。
  2. 动态配置:使用服务发现插件自动发现每个服务器和其对应的指标数据。Prometheus 支持的插件有 Consul、Zookeeper、Kubernetes 等。
  3. File-Based SD:通过解析特定格式的文件来动态添加新的目标,比如通过解析 Marahall JSON.

使用 Service Discovery 机制,可以让 Prometheus 自动发现多个服务的节点,并采集其指标数据,从而实现跨平台、分布式监控的功能。同时,Service Discovery 也支持标签技术,可以通过在节点上设置不同的标签来定义更加精细的指标采集策略。例如,可以根据服务实例的地理位置、角色、环境等标签来采集更加定向的指标数据,从而更好地反馈系统的性能和健康状态。

  • Alertmanager

在Prometheus Server中支持基于PromQL创建告警规则,如果满足PromQL定义的规则,则会产生一条告警,而告警的后续处理流程则由AlertManager进行管理。在AlertManager中我们可以与邮件,Slack等等内置的通知方式进行集成,也可以通过Webhook自定义告警处理方式。AlertManager即Prometheus体系中的告警处理中心。

  • Grafana

Grafana 是一个流行的开源数据可视化工具,通常与 Prometheus、Graphite 等多种数据源集成,可以帮助用户通过自定义可视化面板,展示和分析数据,同时也支持警报等功能。

Grafana 可以通过多种方式展示数据,包括图表、地图、仪表盘、表格等,同时支持与多种外部数据源进行交互,包括 Prometheus、Graphite、InfluxDB、Elasticsearch 等。用户可以根据自己的需求自定义数据查询查询语言,在不同的 Dashboard 中展现数据,并通过警报和通知功能及时掌握系统的动态。

另外,Grafana 还具备高度可定制性,可以根据用户需要通过插件和模板来拓展功能。Grafana 的强大的可视化功能、操作简单,对于可视化需求强烈的用户来说是一个非常好的数据分析和展示工具。同时,与各类开源监控组件的深度整合,带来了便捷的数据转化、处理、监控等功能。

Grafana官方提供了许多类型的模板,具体链接为:https://grafana.com/grafana/dashboards/

以上大概就是prometheus的一些简单介绍,想具体深入的了解自行查看官方文档,接下来我们进行prometheus的安装

2 prometheus-operator简介

官方文档链接:https://prometheus-operator.dev/docs/prologue/introduction/

Prometheus Operator 提供Kubernetes原生部署和管理Prometheus及相关监控组件。该项目的目的是为 Kubernetes 集群简化和自动化基于 Prometheus 的监控堆栈的配置。

Prometheus-operator包括但不限于以下特性:

  • Kubernetes 自定义资源:使用 Kubernetes 自定义资源部署和管理 Prometheus、Alertmanager 及相关组件。
  • 简化的部署配置:配置 Prometheus 的基础知识,例如版本、持久性、保留策略和本地 Kubernetes 资源的副本。
  • Prometheus Target Configuration:根据熟悉的Kubernetes标签查询,自动生成监控目标配置;无需学习普罗米修斯特定的配置语言。

prometheus-operator架构图

  • Operator: 根据自定义资源(Custom Resource Definition / CRDs)来部署和管理 Prometheus Server,同时监控这些自定义资源事件的变化来做相应的处理,是整个系统的控制中心。
  • Prometheus:声明 Prometheus deployment 期望的状态,Operator 确保这个 deployment 运行时一直与定义保持一致。
  • Prometheus Server: Operator 根据自定义资源 Prometheus 类型中定义的内容而部署的 Prometheus Server 集群,这些自定义资源可以看作是用来管理 Prometheus Server 集群的 StatefulSets 资源。
  • ServiceMonitor:声明指定监控的服务,描述了一组被 Prometheus 监控的目标列表。该资源通过 Labels 来选取对应的 Service Endpoint,让 Prometheus Server 通过选取的 Service 来获取 Metrics 信息。
  • Service:简单的说就是 Prometheus 监控的对象。
  • Alertmanager:定义 AlertManager deployment 期望的状态,Operator 确保这个 deployment 运行时一直与定义保持一致。

kube-prometheus 是一整套监控解决方案,它使用 Prometheus 采集集群指标,Grafana 做展示,包含如下组件:

  • The Prometheus Operator
  • Highly available Prometheus
  • Highly available Alertmanager
  • Prometheus node-exporter
  • Prometheus Adapter for Kubernetes Metrics APIs (k8s-prometheus-adapter)
  • kube-state-metrics
  • Grafana

3 使用kube-prometheus项目安装至k8s

根据自己的k8s版本选择合适的kube-prometheus stack版本

我目前使用的k8s版本是1.22.0,所有这里直接clone的版本为release-0.9

clone源代码

git clone -b release-0.9 https://github.com/prometheus-operator/kube-prometheus.git

所有的安装文件在目录mainfests下面,默认的部分镜像为国外镜像源,国内无法拉取,这里有两种方法,一种是本地挂代理拉取镜像后推到国内的镜像仓库。没有代理的话,可以修改镜像源到国内。这里不再赘述,自行选择。所有镜像准备就绪后开始安装。

具体的安装就是执行所有的yaml文件

# 这里使用create命令来创建setup下面的资源,不然可能会报错
kubectl create -f manifests/setup/
# 安装所有的组件
kubectl apply -f manifests/
# 默认安装的命名空间为monitoring,查看安装信息
kubectl get all -n monitoring
# 外部访问相应组件,需要开启服务暴露,默认的暴露方式为clusterIP,可以修改为NodePort或者使用ingress,我这里直接使用ingress

这里仅仅使用ingress暴露了grafana组件,prometheus,alertmanager采用NodePort方式

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grafana
  namespace: monitoring
  annotations:
    kubernetes.io/ingress.class: "nginx"
    prometheus.io/http_probe: "true"
spec:
  tls:
  - hosts: 
    - grafana.xxx.com          
    secretName: xxx-com      #没有证书可以跳过此配置
  rules:
  - host: grafana.xxx.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: grafana
            port:
              number: 3000
status:
  loadBalancer: {}  

配置完成后添加解析即可通过grafana.xxx.com来访问grafana,默认的用户名密码均为admin,安装完成后grafana默认提供了一些k8s的图表,可以在Default下面找到,如下图

到此所有的安装已经完成,如果想要进行一些个性化的配置,比如说修改告警阈值、配置自定义监控等,可以修改yaml文件来自定义,可以将mainfests下面的所有文件存放在gitlab上进行prometheus版本配置,方便以后的管理。

使用这种方式部署的prometheus查看targets会发现自带的kube-controller-manager和kube-scheduler监控全部是down的状态,alertmanager也会进行告警这两个组件不健康,出现这个问题的原因在于ServiceMonitor是通过service来进行自动发现的,但是使用kubeadm创建的集群默认不会创建这两个服务的service,所有需要手动去创建这两个service,具体文件如下:

apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-scheduler
  labels: 
    app.kubernetes.io/name: kube-scheduler
spec:
  selector:
    component: kube-scheduler
  ports:
    - name: https-metrics
      port: 10259
      targetPort: 10259 # 需要注意现在版本默认的安全端口是10259
---
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-controller-manager
  labels:
    app.kubernetes.io/name: kube-controller-manager
spec:
  selector:
    component: kube-controller-manager
  ports:
    - name: https-metrics
      port: 10257
      targetPort: 10257 # controller-manager 的安全端口为10257

执行这两个文件后,监控页面会报错connect: connection refused,这是因为 kube-scheduler 和kube-controller-manager启动的时候默认绑定的是 127.0.0.1 地址,--bind-address 参数指定该组件监听的 IP 地址,可以设置为节点的 IP 地址或者 127.0.0.1(表示只监听本地回环地址)。如果设置为节点的 IP 地址,则该组件会绑定在该节点的所有接口上,可以接收来自其他节点的访问请求;如果设置为 127.0.0.1,则该组件只能接受来自本地的访问请求,即只能被当前节点上的其他进程访问。所以要通过 IP 地址去访问就被拒绝了,我们可以查看 master 节点上的静态 Pod 资源清单来确认这一点,具体路径为k8s-master节点上的/etc/kubernetes/manifests/kube-scheduler.yaml,/etc/kubernetes/manifests/ kube-controller-manager.yaml,只需要分别修改--bind-address=127.0.0.1 更改为 --bind-address=0.0.0.0 即可,修改完成后服务会自动重启,此时就可以正常获取到监控信息。

4 使用prometheus监控外部MySQL服务

由于prometheus部署在k8s集群中,所以如果需要监控外部MySQL服务需要使用mysql-exporter容器来采集数据,这里多说一句,如果是外部prometheus服务,即prometheus直接使用二进制启动在linux服务器上,用了监控MySQL是非常简单的,只需要去下载官方的mysql-exporter运行在mysql服务器上,再在prometheus.yml配置文件里面新增即可,具体可查看链接:https://github.com/prometheus/mysqld_exporter/
回到现在,使用kube-prometheus监控MySQL的具体思路大概就是集群里面部署一个mysql-exporter去采集MySQL服务指标,在通过ServiceMonitor把采集好的数据自动可以让prometheus自动识别,具体的配置文件如下,该配置文件有三个资源,其中deployment为mysql-exporter服务,用来监控外部MySQL实例, Service用来暴露服务端口,ServiceMonitor用来是prometheus自动发现配置

# mysql-exporter.yaml
apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: mysql-exporter 
  namespace: monitoring 
spec:
  replicas: 1 
  selector:
    matchLabels:
      k8s-app: mysql-exporter 
  template:
    metadata:
      labels:
        k8s-app: mysql-exporter 
    spec:
      containers:
      - image:  prom/mysqld-exporter 
        name: mysqld-beta-exporter 
        env:
          - name: DATA_SOURCE_NAME  
            value: "mysql_monitor:123456@(192.168.0.1:3306)/" # 外部mysql第一个实例,此处可优化成使用k8s-secret来配置密码
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9104 # 默认端口9104
      - image:  prom/mysqld-exporter 
        name: mysqld-ga-exporter 
        command: [ "sh","-c","/bin/mysqld_exporter --web.listen-address=':9003'"] #修改第二个容器的服务暴露端口,不然会冲突
        env:
          - name: DATA_SOURCE_NAME # 
            value: "mysql_monitor:123456@(192.168.0.2:3306)/" # 外部mysql第二个实例,如果只有一个实例需要监控,可以删除第二个容器配置
        imagePullPolicy: IfNotPresent 
        ports:
        - containerPort: 9003  
---
apiVersion: v1 
kind: Service 
metadata:
  name: mysql-exporter 
  namespace: monitoring 
  labels:
    k8s-app: mysql-exporter
    mingcheng: dnsxmu 
spec:
  ports:
  - port: 9104 
    protocol: TCP 
    name: api-beta
  - port: 9003 
    protocol: TCP
    name: api-ga
  selector:
    k8s-app: mysql-exporter 
  type: ClusterIP 
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: mysql-exporter 
  namespace: monitoring 
  labels:
    k8s-app: mysql-exporter 
spec:
  endpoints:
    - interval: 10s  
      port: api-beta 
      scheme: http 
    - interval: 10s  
      port: api-ga
      scheme: http 
  selector:
    matchLabels:
      k8s-app: mysql-exporter 
  namespaceSelector:
    matchNames:
    - monitoring 

执行以上文件

kubectl apply -f mysql-exporter.yaml

等所有服务正常起来后,查看prometheus targets监控

可以看到此时已可以正常获取到监控信息,接下来去grafana添加仪表盘,grafana仪表盘市场搜索MySQL,有个表盘MySQL Overview,复制表盘ID,7262,到grafana导入dashboard,即可查看mysql监控信息,如下图

到此监控mysql完成。

5 配置钉钉告警

AlertManager是一款告警程序,首先由prometheus配置告警规则,当告警规则触发后,会把告警信息推送给Altermanager,AlertManager收到告警之后在根据配置的路由,根据报警级别不同分别发送给不同的receive(收件人),AlertManager可以实现email、企业微信等报警。Prometheus作为客户端Alertmanager负责处理由客户端发来的告警通知。对告警通知进行分组、去重后,根据路由规则将其路由到不同的receiver。

配置钉钉告警首先需要创建钉钉机器人,此处不赘述,钉钉机器人创建完成后,写入到dingtalk config.yml

templates:
      - /etc/prometheus-webhook-dingtalk/dingding.tmpl
    webhook:
      k8s:
        url: https://oapi.dingtalk.com/robot/send?access_token=    #配置webhook地址
        secret: "SEC***"     #生成的secret
        message:
          text: '{{ template "dingtalk.to.message" . }}'   #需要引用的模板名

接着创建告警模板

{{ define "dingtalk.to.message" }}

{{- if gt (len .Alerts.Firing) 0 -}}
{{- range $index, $alert := .Alerts -}}

=========  **监控告警** =========  

**告警集群:**     k8s  
**告警类型:**    {{ $alert.Labels.alertname }}   
**告警级别:**    {{ $alert.Labels.severity }}  
**告警状态:**    {{ .Status }}   
**故障主机:**    {{ $alert.Labels.instance }} {{ $alert.Labels.device }}   
**告警主题:**    {{ .Annotations.summary }}   
**告警详情:**    {{ $alert.Annotations.message }}{{ $alert.Annotations.description}}   
**主机标签:**    {{ range .Labels.SortedPairs  }}  </br> [{{ .Name }}: {{ .Value | markdown | html }} ] 
{{- end }} </br>

**故障时间:**    {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  
========= = **end** =  =========  
{{- end }}
{{- end }}

{{- if gt (len .Alerts.Resolved) 0 -}}
{{- range $index, $alert := .Alerts -}}

========= **故障恢复** =========  
**告警集群:**     k8s
**告警主题:**    {{ $alert.Annotations.summary }}  
**告警主机:**    {{ .Labels.instance }}   
**告警类型:**    {{ .Labels.alertname }}  
**告警级别:**    {{ $alert.Labels.severity }}    
**告警状态:**    {{ .Status }}  
**告警详情:**    {{ $alert.Annotations.message }}{{ $alert.Annotations.description}}  
**故障时间:**    {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  
**恢复时间:**    {{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  

========= = **end** =  =========
{{- end }}
{{- end }}
{{- end }}

以上所有参数都会自动读取webhook的信息后自动填入

接着创建configmap将以上配置写入到k8s,dingtalk-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: dingtalk-cm
  namespace: monitoring
data:
  config.yml: |-
    templates:
      - /etc/prometheus-webhook-dingtalk/dingding.tmpl
    targets:
      webhook:
        url: https://oapi.dingtalk.com/robot/send?access_token=***
        secret: "SEC***"
        message:
          text: '{{ template "dingtalk.to.message" . }}'
  dingding.tmpl: |-
    {{ define "dingtalk.to.message" }}
    {{- if gt (len .Alerts.Firing) 0 -}}
    {{- range $index, $alert := .Alerts -}}

    =========  **监控告警** =========  

    **告警集群:**     k8s 
    **告警类型:**    {{ $alert.Labels.alertname }}   
    **告警级别:**    {{ $alert.Labels.severity }}  
    **告警状态:**    {{ .Status }}   
    **故障主机:**    {{ $alert.Labels.instance }} {{ $alert.Labels.device }}   
    **告警主题:**    {{ .Annotations.summary }}   
    **告警详情:**    {{ $alert.Annotations.message }}{{ $alert.Annotations.description}}   
    **主机标签:**    {{ range .Labels.SortedPairs  }}  </br> [{{ .Name }}: {{ .Value | markdown | html }} ] 
    {{- end }} </br>

    **故障时间:**    {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  
    ========= = **end** =  =========  
    {{- end }}
    {{- end }}

    {{- if gt (len .Alerts.Resolved) 0 -}}
    {{- range $index, $alert := .Alerts -}}

    ========= **故障恢复** =========  
    **告警集群:**     k8s
    **告警主题:**    {{ $alert.Annotations.summary }}  
    **告警主机:**    {{ .Labels.instance }}   
    **告警类型:**    {{ .Labels.alertname }}  
    **告警级别:**    {{ $alert.Labels.severity }}    
    **告警状态:**    {{ .Status }}  
    **告警详情:**    {{ $alert.Annotations.message }}{{ $alert.Annotations.description}}  
    **故障时间:**    {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  
    **恢复时间:**    {{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}  

    ========= = **end** =  =========
    {{- end }}
    {{- end }}
    {{- end }}

执行命令

kubectl apply -f dingtalk-configmap.yaml

创建dingtalk.yaml

apiVersion: v1
kind: Service
metadata:
  name: dingtalk
  namespace: monitoring
spec:
  selector:
    app: dingtalk
  ports:
    - name: http
      protocol: TCP
      port: 8060
      targetPort: 8060
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dingtalk
  namespace: monitoring
  labels:
    app: dingtalk
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels:
      app: dingtalk
  template:
    metadata:
      labels:
        app: dingtalk
    spec:
      restartPolicy: "Always"
      containers:
      - name: dingtalk
        image: timonwong/prometheus-webhook-dingtalk
        imagePullPolicy: "IfNotPresent"
        volumeMounts:
          - name: dingtalk-conf
            mountPath: /etc/prometheus-webhook-dingtalk/
        resources:
          limits:
            cpu: "400m"
            memory: "500Mi"
          requests:
            cpu: "100m"
            memory: "100Mi"
        ports:
        - containerPort: 8060
          name: http
          protocol: TCP 
        readinessProbe:
          failureThreshold: 3
          periodSeconds: 5
          initialDelaySeconds: 30
          successThreshold: 1
          tcpSocket:
            port: 8060
        livenessProbe:
          tcpSocket:
            port: 8060
          initialDelaySeconds: 30
          periodSeconds: 10
      volumes:
        - name: dingtalk-conf
          configMap:
            name: dingtalk-cm

部署该文件,该文件提供一个http服务来为alertmanager提供告警地址,该地址会调用配置好的webhook服务来发送告警信息,具体的调用地址格式为

http😕/dingtalk:8060/dingtalk/"你的钉钉webhook名字"/send,按照文档配置,则地址为http😕/dingtalk:8060/dingtalk/webhook/send

接着配置告警规则,创建文件alertmanager.yaml

global:
  resolve_timeout: 5m  #解析超时时间,也就是报警恢复不是立马发送的,而是在一个时间范围内不在触发报警,才能发送恢复报警,默认为5分钟
receivers:
- name: 'null'   #定义一个为null的接受者
- name: 'webhook'  #钉钉webhook
  webhook_configs:
  - url: 'http://dingtalk:8060/dingtalk/webhook/send'
    send_resolved: true  #告警解决发送
route:
  group_by: ['job']  #采用哪个标签作为分组
  group_wait: 30s   # 当一个新的报警分组被创建后,需要等待至少group_wait时间来初始化通知,这种方式可以确保您能有足够的时间为同一分组来获取多个警报,然后一起触发这个报警信息
  group_interval: 5m   # 当第一个报警发送后,等待'group_interval'时间来发送新的一组报警信息
  repeat_interval: 12h   # 如果一个报警信息已经发送成功了,等待'repeat_interval'时间来重新发送他们
  receiver: "webhook" #默认的receiver:如果一个报警没有被一个route匹配,则发送给默认的接收器
  routes:   #子路由
  - match:
      severity: 'info'   
    continue: true
    receiver: 'null'
  - match:
      severity: 'none'
    continue: true
    receiver: 'null'  #过滤级别为info和none的告警

此处配置可以根据自己的实际情况进行更改,我这里直接过滤掉了级别为info和none的告警

alertmanager的告警规则功能强大,这里简单介绍一下告警路由配置,路由配置可以将不同的告警级别分别发送给不同的接收人,route配置段支持定义“树”状路由表,入口位置称为根节点,比如上面的配置文件route就是根节点,每个子节点可以基于匹配条件定义出一个独立的路由分支,下面的routes就是子节点,所有告警都将进入路由根节点,而后进行子节点遍历,若路由上的continue字段的值为false,则遇到第一个匹配的路由分支后即终止;否则,将继续匹配后续的子节点。支持正则表达式匹配。配置完成后即可在钉钉接受到告警信息,效果如下

恢复通知

posted @   pollosD  阅读(2137)  评论(0编辑  收藏  举报
编辑推荐:
· [杂谈]如何选择:Session 还是 JWT?
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· JavaScript是按顺序执行的吗?聊聊JavaScript中的变量提升
· [杂谈]后台日志该怎么打印
· Pascal 架构 GPU 在 vllm下的模型推理优化
阅读排行:
· WinForm 通用权限框架,简单实用支持二次开发
· 如何为在线客服系统的 Web Api 后台主程序添加 Bootstrap 启动页面
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· 面试官:DNS解析都整不明白,敢说你懂网络?我:嘤嘤嘤!
· Fleck:一个轻量级的C#开源WebSocket服务端库
点击右上角即可分享
微信分享提示