prometheus安装部署

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. 名词解释

为了更好地理解本部署指南,以下是文档中涉及到的关键概念和术语的详细解释:

术语英文全称/类型解释
PrometheusTime-series Database & Monitoring System一个开源的监控系统,以拉取(pull)模式从配置的目标(targets)收集指标,并将其存储在时间序列数据库中。它支持强大的查询语言 PromQL,并能触发告警。
GrafanaData Visualization Platform一个开源的数据可视化和分析平台,常与 Prometheus 配合使用,通过创建交互式仪表盘来展示和分析 Prometheus 收集到的指标数据。
AlertmanagerAlerting SystemPrometheus 的配套告警管理系统。它接收来自 Prometheus 的告警,进行去重、分组、抑制,并路由到各种通知接收器(如邮件、Webhook、Slack 等)。
PromQLPrometheus Query LanguagePrometheus 提供的功能强大的查询语言,用于实时选择和聚合时间序列数据。
ExporterMetric Exporter一个中间件,用于从第三方系统(如数据库、消息队列、操作系统等)收集指标,并将其转换为 Prometheus 可识别的格式暴露出来,供 Prometheus 拉取。
ServiceMonitorKubernetes Custom Resource Definition (CRD)Prometheus Operator 引入的自定义资源,用于声明式地定义 Prometheus 应该如何发现和监控 Kubernetes Service。Prometheus Operator 会根据 ServiceMonitor 自动生成 Prometheus 的抓取配置。
PrometheusRuleKubernetes Custom Resource Definition (CRD)Prometheus Operator 引入的自定义资源,用于在 Kubernetes 中定义 Prometheus 的告警规则和记录规则。
Prometheus OperatorKubernetes Operator一个 Kubernetes Operator,它简化了在 Kubernetes 上部署和管理 Prometheus、Alertmanager 和相关组件的复杂性。它通过 CRD(如 ServiceMonitor、PrometheusRule)来管理 Prometheus 资源。
kube-prometheus-stackHelm Chart一个 Helm Chart,包含了在 Kubernetes 上部署完整 Prometheus 监控栈所需的所有组件,包括 Prometheus Operator、Prometheus、Alertmanager、Grafana、Node Exporter、Kube-state-metrics 等。
NodePortKubernetes Service TypeKubernetes Service 的一种类型,通过在每个节点上打开一个静态端口,将服务暴露到集群外部。外部流量可以通过 <NodeIP>:<NodePort> 访问服务。
ClusterIPKubernetes Service TypeKubernetes Service 的默认类型,为服务提供一个集群内部可访问的虚拟 IP 地址。服务只能在集群内部通过 <ClusterIP>:<Port> 访问。
DeploymentKubernetes Workload API ObjectKubernetes 中用于管理无状态应用的一种控制器。它定义了 Pod 的模板和副本数量,并确保 Pod 按照预期状态运行。
ServiceKubernetes Service API ObjectKubernetes 中用于定义一组 Pod 的逻辑抽象和访问策略。它为 Pod 提供了一个稳定的网络端点。
ConfigMapKubernetes API ObjectKubernetes 中用于存储非敏感配置数据的 API 对象。可以将配置数据以键值对的形式存储,并挂载到 Pod 中作为文件或环境变量使用。
DockerfileDocker Build Instruction File一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。
多阶段构建 (Multi-stage Build)Docker Build TechniqueDockerfile 中的一种优化技术,通过使用多个 FROM 指令,将构建环境和最终运行环境分离,从而减小最终镜像的体积。
HelmKubernetes Package ManagerKubernetes 的包管理工具,用于定义、安装和升级复杂的 Kubernetes 应用程序。通过 Helm Chart 可以方便地部署和管理应用。
KubeletKubernetes Agent运行在每个 Kubernetes 节点上的代理程序,负责管理 Pod 的生命周期,包括创建、启动、停止容器,并向 Master 报告节点和 Pod 的状态。
cAdvisorContainer Advisor一个开源工具,用于收集、处理和导出运行中容器的性能指标(如 CPU、内存、网络、文件系统使用情况)。Prometheus 可以从 cAdvisor 抓取这些指标。
Node ExporterPrometheus 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=falseserviceMonitorSelectorNilUsesHelmValues=false:这是非常关键的两个设置。默认情况下,Prometheus 只会发现由当前 Helm Release 创建的监控目标。将它们设为 false 后,Prometheus 就会发现集群中所有命名空间下、带有匹配标签的 ServiceMonitorPodMonitor,这为我们后续部署自定义监控奠定了基础。

暴露服务,将 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 的一些关键配置,以确保它能发现我们后续创建的 ServiceMonitorPrometheusRule

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 工具,它允许通过非交互方式使用 scpssh
  • 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 的分发策略相匹配。livenessProbereadinessProbe 通过访问 /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-exporterapp.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:核心部分,定义标签选择器来匹配目标 ServicematchLabels 必须与 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:提供更详细、更人性化的信息,如 summarydescription。可以使用 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_configsemail_configs 等多种通知方式。send_resolved: true 表示告警恢复时也发送通知。
  • inhibit_rules:告警抑制规则。当同一个 alertnameapp 同时存在 critical 和 warning 告警时,warning 告警会被抑制,避免重复通知。

重要说明:kube-prometheus-stack 可能使用 AlertmanagerConfig CRD。如果上面的 Secret 方式不生效,使用下面的 CRD 方式:

代码解释: 这是使用 AlertmanagerConfig CRD 的替代方式。与 Secret 方式不同,它使用 Kubernetes 原生的资源对象来定义 Alertmanager 配置,更符合 GitOps 的实践。字段名称采用驼峰命名(如 groupBygroupWaitwebhookConfigs),与 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 镜像,通过 volumesvolumeMounts 将 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 个步骤:

  1. Pre-flight checks:检查 kubectl 是否能连接到集群,以及 Prometheus Operator 的 CRD(如 ServiceMonitor)是否已安装。
  2. Building Docker images:编译 Go 应用并构建 Docker 镜像。
  3. Distributing images:将镜像分发到集群的所有节点,通过 docker save + scp + ctr images import 的方式。
  4. Deploying K8s resources:按顺序应用所有 YAML 文件。注意部署顺序很重要:先创建命名空间和应用,等待 Pod 就绪后再创建 ServiceMonitor 和 PrometheusRule。kubectl wait 命令确保 Pod 已经 Ready 后才继续。
  5. Verifying deployment:检查所有资源的状态,并从 Exporter Pod 中获取样本指标确认数据采集正常。
  6. 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 没有发现目标,以上命令可以帮助定位问题。核心检查点是 serviceMonitorSelectorserviceMonitorNamespaceSelector。如果它们为空 {},则表示不做任何过滤,会发现所有 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 1order_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 :

  1. Status → Targets: 查看是否有 serviceMonitor/monitoring/order-exporter 目标,状态应为 UP
  2. Graph: 输入 order_app_orders_total 验证有数据
  3. 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:

  1. 登录 (admin / 获取的密码)
  2. 左侧菜单 → DashboardsImport
  3. 粘贴前文提到的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 服务并获取授权码。
获取授权码步骤:

  1. 登录 QQ 邮箱网页版:https://mail.qq.com
  2. 点击顶部 设置 → 账户
  3. 找到 POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
  4. 开启 IMAP/SMTP服务
  5. 按照提示用手机发送短信验证 ,完成后会生成一个 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-emailorder-app-emailcritical-email 同时配置了 email_configswebhook_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

PromLabs |PromQL 速查表

查询基础 |普罗米修斯

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cllsse

富✌您吉祥

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值