《从零到一搭建 Kubernetes 集群监控系统:Prometheus、Grafana、钉钉/邮件告警全流程》

386 阅读8分钟

一.前言

本文将带你一步步实现一个完整的 Kubernetes 集群监控和告警系统:通过 Prometheus 采集实时数据,利用 Grafana 进行可视化展示,并结合 Alertmanager 实现告警推送。告警信息将通过 钉钉机器人邮件 双重方式及时通知到相关人员,确保在问题发生的第一时间就能响应并处理。

如果你正在面临 Kubernetes 集群管理中的监控困扰,或者希望优化现有的监控系统,这篇文章将是你最佳的参考。

二. 架构概览

image.png 为了实现高效的 Kubernetes 集群监控,我们选择了以下技术栈:

  • Prometheus:作为监控系统的核心,用于采集和存储集群的各类指标数据。
  • Grafana:用来展示 Prometheus 中采集到的指标数据,生成各种可视化的仪表盘。
  • Alertmanager:处理 Prometheus 生成的告警,并通过钉钉机器人和邮件通知相关人员。
  • 钉钉机器人:实时推送告警消息到指定的钉钉群,确保运维人员能够及时响应。
  • 邮件通知:备用的通知方式,适合长时间无法接入钉钉的人员。

架构图如下:

image.png

在我们的架构中,Prometheus 的 Agent 模式 是关键组件。我们配置了 Prometheus 将采集到的 Kubernetes 指标通过 remote_write 发送到远程的 Prometheus 实例。

准备机器 (一个k8s集群和一台物理机)

nameip
k8s-master192.168.197.131
k8s-node1192.168.197.141
k8s-node2192.168.197.142
prometheus-remote192.168.197.137

三. 安装配置 Prometheus 作为监控系统

首先先安装远程中心的prometheus(最好采用一台单独物理机部署,本文中是以docker-compose 部署)

1.docker-compose 部署远程中心prometheus

docker-compose.yaml内容如下:

version: '2'
services:
  prometheus-server:
    image: prom/prometheus:v2.54.1
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --web.listen-address=0.0.0.0:9090
      - --web.console.libraries=/usr/share/prometheus/console_libraries
      - --web.console.templates=/usr/share/prometheus
      - --storage.tsdb.retention=30d        # 数据的保留时间为 30 天
      - --web.enable-lifecycle
      - --enable-feature=promql-at-modifier
      - --web.enable-remote-write-receiver  # 启用远程写接收(用于agent模式)
    ports:
    - 30090:9090   # 端口映射
    user: root     # 以root 用户身份运行容器 避免权限问题
    volumes:
    - /data/prometheus/config:/etc/prometheus  # 配置文件和rule文件挂载
    - /data/prometheus/data:/prometheus        # 存储目录挂载
    restart: always

command 参数解释

  • --config.file=/etc/prometheus/prometheus.yml : 指定 Prometheus 配置文件路径
  • --storage.tsdb.path=/prometheus : 设置 Prometheus TSDB 数据存储路径
  • --web.listen-address=0.0.0.0:9090 : Prometheus Web UI 监听所有地址的 9090 端口
  • --web.console.libraries=/usr/share/prometheus/console_libraries : 设置控制台库的位置
  • --web.console.templates=/usr/share/prometheus : 设置控制台模板的位置
  • --storage.tsdb.retention=30d : 设置数据的保留时间为 30 天 (默认15天)
  • --web.enable-lifecycle : 启用 Prometheus 的生命周期管理(例如重新加载配置)
  • --enable-feature=promql-at-modifier : 启用 PromQL 中的 at 修饰符(可以用于时间窗口)
  • --web.enable-remote-write-receiver : 启用远程写接收

创建挂载文件夹

mkdir -p /data/prometheus/{config,data}

prometheus.yml配置文件

global:
  scrape_interval: 2m  # 设置抓取间隔为每 2 分钟一次(默认是每分钟一次)
  evaluation_interval: 2m  # 设置规则评估间隔为每 2 分钟一次
  scrape_timeout: 2m  # 设置抓取超时时间为 2 分钟

# Alertmanager 配置:定义 Prometheus 发送警报的目标地址 等部署了Alertmanager再配置
#alerting:
#  alertmanagers:
#  - static_configs:
#    - targets: ["192.168.197.137:9093"]  # 设置 Alertmanager 地址,Prometheus 将警报发送到该地址 

# 规则文件配置:加载 Prometheus 的规则文件
rule_files:
  - "/etc/prometheus/*_rules.yml"  # 加载所有 *_rules.yml 文件(可添加更多规则文件)
 
# Scrape 配置:定义 Prometheus 从哪里抓取数据
scrape_configs:
  # Prometheus 自身监控配置
  - job_name: 'prometheus'
    static_configs:
    - targets: ['127.0.0.1:9090']  # Prometheus 监控自己,默认地址是 localhost:9090

创建一些简单的规则,更多详细规则可参考:samber.github.io/awesome-pro…

groups:
  - name: Prometheus1推送告警
    rules:
        # 【这是一个判断k8s集群的prometheus是否往远程中心推送数据的规则】
      - alert: "Prometheus1推送离线"
        expr: absent(up{job=~"prometheus", project=~"prometheus1"}) == 1
        for: 3m
        labels:
          severity: critical
        annotations:
          description: '远程写 Prometheus1 无数据'
          summary: "远程写 Prometheus1 无数据"

文件效果

image.png

在prometheus docker-compose.yaml 所在目录,运行docker-compose up 启动

image.png

若启动无报错,推荐后台启动 docker-compose up -d

访问UI界面 http://192.168.197.137:30090/

image.png 恭喜!如果访问成功 说明远程中心prometheus 已搭建成功!接下来开始部署k8s中的prometheus-agent

2.helm 部署k8s集群prometheus-agent模式

采用helm包通过编辑values 的方式实现快速部署 本文是离线下载prometheus-25.8.0.tgz 为社区提供的chart, 可以通过如下方式获取最新版本:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm fetch prometheus-community/prometheus

离线包可在github社区自行下载:github.com/prometheus-…

也可以直接采用我这个包: pan.baidu.com/s/1bP8-J5Jl…

提取码: tyyh

该chart默认会安装prometheus-node-exporterkube-state-metrics

新建values.yaml

configmapReload:
  prometheus:
    enabled: true
    image:
      repository: registry.cn-hangzhou.aliyuncs.com/base_doc/prometheus-config-reloader
      tag: v0.67.0
      digest: ""
      pullPolicy: IfNotPresent

    resources:
      limits:
        cpu: 50m
        memory: 30Mi
      requests:
        cpu: 50m
        memory: 30Mi

server:
  image:
    repository: registry.cn-hangzhou.aliyuncs.com/base_doc/prometheus

  defaultFlagsOverride:
    - --enable-feature=agent
    - --storage.agent.retention.max-time=720m
    - --config.file=/etc/config/prometheus.yml

  persistentVolume:
    enabled: false  # 不启用持久化卷

  emptyDir:
    sizeLimit: "8Gi"  # 设置临时存储目录的大小限制为 8Gi

  remoteWrite:
    - url: http://192.168.197.137:30090/api/v1/write  # 远程中心prometheus的地址

  global:
    external_labels:
      k8scluster: demo  # 集群标签
      origin_prometheus: demo  # 设置全局标签 origin_prometheus

serverFiles:
  prometheus.yml:
    rule_files: []
    scrape_configs:
    - job_name: 'kubernetes-apiservers'
      kubernetes_sd_configs:
      - role: endpoints
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
        action: keep
        regex: default;kubernetes;https

    - job_name: 'kubernetes-cadvisor'
      kubernetes_sd_configs:
      - role: node
      scheme: https
      tls_config:
        ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
      - target_label: __address__
        replacement: kubernetes.default.svc:443
      - source_labels: [__meta_kubernetes_node_name]
        regex: (.+)
        target_label: __metrics_path__
        replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

    - job_name: 'kubernetes-service-endpoints'
      kubernetes_sd_configs:
      - role: endpoints
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
        action: replace
        target_label: __scheme__
        regex: (https?)
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        action: replace
        target_label: kubernetes_name

    - job_name: 'kubernetes-services'
      kubernetes_sd_configs:
      - role: service
      metrics_path: /probe
      params:
        module: [http_2xx]
      relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
        action: keep
        regex: true
      - source_labels: [__address__]
        target_label: __param_target
      - target_label: __address__
        replacement: blackbox-exporter.example.com:9115
      - source_labels: [__param_target]
        target_label: instance
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_service_name]
        target_label: kubernetes_name

    - job_name: 'kubernetes-ingresses'
      kubernetes_sd_configs:
      - role: ingress
      relabel_configs:
      - source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_probe]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
        regex: (.+);(.+);(.+)
        replacement: ${1}://${2}${3}
        target_label: __param_target
      - target_label: __address__
        replacement: blackbox-exporter.example.com:9115
      - source_labels: [__param_target]
        target_label: instance
      - action: labelmap
        regex: __meta_kubernetes_ingress_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_ingress_name]
        target_label: kubernetes_name

    - job_name: 'kubernetes-pods'
      kubernetes_sd_configs:
      - role: pod
      relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
      - action: labelmap
        regex: __meta_kubernetes_pod_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: kubernetes_namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: kubernetes_pod_name

alertmanager:
  ## 如果设置为 false,则不安装 Alertmanager
  ##
  enabled: false

  persistence:
    size: 2Gi  # 设置 Alertmanager 的持久化存储大小

  podSecurityContext:
    runAsUser: 65534  # 运行时的用户 ID
    runAsNonRoot: true  # 强制容器以非 root 用户运行
    runAsGroup: 65534  # 运行时的用户组 ID
    fsGroup: 65534  # 设置文件系统组 ID

## 请参考:https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics
kube-state-metrics:
  enabled: true
  image:
    registry: registry.cn-hangzhou.aliyuncs.com
    repository: base_doc/kube-state-metrics
    tag: v2.10.1

## prometheus-node-exporter 子图表配置项
## 请参考:https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter
prometheus-node-exporter:
  ## 如果设置为 false,则不安装 node-exporter
  enabled: true
  image:
    registry: registry.cn-hangzhou.aliyuncs.com
    repository: base_doc/node-exporter
    tag: v1.7.0

  rbac:
    pspEnabled: false  # 禁用 Pod 安全策略

  containerSecurityContext:
    allowPrivilegeEscalation: false  # 不允许权限升级

## prometheus-pushgateway 子图表配置项
## 请参考:https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-pushgateway
prometheus-pushgateway:
  enabled: false

安装部署

helm -n prometheus upgrade --install prometheus prometheus-25.8.0.tgz -f values.yaml --create-namespace

查看状态 kubectl get -n prometheus pod image.png

确保都是running 访问 http://192.168.197.131:9090/

image.png

部署完成。

四. Grafana 的安装与配置

在192.168.197.137物理机上 下载安装grafana ,这个地方演示用的本地安装,生产环境建议docker

wget https://dl.grafana.com/enterprise/release/grafana-enterprise-9.5.3.linux-amd64.tar.gz
tar -zxvf grafana-enterprise-9.5.3.linux-amd64.tar.gz
cd grafana-9.5.3/

# 重置grafana密码
./grafana-cli admin reset-admin-password admin123 

#启动grafana
./grafana server

访问 http://192.168.197.137:3000 用户密码就是刚刚重置的admin admin123 image.png

安装并配置 Grafana 后,配置Prometheus 数据源将其与集群的监控数据进行连接。

image.png

接着,我们导入仪表盘。 grafana.com/grafana/das… image.png

image.png

看看效果

image.png

image.png

更多仪表盘详见: grafana.com/dashboards?…

五. 设置 Alertmanager 实现告警推送

告警规则的配置非常重要,我们通过设置告警条件来确保当 Kubernetes 集群中某些关键资源超载时,能够及时通知到相关人员。以下是一个 CPU 使用率过高的告警规则示例:

groups:
  - name: example
    rules:
      - alert: HighCPUUsage
        expr: sum(rate(container_cpu_usage_seconds_total[5m])) by (pod) / sum(container_spec_cpu_quota) by (pod) > 0.9
        for: 2m
        annotations:
          summary: "CPU usage is over 90% for pod {{ $labels.pod }}"
          
       # 测试告警
      - alert: "ImmediateTestAlert2"
        expr: vector(1)  # 始终为 1,告警条件始终成立
        for: 0s  # 无等待,告警立即触发并持续触发
        labels:
          severity: error
        annotations:
          description: '这是一个测试告警,立即触发并持续发送'
          summary: "测试用的告警,持续触发以测试 Alertmanager"

更新规则后 重启prometheus 或热加载(建议热加载)

# 检查配置文件语法是否正确
docker exec prometheus-prometheus-server-1 promtool check config /etc/prometheus/prometheus.yml

# 发送热加载信号
docker exec prometheus-prometheus-server-1 kill -HUP 1 

创建挂载文件夹

mkdir -p /data/alertmanager/{data,config}

配置config 文件,并配置邮件通知

global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.163.com:25'
  smtp_from: 'xxxx@163.com' # 发送者
  smtp_auth_username: 'xxxxxx@163.com'
  smtp_auth_password: 'xxxx' #网易邮箱有个三方授权密码 这个地方使用的是授权密码 在设置中可以申请
  smtp_require_tls: false

route:              # 路由
  receiver: default
  group_wait: 1m
  group_interval: 1m
  repeat_interval: 4h
  group_by: ['alertname', 'k8scluster', 'namespace', 'pod', 'container', 'node', 'exported_job', 'daemonset'] # 分组

receivers:            # 接收者
- name: default
  email_configs:
  - to: 'xxxx@qq.com' # 目标邮箱
    send_resolved: true 

docker-compose安装Alertmanager

version: "2"
services:
  alertmanager-server:
    #image: prom/alertmanager:v0.15.2
    image: prom/alertmanager:v0.22.0-rc.2
    command:
      - --config.file=/etc/alertmanager/config.yml
      - --storage.path=/alertmanager
      - --data.retention=720h
    user: root
    ports:
    - 9093:9093
    volumes:
    - /data/alertmanager/config:/etc/alertmanager/
    - /data/alertmanager/data:/alertmanager
    restart: always

启动docker-compose up -d 访问http://192.168.197.137:9093/

image.png

部署完成后,别忘记了配置中心prometheuse的 alertmanage地址 prometheus.yml

image.png

通过 Alertmanager,我们将告警给相关人员,确保运维团队能够迅速响应。

邮件通知效果

image.png

1. 结合钉钉机器人与邮件通知

首先,在钉钉创建一个群组

在群设置中添加机器人-->自定义-->添加 填写配置好之后点击完成即可,这样就会创建一个test的报警机器人,然后会生成一个webhook链接

image.png

安装钉钉的webhook插件 prometheus-webhook-dingtalk-0.3.0.linux-amd64.tar.gz pan.baidu.com/s/1vFyQ_ln-…

提取码: tyyh

tar -zxvf prometheus-webhook-dingtalk-0.3.0.linux-amd64.tar.gz
cd prometheus-webhook-dingtalk-0.3.0.linux-amd64

# 启动
nohup ./prometheus-webhook-dingtalk --web.listen-address="0.0.0.0:8060" --ding.profile="cluster1=这个地方填写刚刚的webhook链接" &

alertmanage配置文件新增钉钉接收方式 ,在配置文件中default的receivers下新增

  webhook_configs:
  - url: "http://192.168.197.137:8060/dingtalk/cluster1/send"
    send_resolved: true

image.png

重启服务后,查看最终通知效果。

image.png

这样就同时实现了 Alertmanager 的钉钉通知和邮件通知的通道。

六. 最后

谢谢您的阅读,如果部署有问题的同学,欢迎在下面留言!