prometheus安装部署
k8s安装helm,prometheus+grafana+alertmanager部署。
默认两台虚拟机已经部署好k8s。
虚拟机ubuntu 24 live server 192.168.201.134,k8s-master,v1.35
虚拟机ubuntu 24 live server 192.168.201.135,k8s-node1,v1.35
感觉不如openclaw
文章目录
1. 名词解释
为了更好地理解本部署指南,以下是文档中涉及到的关键概念和术语的详细解释:
| 术语 | 英文全称/类型 | 解释 |
|---|---|---|
| Prometheus | Time-series Database & Monitoring System | 一个开源的监控系统,以拉取(pull)模式从配置的目标(targets)收集指标,并将其存储在时间序列数据库中。它支持强大的查询语言 PromQL,并能触发告警。 |
| Grafana | Data Visualization Platform | 一个开源的数据可视化和分析平台,常与 Prometheus 配合使用,通过创建交互式仪表盘来展示和分析 Prometheus 收集到的指标数据。 |
| Alertmanager | Alerting System | Prometheus 的配套告警管理系统。它接收来自 Prometheus 的告警,进行去重、分组、抑制,并路由到各种通知接收器(如邮件、Webhook、Slack 等)。 |
| PromQL | Prometheus Query Language | Prometheus 提供的功能强大的查询语言,用于实时选择和聚合时间序列数据。 |
| Exporter | Metric Exporter | 一个中间件,用于从第三方系统(如数据库、消息队列、操作系统等)收集指标,并将其转换为 Prometheus 可识别的格式暴露出来,供 Prometheus 拉取。 |
| ServiceMonitor | Kubernetes Custom Resource Definition (CRD) | Prometheus Operator 引入的自定义资源,用于声明式地定义 Prometheus 应该如何发现和监控 Kubernetes Service。Prometheus Operator 会根据 ServiceMonitor 自动生成 Prometheus 的抓取配置。 |
| PrometheusRule | Kubernetes Custom Resource Definition (CRD) | Prometheus Operator 引入的自定义资源,用于在 Kubernetes 中定义 Prometheus 的告警规则和记录规则。 |
| Prometheus Operator | Kubernetes Operator | 一个 Kubernetes Operator,它简化了在 Kubernetes 上部署和管理 Prometheus、Alertmanager 和相关组件的复杂性。它通过 CRD(如 ServiceMonitor、PrometheusRule)来管理 Prometheus 资源。 |
| kube-prometheus-stack | Helm Chart | 一个 Helm Chart,包含了在 Kubernetes 上部署完整 Prometheus 监控栈所需的所有组件,包括 Prometheus Operator、Prometheus、Alertmanager、Grafana、Node Exporter、Kube-state-metrics 等。 |
| NodePort | Kubernetes Service Type | Kubernetes Service 的一种类型,通过在每个节点上打开一个静态端口,将服务暴露到集群外部。外部流量可以通过 <NodeIP>:<NodePort> 访问服务。 |
| ClusterIP | Kubernetes Service Type | Kubernetes Service 的默认类型,为服务提供一个集群内部可访问的虚拟 IP 地址。服务只能在集群内部通过 <ClusterIP>:<Port> 访问。 |
| Deployment | Kubernetes Workload API Object | Kubernetes 中用于管理无状态应用的一种控制器。它定义了 Pod 的模板和副本数量,并确保 Pod 按照预期状态运行。 |
| Service | Kubernetes Service API Object | Kubernetes 中用于定义一组 Pod 的逻辑抽象和访问策略。它为 Pod 提供了一个稳定的网络端点。 |
| ConfigMap | Kubernetes API Object | Kubernetes 中用于存储非敏感配置数据的 API 对象。可以将配置数据以键值对的形式存储,并挂载到 Pod 中作为文件或环境变量使用。 |
| Dockerfile | Docker Build Instruction File | 一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。 |
| 多阶段构建 (Multi-stage Build) | Docker Build Technique | Dockerfile 中的一种优化技术,通过使用多个 FROM 指令,将构建环境和最终运行环境分离,从而减小最终镜像的体积。 |
| Helm | Kubernetes Package Manager | Kubernetes 的包管理工具,用于定义、安装和升级复杂的 Kubernetes 应用程序。通过 Helm Chart 可以方便地部署和管理应用。 |
| Kubelet | Kubernetes Agent | 运行在每个 Kubernetes 节点上的代理程序,负责管理 Pod 的生命周期,包括创建、启动、停止容器,并向 Master 报告节点和 Pod 的状态。 |
| cAdvisor | Container Advisor | 一个开源工具,用于收集、处理和导出运行中容器的性能指标(如 CPU、内存、网络、文件系统使用情况)。Prometheus 可以从 cAdvisor 抓取这些指标。 |
| Node Exporter | Prometheus Exporter | 一个官方的 Prometheus Exporter,用于收集 Linux/Unix 主机的硬件和操作系统指标,如 CPU 使用率、内存、磁盘 I/O、网络流量等。 |

prometheus不适用于每次请求计费。
--- 是 YAML 文档分隔符,用于在一个文件中定义多个独立的 YAML 文档。
Go 1.20+ 不允许在系统临时目录创建 go.mod。
Prometheus 中的告警状态通常有以下几种:
• Firing(触发):告警处于激活状态,表示某个指标的阈值条件已经满足,告警被触发。
• Pending(待处理):告警条件暂时没有触发,但正在等待进一步的评估,通常是因为设置了一个 for 时长,表示告警需要在一定时间内持续满足条件才会触发。
• Resolved(已解决):告警条件不再满足,告警已被解除,系统恢复正常。
2. 部署prometheus
1. 二进制安装(不建议)
虽然二进制安装最直接,但在 Kubernetes 环境中并不推荐,因为它缺乏自动化管理和动态发现能力。这里仅作为理解 Prometheus 配置结构的参考。
tar xvfz prometheus-*.tar.gz
cd prometheus-*
./prometheus --help
cat prometheus.yml
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]
# The label name is added as a label `label_name=<label_value>` to any timeseries scraped from this config.
labels:
app: "prometheus"
示例配置文件中有三个配置块:global、rule_files 和 scrape_configs。
global 块控制 Prometheus 服务器的全局配置。我们在这里提供了两个选项。第一个是 scrape_interval,它控制 Prometheus 抓取目标的频率。您可以为单个目标覆盖此设置。在此示例中,全局设置为每 15 秒抓取一次。
evaluation_interval 选项控制 Prometheus 评估规则的频率。Prometheus 使用规则来创建新的时间序列和生成警报。
rule_files 块指定 Prometheus 服务器要加载的任何规则的位置。目前我们没有设置任何规则。
最后一个块是 scrape_configs,它控制 Prometheus 监控的资源。由于 Prometheus 也通过 HTTP 端点公开关于自身的数据,因此它可以抓取和监控自身的运行状况。在默认配置中,有一个名为 prometheus 的作业,它抓取 Prometheus 服务器公开的时间序列数据。该作业包含一个静态配置的目标:端口 9090 上的 localhost。Prometheus 期望目标上的指标在 /metrics 路径可用。因此,此默认作业通过以下 URL 进行抓取:https://:9090/metrics 。
启动prometheus
./prometheus --config.file=prometheus.yml
https://prometheus.ac.cn/docs/visualization/consoles/#required-for-focus
2. k8s安装kube-prometheus-stack
这是目前 Kubernetes 生产环境中最推荐的部署方式。kube-prometheus-stack 是一套完整的监控方案,基于 Prometheus Operator,它极大地简化了在 K8s 中管理 Prometheus 及其相关组件的难度。
k8s-master 节点安装 Helm:
# 下载并安装 Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 验证安装
helm version
准备helm仓库和命名空间
# 添加 Prometheus 社区仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 创建独立的监控命名空间
kubectl create namespace monitoring
部署 kube-prometheus-stack:
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--set grafana.adminPassword=admin \
--set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
代码解释:
--namespace monitoring:将监控组件部署在独立的命名空间中。grafana.adminPassword=admin:设置 Grafana 的初始管理员密码。podMonitorSelectorNilUsesHelmValues=false和serviceMonitorSelectorNilUsesHelmValues=false:这是非常关键的两个设置。默认情况下,Prometheus 只会发现由当前 Helm Release 创建的监控目标。将它们设为false后,Prometheus 就会发现集群中所有命名空间下、带有匹配标签的ServiceMonitor和PodMonitor,这为我们后续部署自定义监控奠定了基础。
暴露服务,将 ClusterIP 改为 NodePort,以便从集群外部访问 UI:
# 暴露 Grafana (默认 3000 端口)
kubectl patch svc prometheus-grafana -n monitoring -p '{"spec": {"type": "NodePort"}}'
# 暴露 Prometheus (默认 9090 端口)
kubectl patch svc prometheus-kube-prometheus-prometheus -n monitoring -p '{"spec": {"type": "NodePort"}}'
# 暴露 Alertmanager (默认 9093 端口)
kubectl patch svc prometheus-kube-prometheus-alertmanager -n monitoring -p '{"spec": {"type": "NodePort"}}'
#暴露
查看随机分配的端口
root@k8s-master:/opt/prometheus# kubectl get svc -n monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 116m
prometheus-grafana NodePort 10.109.57.237 <none> 80:32212/TCP 118m
prometheus-kube-prometheus-alertmanager NodePort 10.101.30.101 <none> 9093:30513/TCP,8080:31354/TCP 118m
prometheus-kube-prometheus-operator ClusterIP 10.103.57.84 <none> 443/TCP 118m
prometheus-kube-prometheus-prometheus NodePort 10.109.142.32 <none> 9090:31442/TCP,8080:30576/TCP 118m
prometheus-kube-state-metrics ClusterIP 10.106.239.92 <none> 8080/TCP 118m
prometheus-operated ClusterIP None <none> 9090/TCP 116m
prometheus-prometheus-node-exporter ClusterIP 10.106.96.232 <none> 9100/TCP 118m
http://192.168.201.134:32212/
helm安装自带一些仪表盘,可以导入官方的或者自己的。



常见exporter
node_exporter 用于机器系统数据收集
mysqld-exporter 用于MySQL数据库数据收集
Cadvisor 用于收集宿主机上的docker容器数据
3. PromQL
PromQL 是 Prometheus 监控系统的灵魂。通过简单的表达式,你可以实现复杂的查询:
- 瞬时向量查询:如
up查看所有目标的在线状态。 - 范围向量查询:如
rate(http_requests_total[5m])计算过去 5 分钟的每秒请求速率。 - 聚合操作:如
sum by (instance) (node_cpu_seconds_total)按实例求和 CPU 使用时间。
prometheus
grafana
修改密码
GRAFANA_POD=$(kubectl get pod -n monitoring -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].metadata.name}')
echo "Resetting Grafana password..."
kubectl exec -n monitoring $GRAFANA_POD -c grafana -- grafana-cli admin reset-admin-password admin
alertmanager
4. 完整的 Kubernetes 自定义监控示例
叫ai帮我写个示例
https://gitee.com/googlecmd/custom-monitoring/tree/master
Exporter 暴露指标 → Prometheus 抓取指标 → Prometheus 评估告警规则
→ 告警触发(firing) → Alertmanager 接收告警 → Alertmanager 路由匹配
→ Webhook Receiver 收到 POST 请求
1. 架构概览
下图展示了本示例的整体部署架构。整个系统分为两个平面:监控平面(monitoring namespace)运行在 Master 节点上,包含 Prometheus、Alertmanager 和 Grafana 等核心监控组件;应用平面(demo-app namespace)运行在 Node 节点上,包含业务应用和自定义 Exporter。Prometheus 通过 ServiceMonitor 自动发现 Exporter 并定期抓取指标,Grafana 从 Prometheus 读取数据进行可视化展示,Alertmanager 则负责接收告警并路由到 Webhook 或邮件等通知渠道。
┌─────────────────────────────────────────────────────────────┐
│ k8s-master (192.168.201.134) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Prometheus │←─│ServiceMonitor│──│ Auto Discovery │ │
│ └──────┬──────┘ └──────────────┘ └───────────────────┘ │
│ │ │
│ ┌──────▼──────┐ ┌──────────────┐ │
│ │ Grafana │ │ AlertManager │ │
│ │ Dashboard │ │ Webhook │ │
│ └─────────────┘ └──────────────┘ │
│ │
│ namespace: monitoring │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ k8s-node1 (192.168.201.135) │
│ │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ Demo Order │ │ Order Exporter(Go) │ │
│ │ Application │ │ :2112/metrics │ │
│ │ :8080 │ │ │ │
│ └─────────────────┘ └──────────────────────┘ │
│ │
│ namespace: demo-app │
└─────────────────────────────────────────────────────────────┘
数据流说明: Demo Order Application 通过 /api/stats 接口暴露业务统计的 JSON 数据。Order Exporter 定期请求该接口,将 JSON 数据转换为 Prometheus 指标格式,并在自己的 :2112/metrics 路径上暴露。Prometheus 通过 ServiceMonitor 发现 Exporter 的 Service,并按照配置的间隔(15秒)拉取指标。当指标满足告警规则的条件时,Prometheus 将告警发送给 Alertmanager,Alertmanager 根据路由规则将通知推送到对应的 Webhook Receiver 或邮箱。
2. 项目架构
custom-monitoring/
├── app/
│ ├── main.go # 示例订单应用
│ ├── Dockerfile
│ └── go.mod
├── exporter/
│ ├── main.go # 自定义 Go Exporter
│ ├── Dockerfile
│ └── go.mod
├── k8s/
│ ├── 00-namespace.yaml
│ ├── 01-demo-app.yaml # 示例应用部署
│ ├── 02-exporter.yaml # Exporter 部署
│ ├── 03-servicemonitor.yaml # ServiceMonitor 自动发现
│ ├── 04-prometheus-rules.yaml # 告警规则
│ ├── 05-alertmanager-config.yaml # AlertManager 配置
│ └── 06-webhook-receiver.yaml # Webhook 接收器
├── grafana/
│ └── dashboard.json # Grafana Dashboard
├── build.sh # 一键构建脚本
└── deploy.sh # 一键部署脚本
目录说明: app/ 存放模拟业务应用(订单系统)的 Go 语言源代码和 Dockerfile;exporter/ 存放自定义 Exporter 的 Go 语言源代码和 Dockerfile;k8s/ 存放所有用于部署的 Kubernetes YAML 文件,并按部署顺序编号;grafana/ 存放用于导入 Grafana 的 Dashboard JSON 文件;build.sh 用于编译 Go 应用、构建 Docker 镜像并分发到集群各节点;deploy.sh 用于一键式地将 k8s/ 目录下的所有资源应用到集群中。
在开始之前,我们需要确认 Prometheus Operator 的一些关键配置,以确保它能发现我们后续创建的 ServiceMonitor 和 PrometheusRule。
root@k8s-master:~# kubectl get prometheus -n monitoring prometheus-kube-prometheus-prometheus -o yaml | grep -A 5 serviceMonitorSelector
serviceMonitorSelector: {}
shards: 1
tsdb:
outOfOrderTimeWindow: 0s
version: v3.9.1
walCompression: true
root@k8s-master:~# kubectl get prometheus -n monitoring prometheus-kube-prometheus-prometheus -o jsonpath='{.spec.ruleSelector}' && echo
{"matchLabels":{"release":"prometheus"}}
代码解释: 第一条命令检查 Prometheus 实例的 serviceMonitorSelector 配置。结果为 {} (空)表示 Prometheus 会发现并应用所有命名空间中的所有 ServiceMonitor 资源,没有标签限制。第二条命令检查 ruleSelector 配置,结果表明 Prometheus 只会加载那些带有 release: prometheus 标签的 PrometheusRule 资源。因此,我们在后续创建告警规则时必须加上这个标签,否则规则不会被 Prometheus 加载。
3. 示例订单应用
这是一个简单的 Go 应用,它模拟了一个订单处理服务。它会随机生成订单,并提供一个 /api/stats 端点来暴露内部的业务统计数据,这些数据将被 Exporter 读取并转换为 Prometheus 指标。
app/go.mod
module demo-order-app
go 1.22
require github.com/gorilla/mux v1.8.1
代码解释: 定义了项目的 Go 模块名称为 demo-order-app,依赖了 github.com/gorilla/mux 这个流行的 Go Web 路由库,用于处理 HTTP 请求的路由分发。
app/main.go
代码解释: 这个 Go 应用的核心逻辑包括以下几个部分:
Stats结构体:定义了我们关心的核心业务指标,包括总订单数、成功/失败订单数、总收入和按产品分类的订单统计。这些数据通过/api/stats接口以 JSON 格式暴露给 Exporter。simulateOrders():后台运行的 goroutine,无限循环,每隔 2-8 秒随机生成一笔新订单,模拟真实的业务流量。订单有 10% 的概率失败、5% 的概率处于待处理状态。getStats():/api/stats接口的处理器,返回当前内存中的Stats数据。Exporter 将定期调用这个接口来获取最新的业务数据。main():程序入口,设置 HTTP 路由(包括创建订单、列出订单、获取统计和健康检查),启动订单模拟器,并监听 8080 端口。
app/Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o demo-order-app .
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app/demo-order-app .
EXPOSE 8080
CMD ["./demo-order-app"]
代码解释: 这是一个标准的多阶段构建(multi-stage build)Dockerfile。第一阶段(builder)使用包含完整 Go 编译环境的 golang:1.22-alpine 镜像,下载依赖并编译出静态链接的可执行文件。第二阶段使用非常小巧的 alpine:3.19 作为最终镜像基础,只复制编译好的二进制文件。这样可以大大减小最终镜像体积,提高安全性和部署效率。CGO_ENABLED=0 确保编译不依赖 C 库,GOOS=linux 指定目标操作系统为 Linux。
4. 自定义 Go Exporter
Exporter 是一个独立的程序,它的职责是从目标应用(订单系统)获取数据,并将其转换为 Prometheus 指标格式。这种模式对于监控那些本身不支持 Prometheus 的老旧系统或第三方应用非常有用。
exporter/go.mod
module order-exporter
go 1.22
require (
github.com/prometheus/client_golang v1.19.0
)
代码解释: 定义了 Exporter 项目的 Go 模块名称,依赖了 github.com/prometheus/client_golang,这是 Prometheus 官方提供的 Go 客户端库,用于创建和暴露自定义指标。
exporter/main.go
代码解释: 这是 Exporter 的核心逻辑,它实现了 prometheus.Collector 接口,这是编写自定义 Exporter 的标准方式。
OrderCollector结构体:自定义收集器,包含所有指标的“描述符”(prometheus.Desc)。每个描述符定义了指标的名称、帮助文本和标签。例如orders_by_product_total定义了一个product标签,用于区分不同产品的订单数。Describe()方法:实现Collector接口的第一个方法,将所有指标描述符发送到 Prometheus。Prometheus 在注册 Collector 时调用此方法。Collect()方法:核心方法,每次 Prometheus 来抓取/metrics端点时都会被调用。它首先通过fetchStats()请求订单应用的/api/stats接口获取最新数据;如果获取失败,上报order_app_up=0表示应用宕机;如果成功,将 JSON 数据转换为 Prometheus 指标。注意指标类型的区分:orders_total是只增不减的计数器(CounterValue),而order_fail_rate是可增可减的仪表值(GaugeValue)。fetchStats()方法:通过 HTTP GET 请求目标应用的/api/stats接口,并将响应的 JSON 解码为Stats结构体。main()函数:创建并注册OrderCollector,然后使用promhttp.Handler()将/metrics路径与收集器关联,最后启动 HTTP 服务监听 2112 端口。
exporter/Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o order-exporter .
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app/order-exporter .
EXPOSE 2112
CMD ["./order-exporter"]
代码解释: 与订单应用的 Dockerfile 类似,同样采用多阶段构建,最终生成一个包含 order-exporter 可执行文件的轻量级 Alpine 镜像,并暴露 2112 端口供 Prometheus 抓取指标。
5. 构建镜像
在部署到 Kubernetes 之前,我们需要将 Go 应用和 Exporter 编译打包成 Docker 镜像。build.sh 脚本自动化了这个过程。
build.sh
#!/bin/bash
set -e
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
NODE1_IP="192.168.201.135"
NODE1_USER="root"
NODE1_PASS="root"
# ========== 检查 sshpass ==========
if ! command -v sshpass &> /dev/null; then
echo ""
echo "sshpass not found, installing..."
sudo apt-get update
sudo apt-get install -y sshpass
fi
echo "========== Building Demo Order App =========="
cd app
go mod tidy
cd ..
echo "========== Building Order Exporter =========="
cd exporter
go mod tidy
cd ..
echo "========== Building Docker Images =========="
# Method 1: Build directly on each node (recommended for simple setup)
# Build on master and save
export GOPROXY=https://goproxy.cn,direct
docker build -t demo-order-app:v1 ./app/
docker build -t order-exporter:v1 ./exporter/
# Save as tar for transfer
docker save demo-order-app:v1 -o /tmp/demo-order-app.tar
docker save order-exporter:v1 -o /tmp/order-exporter.tar
echo "========== Transferring images to node1 =========="
sshpass -p "${NODE1_PASS}" scp /tmp/demo-order-app.tar ${NODE1_USER}@${NODE1_IP}:/tmp/
sshpass -p "${NODE1_PASS}" scp /tmp/order-exporter.tar ${NODE1_USER}@${NODE1_IP}:/tmp/
# Also load on master (in case pods are scheduled on master)
ctr -n k8s.io images import /tmp/demo-order-app.tar
ctr -n k8s.io images import /tmp/order-exporter.tar
echo "========== Loading images on node1 =========="
sshpass -p "${NODE1_PASS}" ssh ${NODE1_USER}@${NODE1_IP} "ctr -n k8s.io images import /tmp/demo-order-app.tar"
sshpass -p "${NODE1_PASS}" ssh ${NODE1_USER}@${NODE1_IP} "ctr -n k8s.io images import /tmp/order-exporter.tar"
echo "========== Build Complete =========="
echo "Images: demo-order-app:v1, order-exporter:v1"
echo ""
echo "Verify images on master:"
ctr -n k8s.io images ls | grep -E "demo-order-app|order-exporter"
echo ""
echo "Verify images on node1:"
sshpass -p "${NODE1_PASS}" ssh ${NODE1_USER}@${NODE1_IP} "ctr -n k8s.io images ls | grep -E 'demo-order-app|order-exporter'"
代码解释: 这个脚本负责在本地构建 Docker 镜像,并将其分发到 Kubernetes 集群的所有节点。在没有私有镜像仓库(如 Harbor)的开发环境中,这是一种常见的做法。
set -e:确保脚本在任何命令失败时立即退出。sshpass检查:检查并安装sshpass工具,它允许通过非交互方式使用scp和ssh。docker build:使用app/和exporter/目录下的 Dockerfile 分别构建两个镜像。docker save:将构建好的镜像打包成.tar文件以便传输。scp:将.tar文件复制到集群的 Node 节点上。ctr images import:在 Master 和 Node 节点上,使用 containerd 的客户端工具ctr将.tar文件导入到容器运行时的本地镜像存储中。这样 Kubernetes 调度 Pod 时就能在本地找到所需镜像,无需从远程仓库拉取。
6. Kubernetes 资源清单
这是部署的核心部分,我们通过一系列 YAML 文件来定义所有需要的 Kubernetes 资源。文件按编号顺序部署,确保依赖关系正确。
k8s/00-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo-app
labels:
name: demo-app
# 这个标签很重要,让 Prometheus Operator 能发现此命名空间的 ServiceMonitor
monitoring: "true"
代码解释: 创建一个名为 demo-app 的独立命名空间,用于存放所有的应用和监控相关资源,实现资源隔离。labels.monitoring: "true" 标签是一个良好的实践,在某些 Prometheus Operator 配置中,可能只监控带有特定标签的命名空间,添加这个标签可以确保我们的 ServiceMonitor 不会被忽略。
k8s/01-demo-app.yaml
代码解释: 这个文件定义了订单应用的 Deployment 和 Service。
- Deployment 部分:定义了运行
demo-order-app:v1镜像的 Pod。replicas: 2表示运行两个副本实现高可用。imagePullPolicy: IfNotPresent告诉 Kubernetes 如果本地已存在该镜像就不从远程仓库拉取,与build.sh的分发策略相匹配。livenessProbe和readinessProbe通过访问/healthz端点确保 Pod 的健康状态。resources字段设置了 CPU 和内存的请求和限制,防止单个 Pod 耗尽节点资源。 - Service 部分:创建一个
ClusterIP类型的服务,为后端的 Pod 提供稳定的内部访问入口。Exporter 将通过demo-order-app.demo-app.svc.cluster.local这个 DNS 名称来访问它。
k8s/02-exporter.yaml
代码解释: 这个文件定义了 Exporter 的 Deployment 和 Service。
- Deployment 部分:运行
order-exporter:v1镜像。关键配置是env.TARGET_URL环境变量,它告诉 Exporter 应该去哪里抓取订单应用的数据。这里使用了 Kubernetes 内部服务的 DNS 名称,格式为<service-name>.<namespace>.svc.cluster.local。 - Service 部分:创建了一个暴露 2112 端口的服务。标签非常重要:
app.kubernetes.io/name: order-exporter和app.kubernetes.io/component: exporter这两个标签将被下一步的ServiceMonitor用来发现这个服务作为抓取目标。
k8s/03-servicemonitor.yaml
代码解释: ServiceMonitor 是 Prometheus Operator 提供的自定义资源(CRD),它以声明式的方式定义了 Prometheus 应该如何监控一组服务。
metadata.namespace: monitoring:按惯例,ServiceMonitor 通常和 Prometheus 本身放在同一个命名空间下。spec.namespaceSelector:指定在哪个命名空间里寻找目标 Service,这里设置为demo-app。spec.selector:核心部分,定义标签选择器来匹配目标 Service。matchLabels必须与02-exporter.yaml中 Service 的标签完全一致。spec.endpoints:定义如何从被选中的 Service 上抓取指标。port: metrics指定抓取 Service 的 metrics 端口(南2112);interval: 15s定义抓取间隔为 15 秒;path: /metrics指定指标的 URL 路径。relabelings:将 Kubernetes 元数据(命名空间、服务名、Pod 名)添加为指标的标签,便于在 Prometheus 中进行查询和过滤。
一旦这个 ServiceMonitor 被创建,Prometheus Operator 就会发现它,并自动生成相应的抓取配置,命令 Prometheus 开始从 order-exporter 服务上拉取指标。
k8s/04-prometheus-rules.yaml
代码解释: PrometheusRule 是另一个 CRD,用于以 Kubernetes 原生的方式定义告警规则。
metadata.labels.release: prometheus:这个标签至关重要,根据之前的检查,Prometheus 只会加载带有这个标签的规则文件。spec.groups:将相关规则组织在一起。本示例定义了四组规则:应用可用性、业务指标、收入和 Exporter 性能。- 每条规则的关键字段:
alert:告警名称。expr:触发告警的 PromQL 表达式。例如order_app_up == 0表示当应用状态为 0 时触发。for:持续时间要求。例如for: 1m表示表达式必须持续为 true 达 1 分钟,告警才会从 Pending 变为 Firing。这可以有效防止网络抖动等瞬时问题引发的误报。labels:为触发的告警附加额外标签,最常用的是severity(严重等级),这对后续在 Alertmanager 中进行路由至关重要。annotations:提供更详细、更人性化的信息,如summary和description。可以使用 Go 模板语法(例如{{ $value | humanizePercentage }})来引用告警表达式的当前值。
k8s/05-alertmanager-config.yaml
代码解释: 这是 Alertmanager 的核心配置文件,定义了告警的路由和接收器。
- Secret 方式:通过 Kubernetes Secret 来存储 Alertmanager 配置。Secret 的名称必须与 Alertmanager 实例的名称匹配(格式为
alertmanager-<alertmanager-name>)。 route:定义告警路由树。group_by指定分组依据,相同分组的告警会被合并发送。group_wait是收到第一个告警后等待多久再发送(用于等待同组的其他告警)。repeat_interval是重复发送的间隔。continue: true:关键配置。默认情况下,Alertmanager 匹配到第一个子路由后就停止。添加continue: true后,告警会继续匹配后续路由,实现一个告警发送到多个接收器。receivers:定义告警的接收方式。每个 receiver 可以配置webhook_configs、email_configs等多种通知方式。send_resolved: true表示告警恢复时也发送通知。inhibit_rules:告警抑制规则。当同一个alertname和app同时存在 critical 和 warning 告警时,warning 告警会被抑制,避免重复通知。
重要说明:kube-prometheus-stack 可能使用
AlertmanagerConfigCRD。如果上面的 Secret 方式不生效,使用下面的 CRD 方式:
代码解释: 这是使用 AlertmanagerConfig CRD 的替代方式。与 Secret 方式不同,它使用 Kubernetes 原生的资源对象来定义 Alertmanager 配置,更符合 GitOps 的实践。字段名称采用驼峰命名(如 groupBy、groupWait、webhookConfigs),与 Secret 中的下划线命名略有不同。如果 Secret 方式不生效,可以尝试这种 CRD 方式。
k8s/06-webhook-receiver.yaml
代码解释: 这个文件创建了一个简单的 Python 应用,用于接收并打印 Alertmanager 发送过来的告警通知,方便调试和验证。
- ConfigMap:将 Python 脚本的内容存储在 ConfigMap 中,这样可以在不重新构建镜像的情况下修改脚本内容。
receiver.py是一个简单的 HTTP 服务器,它监听 9095 端口,处理 GET 请求(健康检查和查看告警历史)和 POST 请求(接收 Alertmanager 发送的告警)。收到告警后,它会解析 JSON 数据,提取告警名称、严重等级、摘要等信息,并以格式化的方式打印到日志中。 - Deployment:使用通用的
python:3.11-alpine镜像,通过volumes和volumeMounts将 ConfigMap 挂载到容器的/scripts目录下,然后执行receiver.py脚本。 - Service:创建
ClusterIP服务,使 Alertmanager 可以通过alert-webhook-receiver.demo-app.svc.cluster.local:9095访问到它。
7. Grafana Dashboard JSON
grafana/dashboard.json 文件定义了一个用于展示自定义指标的 Grafana 可视化仪表盘。它以声明式的方式定义了仪表盘的布局、变量以及每个面板的配置,包括概览指标卡、趋势图、产品分析和 Exporter 性能监控等多个区域。可以通过 Grafana 的导入功能直接使用。
grafana/dashboard.json
代码解释: 这是一个标准的 Grafana Dashboard JSON 模型。panels 数组包含了仪表盘上的所有图表,每个面板通过 type 字段指定类型(如 stat 指标卡、timeseries 时间序列图、piechart 饼图、bargauge 条形图、gauge 仪表盘等),通过 targets 字段定义 PromQL 查询表达式。例如 rate(order_app_orders_success_total[5m]) * 60 计算了过去 5 分钟内每分钟成功订单的平均速率。gridPos 字段控制每个面板在仪表盘上的位置和大小,thresholds 定义了颜色阈值(如失败率超过 8% 变黄、超过 15% 变红)。这个 JSON 文件可以通过 Grafana 的 Import 功能直接导入使用。
8. 一键部署脚本
deploy.sh 脚本将上述所有 Kubernetes 资源按顺序部署到集群中,并提供验证步骤。在执行部署之前,需要先确认一些基本信息。
#注意查看svc nodeport的地址
kubectl get svc -n monitoring
#注意查看yaml文件的编码是否为utf-8
file -i filename
代码解释: 部署前的准备工作。第一条命令查看 monitoring 命名空间下所有 Service 的 NodePort 端口,确认 Prometheus、Grafana、Alertmanager 的访问地址。第二条命令检查 YAML 文件的编码是否为 UTF-8,避免因编码问题导致中文字符乱码。
deploy.sh
#!/bin/bash
set -e
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# ========== 检查 sshpass ==========
if ! command -v sshpass &> /dev/null; then
echo ""
echo "sshpass not found, installing..."
sudo apt-get update
sudo apt-get install -y sshpass
fi
echo "============================================"
echo " Order App Custom Monitoring - Deploy"
echo "============================================"
# Color definitions
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
print_step() {
echo -e "\n${GREEN}[STEP]${NC} $1"
}
print_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# ========== Pre-check ==========
print_step "1. Pre-flight checks"
echo "Checking kubectl connection..."
kubectl cluster-info || { print_error "Cannot connect to cluster"; exit 1; }
echo "Checking Prometheus Operator..."
kubectl get crd servicemonitors.monitoring.coreos.com > /dev/null 2>&1 || {
print_error "ServiceMonitor CRD not found, please install kube-prometheus-stack first"
exit 1
}
echo "Checking kube-prometheus-stack..."
kubectl get pods -n monitoring -l app.kubernetes.io/name=prometheus 2>/dev/null || {
print_warn "Prometheus pods not found in monitoring namespace"
}
# ========== Build images ==========
print_step "2. Building Docker images"
echo "Preparing go.mod..."
cd app
[ ! -f go.sum ] && go mod tidy
cd ..
cd exporter
[ ! -f go.sum ] && go mod tidy
cd ..
echo "Building demo-order-app..."
docker build -t demo-order-app:v1 ./app/
echo "Building order-exporter..."
docker build -t order-exporter:v1 ./exporter/
# ========== Distribute images ==========
print_step "3. Distributing images to all nodes"
RUNTIME="containerd"
echo "Container runtime: ${RUNTIME}"
docker save demo-order-app:v1 -o /tmp/demo-order-app.tar
docker save order-exporter:v1 -o /tmp/order-exporter.tar
# Node list
NODES=("192.168.201.135")
NODE1_PASS="root"
NODE1_USER="root"
for NODE in "${NODES[@]}"; do
echo "Transferring images to node $NODE..."
sshpass -p "${NODE1_PASS}" scp /tmp/demo-order-app.tar ${NODE1_USER}@${NODE}:/tmp/ || print_warn "SCP to ${NODE} failed"
sshpass -p "${NODE1_PASS}" scp /tmp/order-exporter.tar ${NODE1_USER}@${NODE}:/tmp/ || print_warn "SCP to ${NODE} failed"
echo "Importing images on $NODE..."
sshpass -p "${NODE1_PASS}" ssh ${NODE1_USER}@${NODE} "ctr -n k8s.io images import /tmp/demo-order-app.tar" || true
sshpass -p "${NODE1_PASS}" ssh ${NODE1_USER}@${NODE} "ctr -n k8s.io images import /tmp/order-exporter.tar" || true
done
# Import on master
echo "Importing images on master node..."
ctr -n k8s.io images import /tmp/demo-order-app.tar || true
ctr -n k8s.io images import /tmp/order-exporter.tar || true
# ========== Deploy K8s resources ==========
print_step "4. Deploying Kubernetes resources"
echo "Creating namespace..."
kubectl apply -f k8s/00-namespace.yaml
echo "Deploying demo application..."
kubectl apply -f k8s/01-demo-app.yaml
echo "Deploying exporter..."
kubectl apply -f k8s/02-exporter.yaml
echo "Deploying webhook receiver..."
kubectl apply -f k8s/06-webhook-receiver.yaml
echo "Waiting for pods to be ready (max 2 minutes)..."
kubectl wait --for=condition=ready pod -l app=demo-order-app -n demo-app --timeout=120s || print_warn "App pods not ready yet"
kubectl wait --for=condition=ready pod -l app=order-exporter -n demo-app --timeout=120s || print_warn "Exporter pods not ready yet"
kubectl wait --for=condition=ready pod -l app=alert-webhook-receiver -n demo-app --timeout=120s || print_warn "Webhook receiver not ready yet"
echo ""
echo "Deploying ServiceMonitor..."
kubectl apply -f k8s/03-servicemonitor.yaml
echo "Deploying PrometheusRule..."
kubectl apply -f k8s/04-prometheus-rules.yaml
echo "Configuring AlertManager..."
kubectl apply -f k8s/05-alertmanager-config.yaml
echo "Restarting AlertManager to apply config..."
kubectl delete pod -n monitoring alertmanager-prometheus-kube-prometheus-alertmanager-0 2>/dev/null || true
# ========== Verification ==========
print_step "5. Verifying deployment"
echo ""
echo "========== Pods in demo-app namespace =========="
kubectl get pods -n demo-app -o wide
echo ""
echo "========== Services in demo-app namespace =========="
kubectl get svc -n demo-app
echo ""
echo "========== ServiceMonitor =========="
kubectl get servicemonitor -n monitoring | grep order || echo "order-exporter ServiceMonitor not found"
echo ""
echo "========== PrometheusRule =========="
kubectl get prometheusrule -n monitoring | grep order || echo "order-app-alerts not found"
echo ""
echo "========== Verifying exporter metrics =========="
sleep 5
EXPORTER_POD=$(kubectl get pods -n demo-app -l app=order-exporter -o jsonpath='{.items[0].metadata.name}' 2>/dev/null)
if [ -n "$EXPORTER_POD" ]; then
echo "Getting metrics sample from exporter pod..."
kubectl exec -n demo-app $EXPORTER_POD -- wget -qO- http://localhost:2112/metrics 2>/dev/null | grep "order_app_" | head -15 || {
print_warn "Cannot get metrics yet, exporter may still be starting"
}
fi
# ========== Access information ==========
print_step "6. Access information"
echo ""
echo "============================================"
echo " Deployment Complete!"
echo "============================================"
echo ""
echo "Prometheus (NodePort exposed):"
echo " http://192.168.201.134:31442"
echo ""
echo " Verify targets: http://192.168.201.134:31442/targets"
echo " Search for 'order-exporter' - should see 1 UP target"
echo ""
echo "Grafana (NodePort exposed):"
echo " http://192.168.201.134:32212"
echo " Username: admin"
GRAFANA_POD=$(kubectl get pod -n monitoring -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].metadata.name}')
echo "Resetting Grafana password..."
kubectl exec -n monitoring $GRAFANA_POD -c grafana -- grafana-cli admin reset-admin-password admin
GRAFANA_PASSWORD=$(kubectl get secret -n monitoring prometheus-grafana -o jsonpath='{.data.admin-password}' 2>/dev/null | base64 -d)
echo " Password: ${GRAFANA_PASSWORD}"
echo ""
echo "AlertManager (NodePort exposed):"
echo " http://192.168.201.134:30513"
echo ""
echo "Demo App API:"
echo " Port-forward command:"
echo " kubectl port-forward svc/demo-order-app 8080:8080 -n demo-app --address=0.0.0.0 &"
echo " Access: http://192.168.201.134:8080/api/stats"
echo ""
echo "Exporter Metrics:"
echo " Port-forward command:"
echo " kubectl port-forward svc/order-exporter 2112:2112 -n demo-app --address=0.0.0.0 &"
echo " Access: http://192.168.201.134:2112/metrics"
echo ""
echo "View alert logs:"
echo " kubectl logs -f -n demo-app -l app=alert-webhook-receiver"
echo ""
echo "============================================"
echo " Next Steps:"
echo "============================================"
echo "1. Verify targets in Prometheus:"
echo " http://192.168.201.134:31442/targets"
echo ""
echo "2. Import Dashboard in Grafana:"
echo " - Visit http://192.168.201.134:32212"
echo " - Left menu -> Dashboards -> Import"
echo " - Upload grafana/dashboard.json"
echo ""
echo "3. Verify alert rules:"
echo " http://192.168.201.134:31442/alerts"
echo ""
echo "4. Test alert triggering:"
echo " kubectl scale deployment demo-order-app -n demo-app --replicas=0"
echo " Wait 1-2 minutes and check alerts"
echo ""
echo "============================================"
代码解释: deploy.sh 是一个全自动化的部署脚本,它将整个部署过程分为 6 个步骤:
- Pre-flight checks:检查 kubectl 是否能连接到集群,以及 Prometheus Operator 的 CRD(如
ServiceMonitor)是否已安装。 - Building Docker images:编译 Go 应用并构建 Docker 镜像。
- Distributing images:将镜像分发到集群的所有节点,通过
docker save+scp+ctr images import的方式。 - Deploying K8s resources:按顺序应用所有 YAML 文件。注意部署顺序很重要:先创建命名空间和应用,等待 Pod 就绪后再创建 ServiceMonitor 和 PrometheusRule。
kubectl wait命令确保 Pod 已经 Ready 后才继续。 - Verifying deployment:检查所有资源的状态,并从 Exporter Pod 中获取样本指标确认数据采集正常。
- Access information:打印所有服务的访问地址和后续操作指南。
9. 执行部署和验证
本节将按顺序执行部署并逐步验证每个组件是否正常工作。
1. 执行构建和部署
首先确保环境中已安装 Go 语言环境,并配置国内代理以加速依赖下载。
# 更新包列表
sudo apt update
# 安装 Go
sudo apt install -y golang-go
# 验证
go version
# 设置 GOPATH(可选)
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
# 设置 Go 代理为阿里云或七牛云
export GOPROXY=https://goproxy.cn,direct
# 或者
export GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
# 永久设置
cat >> ~/.bashrc <<'EOF'
export GOPROXY=https://goproxy.cn,direct
EOF
source ~/.bashrc
# 验证
go env | grep GOPROXY
代码解释: 安装 Go 语言并配置 GOPROXY 为国内镜像源(七牛云或阿里云),避免因网络问题导致 go mod download 失败。将配置写入 ~/.bashrc 确保永久生效。
然后执行构建和部署脚本:
# 在 k8s-master 上执行
cd custom-monitoring
# 赋予执行权限
chmod +x build.sh deploy.sh
# 执行部署
./build.sh
./deploy.sh
代码解释: 赋予脚本执行权限后,先运行 build.sh 构建镜像并分发到各节点,再运行 deploy.sh 将所有资源部署到集群中。

2. 验证 ServiceMonitor 被发现
部署完成后,首先确认 Prometheus 是否已经发现了我们的 Exporter 作为抓取目标。
# 浏览器访问
http://192.168.201.134:31442/targets
# 或者命令行实现
# 检查 Prometheus 的 serviceMonitorSelector 匹配
kubectl get prometheus -n monitoring -o yaml | grep -A 10 serviceMonitorSelector
# 如果 serviceMonitorSelector 为空 ({}),则匹配所有namespaces中的所有 ServiceMonitor,而不进行标签过滤
# 如果有 matchLabels,确保 ServiceMonitor 带有对应标签
# 查看 ServiceMonitor
kubectl get servicemonitor -n monitoring
kubectl describe servicemonitor order-exporter -n monitoring
代码解释: 通过访问 Prometheus 的 Targets 页面或命令行来确认 order-exporter 是否被发现。如果在 Targets 页面看到 serviceMonitor/monitoring/order-exporter 且状态为 UP,则说明数据采集链路已打通。

重要:如果 Prometheus 没有发现目标,检查以下几点:
# 1. 检查 Prometheus 的配置
kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.serviceMonitorNamespaceSelector}' && echo
kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.serviceMonitorSelector}' && echo
#{}
#{}
# 2. 如果 serviceMonitorNamespaceSelector 不为空,可能需要
# 在 demo-app 命名空间添加对应标签,或将 ServiceMonitor 放在 monitoring 命名空间
# 3. 查看 Prometheus Operator 日志
kubectl logs -n monitoring -l app.kubernetes.io/name=prometheus-operator --tail=50
# 4. 如果需要修改 Prometheus 配置使其监控所有命名空间
# 编辑 kube-prometheus-stack 的 helm values:
# prometheus:
# prometheusSpec:
# serviceMonitorSelectorNilUsesHelmValues: false
# serviceMonitorNamespaceSelector: {}
# serviceMonitorSelector: {}
# ruleSelectorNilUsesHelmValues: false
# ruleNamespaceSelector: {}
# ruleSelector: {}
# 快速修改方式(如果 helm values 不方便改):
kubectl edit prometheus -n monitoring
# 在 spec 下设置:
# serviceMonitorNamespaceSelector: {}
# serviceMonitorSelector: {}
# ruleNamespaceSelector: {}
# ruleSelector: {}
代码解释: 如果 Prometheus 没有发现目标,以上命令可以帮助定位问题。核心检查点是 serviceMonitorSelector 和 serviceMonitorNamespaceSelector。如果它们为空 {},则表示不做任何过滤,会发现所有 ServiceMonitor;如果有特定的 matchLabels,则需要确保 ServiceMonitor 带有对应的标签。如果使用 Helm 安装的 kube-prometheus-stack,可以通过修改 Helm values 或直接 kubectl edit 来调整这些选择器。
3. 验证指标
确认 Exporter 能够正常产生指标数据。
# 端口转发 Exporter
kubectl port-forward svc/order-exporter 2112:2112 -n demo-app --address=0.0.0.0 &
# 查看指标
curl -s http://192.168.201.134:2112/metrics | grep order_app_
# 预期输出类似:
# order_app_orders_total 15
# order_app_orders_success_total 12
# order_app_orders_failed_total 2
# order_app_orders_pending_total 1
# order_app_revenue_total_dollars 15234.56
# order_app_order_fail_rate 0.133
# order_app_orders_by_product_total{product="laptop"} 3
# order_app_orders_by_product_total{product="phone"} 5
# order_app_up 1
# order_app_exporter_scrape_success 1
# order_app_exporter_scrape_duration_seconds 0.023
代码解释: 通过 kubectl port-forward 将 Exporter 的 2112 端口映射到本地,然后用 curl 访问 /metrics 端点。如果能看到 order_app_ 前缀的指标且数值合理(如 order_app_up 1、order_app_orders_total 有值),则说明 Exporter 工作正常。


4. 在 Prometheus 中验证
确认 Prometheus 已经成功采集到指标数据,并且告警规则已加载。
# 端口转发 Prometheus
#kubectl port-forward svc/kube-prometheus-stack-prometheus 9090:9090 -n monitoring --address=0.0.0.0 &
root@k8s-master:~/custom-monitoring# kubectl get svc -n monitoring
#prometheus-kube-prometheus-prometheus NodePort 10.109.142.32 <none> 9090:31442/TCP,8080:30576/TCP 4d5h
浏览器打开 http://192.168.201.134:31442 :
- Status → Targets: 查看是否有
serviceMonitor/monitoring/order-exporter目标,状态应为UP - Graph: 输入
order_app_orders_total验证有数据 - Alerts: 查看告警规则是否加载
代码解释: 通过 Prometheus Web UI 进行三个关键验证:在 Targets 页面确认 Exporter 状态为 UP;在 Graph 页面查询指标确认有数据;在 Alerts 页面确认告警规则已成功加载。



5. 导入 Grafana Dashboard
将之前准备的 Dashboard JSON 导入到 Grafana 中,实现指标的可视化展示。
kubectl get svc -n monitoring
#prometheus-grafana NodePort 10.109.57.237 <none> 80:32212/TCP
# 获取 Grafana 密码
kubectl get secret -n monitoring prometheus-grafana -o jsonpath='{.data.admin-password}' | base64 -d && echo
#admin
代码解释: 第一条命令查看 Grafana 的 NodePort 端口,第二条命令从 Kubernetes Secret 中获取 Grafana 的管理员密码(存储时经过 base64 编码,需要解码)。
浏览器打开 http://192.168.201.134:32212:
- 登录 (admin / 获取的密码)
- 左侧菜单 → Dashboards → Import
- 粘贴前文提到的json文件




6. 验证告警
确认告警规则已加载,以及 Alertmanager 和 Webhook Receiver 已就绪。
# 查看 PrometheusRule
kubectl get prometheusrule -n monitoring
kubectl describe prometheusrule order-app-alerts -n monitoring
# 查看 AlertManager
#kubectl port-forward svc/alertmanager-operated 9093:9093 -n monitoring --address=0.0.0.0 &
# 浏览器访问 http://192.168.201.134:9093
kubectl get svc -n monitoring | grep alertmanager
# 浏览器访问 http://192.168.201.134:32212
# 查看 Webhook 接收器日志
kubectl logs -f -n demo-app -l app=alert-webhook-receiver
代码解释: 依次检查:告警规则是否已被 Prometheus 加载;Alertmanager 是否可访问;Webhook Receiver 的日志是否有告警 POST 请求。如果只看到 GET /healthz 200 而没有 POST 请求,说明告警还未触发或 Alertmanager 路由配置有问题。
[2026-03-03 06:29:57] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:01] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:06] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:07] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:11] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:16] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:17] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:21] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:26] "GET /healthz HTTP/1.1" 200 -
[2026-03-03 06:30:27] "GET /healthz HTTP/1.1" 200 -


7. 模拟告警触发
通过人为制造故障来验证整个告警链路是否畅通。
# 方法1: 缩放应用到0副本(触发 OrderAppDown)
# 1. 先确认应用正常运行
kubectl scale deployment demo-order-app -n demo-app --replicas=2
sleep 30
# 2. 缩容触发告警
echo "=== 缩容应用 ==="
kubectl scale deployment demo-order-app -n demo-app --replicas=0
# 3. 等待 3 分钟(充足的时间让告警从 pending → firing → 发送)
echo "=== 等待 3 分钟... ==="
sleep 180
# 4. 查看 webhook 日志(显示全部日志)
echo "=== Webhook Receiver 完整日志 ==="
kubectl logs -n demo-app -l app=alert-webhook-receiver --tail=100
# 5. 确认 Alertmanager 中告警状态
echo ""
echo "=== Alertmanager 告警 ==="
curl -s http://192.168.201.134:30513/api/v2/alerts | python3 -c "
import json, sys
data = json.load(sys.stdin )
for a in data:
name = a['labels'].get('alertname','')
recv = [r['name'] for r in a.get('receivers',[])]
print(f'{name} -> receivers: {recv}')
" 2>/dev/null
# 6. 恢复
kubectl scale deployment demo-order-app -n demo-app --replicas=2
# 方法2: 删除应用Service(触发 Exporter 抓取失败)
#kubectl delete svc demo-order-app -n demo-app
# 等待后恢复
#kubectl apply -f k8s/01-demo-app.yaml
代码解释: 将应用副本数缩容到 0 后,Exporter 无法连接到应用,会上报 order_app_up=0。等待 1 分钟(for: 1m)后,OrderAppDown 告警从 Pending 变为 Firing,再经过 Alertmanager 的 group_wait 后被发送到 Webhook Receiver 和邮箱。共需等待约 2-3 分钟。测试完成后恢复副本数为 2。


8. QQ邮箱接受告警
在原有 Webhook 通知的基础上,新增 QQ 邮箱通知功能,使告警能够同时发送到邮箱。
QQ 邮箱中开启 SMTP 服务并获取授权码。
获取授权码步骤:
- 登录 QQ 邮箱网页版:https://mail.qq.com
- 点击顶部 设置 → 账户
- 找到 POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
- 开启 IMAP/SMTP服务
- 按照提示用手机发送短信验证 ,完成后会生成一个 16位授权码
修改05-alertmanager-config.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: alertmanager-prometheus-kube-prometheus-alertmanager
namespace: monitoring
type: Opaque
stringData:
alertmanager.yaml: |
global:
resolve_timeout: 5m
# QQ 邮箱 SMTP 配置
smtp_smarthost: 'smtp.qq.com:587'
smtp_from: 'xxxx@qq.com'
smtp_auth_username: 'xxxxx@qq.com'
smtp_auth_password: 'xxxxxxxxxx'
smtp_require_tls: true
smtp_tls_config:
insecure_skip_verify: true
# 邮件模板(可选,美化邮件内容)
templates:
- '/etc/alertmanager/config/*.tmpl'
route:
receiver: 'default-email'
group_by: ['alertname', 'severity', 'app']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
# order-app 相关告警 → 邮件 + webhook
- receiver: 'order-app-email'
matchers:
- app="order-app"
continue: true
# critical 告警 → 邮件 + webhook
- receiver: 'critical-email'
matchers:
- severity="critical"
group_wait: 10s
repeat_interval: 1h
continue: true
# warning 告警 → webhook
- receiver: 'warning-webhook'
matchers:
- severity="warning"
group_wait: 30s
repeat_interval: 4h
continue: true
receivers:
# 默认接收器:邮件 + webhook
- name: 'default-email'
email_configs:
- to: 'xxx@qq.com'
send_resolved: true
headers:
subject: '[Prometheus] {{ .Status | toUpper }} - {{ .CommonLabels.alertname }}'
webhook_configs:
- url: 'http://alert-webhook-receiver.demo-app.svc.cluster.local:9095/webhook'
send_resolved: true
# order-app 专用接收器:邮件 + webhook
- name: 'order-app-email'
email_configs:
- to: 'xxxx@qq.com'
send_resolved: true
headers:
subject: '[订单系统告警] {{ .Status | toUpper }} - {{ .CommonLabels.alertname }}'
webhook_configs:
- url: 'http://alert-webhook-receiver.demo-app.svc.cluster.local:9095/webhook/order-app'
send_resolved: true
# critical 接收器:邮件 + webhook
- name: 'critical-email'
email_configs:
- to: 'xxx@qq.com'
send_resolved: true
headers:
subject: '[严重告警] {{ .Status | toUpper }} - {{ .CommonLabels.alertname }}'
webhook_configs:
- url: 'http://alert-webhook-receiver.demo-app.svc.cluster.local:9095/webhook/critical'
send_resolved: true
# warning 接收器:仅 webhook(避免邮件过多)
- name: 'warning-webhook'
webhook_configs:
- url: 'http://alert-webhook-receiver.demo-app.svc.cluster.local:9095/webhook/warning'
send_resolved: true
inhibit_rules:
- source_matchers:
- severity="critical"
target_matchers:
- severity="warning"
equal: ['alertname', 'app']
代码解释: 这是最终的完整配置,在原有 Webhook 通知的基础上新增了 QQ 邮箱通知功能。
global部分:配置了 QQ 邮箱的 SMTP 服务器信息。smtp_smarthost指定 SMTP 服务器地址和端口(587 是 STARTTLS 端口);smtp_auth_password填写的是 QQ 邮箱的授权码(不是登录密码);smtp_tls_config.insecure_skip_verify: true跳过 TLS 证书验证,解决容器环境中缺少根证书的问题。- 接收器设计:
default-email、order-app-email、critical-email同时配置了email_configs和webhook_configs,实现邮件和 Webhook 双通道通知。warning-webhook只配置了 Webhook,避免 warning 级别告警产生过多邮件。 - 邮件标题自定义:通过
headers.subject自定义邮件标题,使用 Go 模板语法插入告警状态和名称,便于在邮箱中快速识别告警类型。
应用配置并重启 Alertmanager:
kubectl apply -f k8s/05-alertmanager-config.yaml
#重启 Alertmanager Pod 以加载新配置:
kubectl delete pod -n monitoring -l app.kubernetes.io/name=alertmanager
代码解释: kubectl apply 更新 Secret 内容,kubectl delete pod 强制重启 Alertmanager Pod 以加载新配置。Alertmanager 不会自动热加载 Secret 的变更,必须重启。
验证配置已加载
# 等待 Alertmanager 重启完成
sleep 30
# 确认 Pod 正常运行
kubectl get pods -n monitoring -l app.kubernetes.io/name=alertmanager
# 确认配置中包含 smtp 和 email 配置
curl -s http://192.168.201.134:30513/api/v2/status | python3 -c "
import json, sys
data = json.load(sys.stdin )
config = data.get('config', {}).get('original', '')
for line in config.split('\n'):
if 'smtp' in line.lower() or 'email' in line.lower() or 'qq.com' in line.lower():
print(line)
"
# 检查 Alertmanager 日志是否有报错
kubectl logs -n monitoring -l app.kubernetes.io/name=alertmanager --tail=20
代码解释: 通过 Alertmanager 的 API 查询当前加载的配置,确认 SMTP 和邮箱相关配置已生效。同时检查 Alertmanager 日志是否有报错,如 TLS 证书验证失败或 SMTP 认证失败等。
测试邮件告警
# 缩容应用触发告警
kubectl scale deployment demo-order-app -n demo-app --replicas=0
# 等待 2 分钟
echo "等待 2 分钟..."
sleep 120
# 查看 webhook 日志确认告警已发送
kubectl logs -n demo-app -l app=alert-webhook-receiver --tail=30
# 同时检查您的 QQ 邮箱收件箱(包括垃圾邮件箱)
# 恢复应用
kubectl scale deployment demo-order-app -n demo-app --replicas=2
代码解释: 通过缩容应用触发告警,等待 2 分钟后检查 Webhook 日志确认告警已发送,同时检查 QQ 邮箱收件箱(包括垃圾邮件箱)是否收到告警邮件。测试完成后恢复应用副本数。



本配置在原有 Webhook 告警的基础上,新增了 QQ 邮箱 通知功能。告警触发时,您的邮箱 将收到告警邮件。
10. 清理
当不再需要这个监控示例时,可以使用以下脚本清理所有资源。
#!/bin/bash
# cleanup.sh
echo "清理自定义监控资源..."
kubectl delete -f k8s/03-servicemonitor.yaml --ignore-not-found
kubectl delete -f k8s/04-prometheus-rules.yaml --ignore-not-found
kubectl delete -f k8s/05-alertmanager-config.yaml --ignore-not-found
kubectl delete -f k8s/06-webhook-receiver.yaml --ignore-not-found
kubectl delete -f k8s/02-exporter.yaml --ignore-not-found
kubectl delete -f k8s/01-demo-app.yaml --ignore-not-found
kubectl delete namespace demo-app --ignore-not-found
echo "清理完成"
代码解释: 清理脚本按照与部署相反的顺序删除资源:先删除监控配置(ServiceMonitor、PrometheusRule、AlertmanagerConfig),再删除应用(Webhook Receiver、Exporter、Demo App),最后删除命名空间。--ignore-not-found 参数确保即使某些资源不存在也不会报错。
关键排错指南
当监控系统出现问题时,可以按照以下流程逐层排查。
问题排查流程:
1. Exporter 无数据?
└─ kubectl logs -n demo-app -l app=order-exporter
└─ kubectl exec -n demo-app <exporter-pod> -- wget -qO- http://demo-order-app:8080/api/stats
2. Prometheus 未发现目标?
└─ kubectl get servicemonitor -n monitoring
└─ 检查 ServiceMonitor labels 是否匹配 Prometheus 的 serviceMonitorSelector
└─ kubectl logs -n monitoring -l app.kubernetes.io/name=prometheus-operator
3. 告警规则未加载?
└─ kubectl get prometheusrule -n monitoring
└─ 检查 PrometheusRule labels 是否匹配 Prometheus 的 ruleSelector
└─ Prometheus UI → Status → Rules
4. AlertManager 未收到告警?
└─ Prometheus UI → Alerts 查看告警状态
└─ kubectl logs -n monitoring -l app.kubernetes.io/name=alertmanager
5. Webhook 未收到通知?
└─ kubectl logs -n demo-app -l app=alert-webhook-receiver
└─ 检查 AlertManager Config 中的 URL 是否正确
代码解释: 这个排查流程按照数据流的方向逐层检查:从 Exporter 数据采集 → Prometheus 目标发现 → 告警规则加载 → Alertmanager 接收告警 → Webhook/邮件接收通知。每一层都提供了具体的检查命令,可以快速定位问题所在的环节。最常见的问题包括:ServiceMonitor 标签不匹配、PrometheusRule 缺少 release: prometheus 标签、Alertmanager 路由缺少 continue: true 以及 Webhook URL 配置错误。
这个完整示例涵盖了:
- Go 应用:模拟订单系统,自动生成测试数据
- Go Exporter:实现
prometheus.Collector接口,从应用拉取指标 - ServiceMonitor:Prometheus Operator 自动发现
- PrometheusRule:多级别告警规则(critical/warning)
- AlertManager:路由分组 + Webhook 通知
- Grafana Dashboard:概览/趋势/产品分析/Exporter 性能多维度面板
参考
https://zhuanlan.zhihu.com/p/714084626
Mini MAX
Manus 1.6 MAX

3533

被折叠的 条评论
为什么被折叠?



