一.前言
本文将带你一步步实现一个完整的 Kubernetes 集群监控和告警系统:通过 Prometheus 采集实时数据,利用 Grafana 进行可视化展示,并结合 Alertmanager 实现告警推送。告警信息将通过 钉钉机器人 和 邮件 双重方式及时通知到相关人员,确保在问题发生的第一时间就能响应并处理。
如果你正在面临 Kubernetes 集群管理中的监控困扰,或者希望优化现有的监控系统,这篇文章将是你最佳的参考。
二. 架构概览
为了实现高效的 Kubernetes 集群监控,我们选择了以下技术栈:
- Prometheus:作为监控系统的核心,用于采集和存储集群的各类指标数据。
- Grafana:用来展示 Prometheus 中采集到的指标数据,生成各种可视化的仪表盘。
- Alertmanager:处理 Prometheus 生成的告警,并通过钉钉机器人和邮件通知相关人员。
- 钉钉机器人:实时推送告警消息到指定的钉钉群,确保运维人员能够及时响应。
- 邮件通知:备用的通知方式,适合长时间无法接入钉钉的人员。
架构图如下:
在我们的架构中,Prometheus 的 Agent 模式 是关键组件。我们配置了 Prometheus 将采集到的 Kubernetes 指标通过 remote_write 发送到远程的 Prometheus 实例。
准备机器 (一个k8s集群和一台物理机)
| name | ip |
|---|---|
| k8s-master | 192.168.197.131 |
| k8s-node1 | 192.168.197.141 |
| k8s-node2 | 192.168.197.142 |
| prometheus-remote | 192.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 无数据"
文件效果
在prometheus docker-compose.yaml 所在目录,运行docker-compose up 启动
若启动无报错,推荐后台启动 docker-compose up -d
访问UI界面 http://192.168.197.137:30090/
恭喜!如果访问成功 说明远程中心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-exporter 和 kube-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
确保都是running 访问 http://192.168.197.131:9090/
部署完成。
四. 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
安装并配置 Grafana 后,配置Prometheus 数据源将其与集群的监控数据进行连接。
接着,我们导入仪表盘。
grafana.com/grafana/das…
看看效果
更多仪表盘详见: 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/
部署完成后,别忘记了配置中心prometheuse的 alertmanage地址 prometheus.yml
通过 Alertmanager,我们将告警给相关人员,确保运维团队能够迅速响应。
邮件通知效果
1. 结合钉钉机器人与邮件通知
首先,在钉钉创建一个群组
在群设置中添加机器人-->自定义-->添加 填写配置好之后点击完成即可,这样就会创建一个test的报警机器人,然后会生成一个webhook链接
安装钉钉的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
重启服务后,查看最终通知效果。
这样就同时实现了 Alertmanager 的钉钉通知和邮件通知的通道。
六. 最后
谢谢您的阅读,如果部署有问题的同学,欢迎在下面留言!