kube-prometheus-stack 安装配置文档

本文档介绍了在 Kubernetes 集群中安装和配置 kube-prometheus-stack 监控组件的两种方式(在线安装和离线/网络不佳情况下的安装)、如何访问 Grafana 仪表盘,以及如何配置邮件、钉钉和飞书等报警通知。

0. 安装前准备(重要):修改 127.0.0.1 监听地址,避免 Prometheus 抓取失败

在部分 kubeadm 集群中,控制平面组件(controller-manager / scheduler / etcd)以及 kube-proxy 的 metrics 端口可能默认只监听 127.0.0.1,会导致 Prometheus 通过 PodIP/NodeIP 抓取时出现 connect: connection refused

请在安装 kube-prometheus-stack 之前,按以下步骤修改 metrics 监听地址。

说明:

  • 第 1/2/3 项需要在每一台 master 节点上执行(静态 Pod 清单在各节点本地:/etc/kubernetes/manifests/*.yaml)。
  • 避坑警告:备份文件时,绝对不要将备份文件(如 .bak)留在 /etc/kubernetes/manifests/ 目录下!Kubelet 会读取该目录下的所有文件,导致读取到旧配置产生冲突而不生效。请将备份文件存放到其他目录(如 /root//tmp/)。本指南已将备份路径修改为 /root/
  • 第 4 项为 kube-proxy(DaemonSet),修改 ConfigMap 后需滚动重启 kube-proxy。

0.1 清理历史遗留的备份文件(极度重要)

如果您之前在 /etc/kubernetes/manifests/ 目录下生成了 .bak 结尾的备份文件,必须先将它们移出,否则 Kubelet 会因为加载了备份文件导致后续修改无法生效。

# 检查是否存在遗留的备份文件
ls -l /etc/kubernetes/manifests/*.bak* || true

# 将它们统一移动到 /root/ 目录下
sudo mv /etc/kubernetes/manifests/*.bak* /root/ 2>/dev/null || true

0.2 controller-manager(10257)

sudo grep -n -- '--bind-address=' /etc/kubernetes/manifests/kube-controller-manager.yaml

sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml \
  /root/kube-controller-manager.yaml.bak.$(date +%F_%H%M%S)

sudo sed -i -E 's#(--bind-address=).*#\10.0.0.0#' /etc/kubernetes/manifests/kube-controller-manager.yaml


kubectl -n kube-system get pod -o wide | grep kube-controller-manager
sudo ss -lntp | grep 10257

0.3 etcd(2381)

sudo grep -n -- '--listen-metrics-urls' /etc/kubernetes/manifests/etcd.yaml || true

sudo cp -a /etc/kubernetes/manifests/etcd.yaml \
  /root/etcd.yaml.bak.$(date +%F_%H%M%S)

sudo sed -i -E 's#(--listen-metrics-urls=http://)127\.0\.0\.1:2381#\10.0.0.0:2381#' /etc/kubernetes/manifests/etcd.yaml
sudo sed -i -E 's#(--listen-metrics-urls=http://)\[::1\]:2381#\10.0.0.0:2381#' /etc/kubernetes/manifests/etcd.yaml


sudo ss -lntp | grep 2381

0.4 kube-scheduler(10259)

sudo grep -n -- '--bind-address=' /etc/kubernetes/manifests/kube-scheduler.yaml || true

sudo cp -a /etc/kubernetes/manifests/kube-scheduler.yaml \
  /root/kube-scheduler.yaml.bak.$(date +%F_%H%M%S)

sudo sed -i -E 's#(--bind-address=).*#\10.0.0.0#' /etc/kubernetes/manifests/kube-scheduler.yaml


kubectl -n kube-system get pod -o wide | grep kube-scheduler
sudo ss -lntp | grep 10259

0.5 kube-proxy(10249)

kubectl -n kube-system get cm | grep -i proxy

kubectl -n kube-system get cm kube-proxy -o yaml > /root/kube-proxy-cm.bak.$(date +%F_%H%M%S).yaml

NEW_CONF="$(kubectl -n kube-system get cm kube-proxy -o jsonpath='{.data.config\.conf}' \
  | sed -E 's#(^[[:space:]]*metricsBindAddress:[[:space:]]*).*$#\10.0.0.0:10249#m')"

kubectl -n kube-system patch cm kube-proxy --type merge \
  -p "{\"data\":{\"config.conf\":$(printf '%s' "$NEW_CONF" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}}"

kubectl -n kube-system rollout restart ds/kube-proxy
kubectl -n kube-system rollout status ds/kube-proxy

1. 方式一:在线安装(网络良好)

如果您的集群网络可以直接拉取官方镜像,可以直接使用 Helm 在线安装:

# 添加 prometheus-community 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 搜索仓库确认
helm search repo prometheus-community | grep kube-prometheus-stack

# 方式A:执行安装/更新 (默认配置,仅集群内访问)
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \ 
  --namespace monitoring \ 
  --create-namespace \ 
  --set grafana.enabled=true \ 
  --set grafana.deploymentStrategy.type=Recreate \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false # 允许 Prometheus 自动发现并抓取所有未指定特定 Label 的 ServiceMonitor
# 方式B:执行安装/更新 (支持直接开启 Grafana、Prometheus 和 Alertmanager 的 NodePort 供外部访问)
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=<您的节点IP>" \
  --set "grafana.grafana\.ini.server.root_url=http://<您的节点IP>:32000" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \# 允许抓取所有 ServiceMonitor
  --set grafana.service.type=NodePort \
  --set grafana.service.nodePort=32000 \
  --set prometheus.service.type=NodePort \
  --set prometheus.service.nodePort=32090 \
  --set alertmanager.service.type=NodePort \
  --set alertmanager.service.nodePort=32093
# 方式C:执行安装/更新 (支持直接开启 Grafana、Prometheus 和 Alertmanager 的 Ingress 供外部域名访问)
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=http://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=nginx \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=nginx \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=nginx \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}"
# 方式D:执行安装/更新 (支持直接开启 Ingress 供外部域名访问,使用 Higress 网关并自动配置 TLS 证书)
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=https://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=higress \
  --set grafana.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string grafana.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set grafana.ingress.tls[0].secretName=grafana-tls \
  --set grafana.ingress.tls[0].hosts[0]=grafana.aioil.top \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=higress \
  --set prometheus.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string prometheus.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set prometheus.ingress.tls[0].secretName=prometheus-tls \
  --set prometheus.ingress.tls[0].hosts[0]=prometheus.aioil.top \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=higress \
  --set alertmanager.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string alertmanager.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}" \
  --set alertmanager.ingress.tls[0].secretName=alertmanager-tls \
  --set alertmanager.ingress.tls[0].hosts[0]=alertmanager.aioil.top
# 方式E:执行安装/更新 (在方式D的基础上,增加 StorageClass 持久化存储,保证监控数据和面板配置重启不丢失)
# 注意:以下使用集群默认 StorageClass `rook-ceph-block` (RBD)。您也可根据需求替换为 `rook-ceph-block-retain` (Retain回收策略更安全)、
#       或 `rook-cephfs` (CephFS, 支持 ReadWriteMany)。可通过 `kubectl get sc` 查看集群中所有可用 StorageClass。
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=https://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=higress \
  --set grafana.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string grafana.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set grafana.ingress.tls[0].secretName=grafana-tls \
  --set grafana.ingress.tls[0].hosts[0]=grafana.aioil.top \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=higress \
  --set prometheus.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string prometheus.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set prometheus.ingress.tls[0].secretName=prometheus-tls \
  --set prometheus.ingress.tls[0].hosts[0]=prometheus.aioil.top \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=higress \
  --set alertmanager.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string alertmanager.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}" \
  --set alertmanager.ingress.tls[0].secretName=alertmanager-tls \
  --set alertmanager.ingress.tls[0].hosts[0]=alertmanager.aioil.top \
  --set grafana.persistence.enabled=true \
  --set grafana.persistence.storageClassName="rook-ceph-block" \
  --set grafana.persistence.size=20Gi \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName="rook-ceph-block" \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.accessModes[0]="ReadWriteOnce" \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage="50Gi" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.storageClassName="rook-ceph-block" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.accessModes[0]="ReadWriteOnce" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.resources.requests.storage="20Gi"

📦 持久化存储扩容说明rook-ceph-block StorageClass 已启用 ALLOWVOLUMEEXPANSION: true,后期如果 Grafana/Prometheus/Alertmanager 的存储空间不足,可以直接在线扩容 PVC,无需重新部署。

扩容步骤(以 Grafana 10Gi → 20Gi 为例)

# 1. 编辑 PVC,将 spec.resources.requests.storage 改为 20Gi
kubectl edit pvc prometheus-stack-grafana -n monitoring

# 2. 重启对应 Pod 使其重新挂载扩容后的卷
kubectl rollout restart deployment prometheus-stack-grafana -n monitoring

Prometheus 和 Alertmanager 扩容方式同理,只需替换 PVC 名称:

  • Prometheus PVC:prometheus-prometheus-stack-kube-prom-prometheus-db-prometheus-prometheus-stack-kube-prom-prometheus-0
    (实际名称可用 kubectl get pvc -n monitoring | grep prometheus 确认)
  • Alertmanager PVC:alertmanager-prometheus-stack-kube-prom-alertmanager-db-alertmanager-prometheus-stack-kube-prom-alertmanager-0

2. 方式二:离线包安装及国内镜像源替换(网络不佳)

如果拉取官方镜像速度较慢或超时,可以下载 Chart 压缩包,替换其中的镜像地址为国内加速源后再进行本地安装。

2.1 下载并解压 Chart 包

# 下载指定版本的压缩包 (例如 85.1.3)
wget https://github.com/prometheus-community/helm-charts/releases/download/kube-prometheus-stack-85.1.3/kube-prometheus-stack-85.1.3.tgz 

# 解压压缩包
tar xvf kube-prometheus-stack-85.1.3.tgz 

# 进入解压后的目录
cd kube-prometheus-stack 

(注:如果需要通过源码包下载,可以使用 wget https://github.com/prometheus-community/helm-charts/archive/refs/tags/kube-prometheus-stack-85.1.3.tar.gz)

2.2 替换镜像为国内加速源

在解压后的 kube-prometheus-stack 目录下执行以下命令,将官方镜像替换为 DaoCloud 的国内加速镜像:

# 替换主 values.yaml 
sed -i 's#registry.k8s.io#k8s.m.daocloud.io#g' values.yaml 
sed -i 's#quay.io#quay.m.daocloud.io#g' values.yaml 
sed -i 's#docker.io#docker.m.daocloud.io#g' values.yaml 

# 替换 kube-state-metrics 子 chart 
sed -i 's#registry.k8s.io#k8s.m.daocloud.io#g' charts/kube-state-metrics/values.yaml 

# 替换 grafana 子 chart 
sed -i 's#registry.k8s.io#k8s.m.daocloud.io#g' charts/grafana/values.yaml  
sed -i 's#quay.io#quay.m.daocloud.io#g' charts/grafana/values.yaml  
sed -i 's#docker.io#docker.m.daocloud.io#g' charts/grafana/values.yaml  

2.3 执行本地安装

使用当前目录 (.) 作为 chart 源进行安装:

# 方式A:执行本地安装/更新 (默认配置,仅集群内访问)
helm upgrade --install prometheus-stack . \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false # 允许 Prometheus 自动发现并抓取所有未指定特定 Label 的 ServiceMonitor
# 方式B:执行本地安装/更新 (支持直接开启 Grafana、Prometheus 和 Alertmanager 的 NodePort 供外部访问)
helm upgrade --install prometheus-stack . \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=<您的节点IP>" \
  --set "grafana.grafana\.ini.server.root_url=http://<您的节点IP>:32000" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \ # 允许抓取所有 ServiceMonitor
  --set grafana.service.type=NodePort \
  --set grafana.service.nodePort=32000 \
  --set prometheus.service.type=NodePort \
  --set prometheus.service.nodePort=32090 \
  --set alertmanager.service.type=NodePort \
  --set alertmanager.service.nodePort=32093
# 方式C:执行本地安装/更新 (支持直接开启 Grafana、Prometheus 和 Alertmanager 的 Ingress 供外部域名访问)
helm upgrade --install prometheus-stack . \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=http://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=nginx \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=nginx \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=nginx \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}"
# 方式D:执行本地安装/更新 (支持直接开启 Ingress 供外部域名访问,使用 Higress 网关并自动配置 TLS 证书)
helm upgrade --install prometheus-stack . \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=https://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=higress \
  --set grafana.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string grafana.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set grafana.ingress.tls[0].secretName=grafana-tls \
  --set grafana.ingress.tls[0].hosts[0]=grafana.aioil.top \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=higress \
  --set prometheus.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string prometheus.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set prometheus.ingress.tls[0].secretName=prometheus-tls \
  --set prometheus.ingress.tls[0].hosts[0]=prometheus.aioil.top \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=higress \
  --set alertmanager.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string alertmanager.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}" \
  --set alertmanager.ingress.tls[0].secretName=alertmanager-tls \
  --set alertmanager.ingress.tls[0].hosts[0]=alertmanager.aioil.top
# 方式E:执行本地安装/更新 (在方式D的基础上,增加 StorageClass 持久化存储,保证监控数据和面板配置重启不丢失)
# 注意:以下使用集群默认 StorageClass `rook-ceph-block` (RBD)。您也可根据需求替换为 `rook-ceph-block-retain` (Retain回收策略更安全)、
#       或 `rook-cephfs` (CephFS, 支持 ReadWriteMany)。可通过 `kubectl get sc` 查看集群中所有可用 StorageClass。
helm upgrade --install prometheus-stack . \
  --namespace monitoring \
  --create-namespace \
  --set grafana.enabled=true \
  --set grafana.deploymentStrategy.type=Recreate \
  --set "grafana.grafana\.ini.server.domain=grafana.aioil.top" \
  --set "grafana.grafana\.ini.server.root_url=https://grafana.aioil.top" \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set grafana.ingress.enabled=true \
  --set grafana.ingress.ingressClassName=higress \
  --set grafana.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string grafana.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set grafana.ingress.hosts="{grafana.aioil.top}" \
  --set grafana.ingress.tls[0].secretName=grafana-tls \
  --set grafana.ingress.tls[0].hosts[0]=grafana.aioil.top \
  --set prometheus.ingress.enabled=true \
  --set prometheus.ingress.ingressClassName=higress \
  --set prometheus.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string prometheus.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set prometheus.ingress.hosts="{prometheus.aioil.top}" \
  --set prometheus.ingress.tls[0].secretName=prometheus-tls \
  --set prometheus.ingress.tls[0].hosts[0]=prometheus.aioil.top \
  --set alertmanager.ingress.enabled=true \
  --set alertmanager.ingress.ingressClassName=higress \
  --set alertmanager.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-prod-dns \
  --set-string alertmanager.ingress.annotations."nginx\.ingress\.kubernetes\.io/ssl-redirect"="true" \
  --set alertmanager.ingress.hosts="{alertmanager.aioil.top}" \
  --set alertmanager.ingress.tls[0].secretName=alertmanager-tls \
  --set alertmanager.ingress.tls[0].hosts[0]=alertmanager.aioil.top \
  --set grafana.persistence.enabled=true \
  --set grafana.persistence.storageClassName="rook-ceph-block" \
  --set grafana.persistence.size=10Gi \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName="rook-ceph-block" \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.accessModes[0]="ReadWriteOnce" \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage="50Gi" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.storageClassName="rook-ceph-block" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.accessModes[0]="ReadWriteOnce" \
  --set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.resources.requests.storage="20Gi"

3. 验证安装状态

安装完成后,可以通过以下命令查看监控组件的 Pod、Service 和 Ingress 状态:

kubectl get po -n monitoring 
kubectl get svc -n monitoring 
kubectl get ingress -n monitoring 

4. 访问监控组件仪表盘

默认情况下,kube-prometheus-stack 中的各个组件(如 Grafana、Prometheus、Alertmanager 等)会以 ClusterIP 方式暴露,只能在集群内部访问。你可以使用 kubectl port-forward 命令将这些服务映射到本地,从而在浏览器中直接访问。

注意:加入 --address 0.0.0.0 参数可以允许不仅是本机(localhost),还允许局域网内的其他机器通过当前机器的 IP 来访问这些映射的端口。这在您通过 SSH 连接到服务器进行操作时非常有用。

4.1 访问 Grafana 仪表盘

方式一:临时端口转发 (Port-Forward)
执行以下命令将 Grafana 服务暴露出来:

kubectl port-forward --address 0.0.0.0 svc/prometheus-stack-grafana 3000:80 -n monitoring 
  • 命令解释:将 monitoring 命名空间下名为 prometheus-stack-grafana 服务的 80 端口,映射到当前机器的所有网卡(0.0.0.0)的 3000 端口上。
  • 访问方式:在浏览器中访问 http://<您的机器IP>:3000

方式二:永久修改为 NodePort (推荐外部访问使用)
如果您希望长期通过节点的 IP 地址访问,可以将其 Service 类型修改为 NodePort,并指定一个固定端口(例如 32000):

kubectl patch svc prometheus-stack-grafana -n monitoring -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 3000, "nodePort": 32000}]}}'
  • 访问方式:在浏览器中访问 http://<任意K8s-Node-IP>:32000

  • 默认登录凭据

    • 用户名admin
    • 密码:可以通过以下命令获取并解密:
      kubectl get secret -n monitoring prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode 
      

方式三:通过 YAML 文件独立创建 Ingress
如果您不想修改 Helm 配置,也可以直接编写 Ingress 资源清单并应用:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheus-stack-grafana-ingress
  namespace: monitoring
spec:
  ingressClassName: nginx
  rules:
  - host: grafana.aioil.top
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus-stack-grafana
            port:
              number: 80

保存为 grafana-ingress.yaml,然后执行 kubectl apply -f grafana-ingress.yaml 即可。

4.2 访问 Prometheus 原生 UI

方式一:临时端口转发 (Port-Forward)
执行以下命令将 Prometheus 服务暴露出来:

kubectl port-forward --address 0.0.0.0 svc/prometheus-stack-kube-prom-prometheus 9090:9090 -n monitoring 
  • 命令解释:将 monitoring 命名空间下名为 prometheus-stack-kube-prom-prometheus 服务的 9090 端口,映射到当前机器的所有网卡(0.0.0.0)的 9090 端口上。
  • 访问方式:在浏览器中访问 http://<您的机器IP>:9090,可以直接使用 PromQL 查询指标数据。

方式二:永久修改为 NodePort
修改 Service 为 NodePort 并指定固定端口(例如 32090):

kubectl patch svc prometheus-stack-kube-prom-prometheus -n monitoring -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 32090}]}}'
  • 访问方式:在浏览器中访问 http://<任意K8s-Node-IP>:32090

方式三:通过 YAML 文件独立创建 Ingress
如果您希望通过域名访问 Prometheus,可以编写如下 Ingress 资源清单:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheus-stack-prometheus-ingress
  namespace: monitoring
spec:
  ingressClassName: nginx
  rules:
  - host: prometheus.aioil.top
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus-stack-kube-prom-prometheus
            port:
              number: 9090

保存为 prometheus-ingress.yaml,然后执行 kubectl apply -f prometheus-ingress.yaml 即可。

  • 访问方式:配置本地 hosts 或 DNS 解析后,在浏览器中访问 http://prometheus.aioil.top

4.3 访问 Alertmanager 报警面板

方式一:临时端口转发 (Port-Forward)
执行以下命令将 Alertmanager 服务暴露出来:

kubectl port-forward --address 0.0.0.0 svc/prometheus-stack-kube-prom-alertmanager 9093:9093 -n monitoring 
  • 命令解释:将 monitoring 命名空间下名为 prometheus-stack-kube-prom-alertmanager 服务的 9093 端口,映射到当前机器的所有网卡(0.0.0.0)的 9093 端口上。
  • 访问方式:在浏览器中访问 http://<您的机器IP>:9093,可以查看当前触发的报警规则和告警信息。

方式二:永久修改为 NodePort
修改 Service 为 NodePort 并指定固定端口(例如 32093):

kubectl patch svc prometheus-stack-kube-prom-alertmanager -n monitoring -p '{"spec": {"type": "NodePort", "ports": [{"port": 9093, "targetPort": 9093, "nodePort": 32093}]}}'
  • 访问方式:在浏览器中访问 http://<任意K8s-Node-IP>:32093

方式三:通过 YAML 文件独立创建 Ingress
如果您希望通过域名访问 Alertmanager,可以编写如下 Ingress 资源清单:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheus-stack-alertmanager-ingress
  namespace: monitoring
spec:
  ingressClassName: nginx
  rules:
  - host: alertmanager.aioil.top
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus-stack-kube-prom-alertmanager
            port:
              number: 9093

保存为 alertmanager-ingress.yaml,然后执行 kubectl apply -f alertmanager-ingress.yaml 即可。

  • 访问方式:配置本地 hosts 或 DNS 解析后,在浏览器中访问 http://alertmanager.aioil.top

4.4 访问 Node Exporter 指标暴露端口

方式一:临时端口转发 (Port-Forward)
执行以下命令将 Node Exporter 服务暴露出来:

kubectl port-forward --address 0.0.0.0 svc/prometheus-stack-prometheus-node-exporter 9110:9100 -n monitoring 
  • 命令解释:将 monitoring 命名空间下名为 prometheus-stack-prometheus-node-exporter 服务的 9100 端口,映射到当前机器的所有网卡(0.0.0.0)的 9110 端口上。(注意:这里本地映射端口改为了 9110,避免与本地可能运行的其他服务冲突)。
  • 访问方式:在浏览器中访问 http://<您的机器IP>:9110/metrics,可以看到该节点采集到的基础物理指标(CPU、内存、磁盘等)的原始数据。

方式二:永久修改为 NodePort
修改 Service 为 NodePort 并指定固定端口(例如 32110):

kubectl patch svc prometheus-stack-prometheus-node-exporter -n monitoring -p '{"spec": {"type": "NodePort", "ports": [{"port": 9100, "targetPort": 9100, "nodePort": 32110}]}}'
  • 访问方式:在浏览器中访问 http://<任意K8s-Node-IP>:32110/metrics

方式三:通过 YAML 文件独立创建 Ingress
如果您希望通过域名访问 Node Exporter 指标,可以编写如下 Ingress 资源清单:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheus-stack-node-exporter-ingress
  namespace: monitoring
spec:
  ingressClassName: nginx
  rules:
  - host: node-exporter.aioil.top
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheus-stack-prometheus-node-exporter
            port:
              number: 9100

保存为 node-exporter-ingress.yaml,然后执行 kubectl apply -f node-exporter-ingress.yaml 即可。

  • 访问方式:配置本地 hosts 或 DNS 解析后,在浏览器中访问 http://node-exporter.aioil.top/metrics

5. 配置报警通知 (邮件、钉钉、飞书)

Alertmanager 默认支持邮件(Email)、企业微信(WeChat)、Slack 等原生报警配置,但对于钉钉(DingTalk)和飞书(Feishu),需要通过 Webhook 配合中间件转发来实现。

5.1 配置邮件报警 (原生支持)

可以在部署时通过覆盖 values.yaml 中的 alertmanager.config 来配置邮件报警。以下是以 QQ 邮箱为例的配置。

注意: 对于 QQ 邮箱等第三方邮箱,smtp_auth_password 通常不能使用网页登录密码,而是需要使用邮箱设置中生成的授权码

获取 QQ 邮箱授权码的步骤:

  1. 电脑端登录你的 QQ 邮箱 / Foxmail 邮箱。
  2. 点击顶部的 设置 -> 账号与安全 -> 安全设置
  3. 向下滚动找到 POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 区域。
  4. 确保 POP3/SMTP服务 已开启,然后点击下方的 生成授权码
  5. 根据提示完成密保验证(通常是发送短信),然后将获取到的一串英文字母填入下方配置的 smtp_auth_password 中。
alertmanager:
  config:
    global:
      # 当告警状态从 firing 变为 resolved 时,Alertmanager 等待多长时间才发送恢复通知
      resolve_timeout: 5m
      # SMTP 服务器地址和端口 (这里以 QQ 邮箱为例,465 端口通常用于 SSL 加密传输)
      smtp_smarthost: 'smtp.qq.com:465'
      # 发件人的邮箱地址
      smtp_from: 'your-email@foxmail.com'
      # SMTP 认证用户名 (通常与发件人邮箱相同)
      smtp_auth_username: 'your-email@foxmail.com'
      # SMTP 认证密码或授权码 (QQ/网易等第三方邮箱通常需要使用授权码而不是网页登录密码)
      smtp_auth_password: 'your-auth-password'
      # 是否强制要求 TLS 连接。由于 QQ 邮箱 465 端口已经是隐式 SSL 协议,因此这里设为 false
      smtp_require_tls: false
    route:
      # 告警分组策略:将具有相同 namespace 和 alertname 标签的告警合并成一条通知发送,避免告警风暴
      group_by: ['namespace', 'alertname']
      # 分组等待时间:产生新告警后,等待 30s 收集同组的其他告警,然后合并后一起发送
      group_wait: 30s
      # 分组间隔时间:当一组告警已经发送过通知后,如果该组内有新的告警产生,需等待 5m 后才再次发送通知
      group_interval: 5m
      # 重复发送间隔:如果告警一直处于未解决 (firing) 状态,每隔 12h 会重新发送一次通知提醒
      repeat_interval: 12h
      # 默认接收者:如果没有匹配到任何子路由规则,告警将默认发送给这个接收者
      receiver: 'email-receiver'
      routes:
      # 子路由规则配置
      - receiver: 'email-receiver'
        # 匹配器配置:只有告警标签 severity 为 warning 或 critical 时,才会进入此路由发送通知
        matchers:
          - severity=~"warning|critical"
    receivers:
    # 接收者配置列表
    - name: 'email-receiver'
      # 邮件发送配置
      email_configs:
      # 收件人的邮箱地址
      - to: 'your-email@foxmail.com'
        # 告警恢复时,是否发送已恢复 (resolved) 的通知邮件
        send_resolved: true

将上述内容保存到 values-alert.yaml,然后使用 Helm 更新(在线安装或离线安装根据实际情况调整命令):

# 如果是离线安装方式,请将 prometheus-community/kube-prometheus-stack 替换为本地的 chart 目录(例如:.)
helm upgrade prometheus-stack prometheus-community/kube-prometheus-stack -n monitoring \
  --reuse-values \
  -f values-alert.yaml

注意: 如果你之前使用 --set 参数(例如开启了 Ingress 或 NodePort)安装了 Helm release,在执行 helm upgrade 时一定要加上 --reuse-values 参数,否则之前配置的那些 --set 参数(包括 Ingress 配置)都会被覆盖丢失!

5.1.1 检查配置是否生效

执行完更新命令后,可以通过以下几种方式验证 Alertmanager 是否成功加载了最新的邮件配置:

方式一:通过 Alertmanager Web UI 查看 (推荐)

  1. 确保已经通过端口转发或 NodePort 暴露了 Alertmanager 服务(参考 4.3 章节)。
  2. 在浏览器中访问 Alertmanager 面板(如 http://<机器IP>:9093)。
  3. 点击顶部导航栏的 Status
  4. Config 区块中,你可以直接看到当前 Alertmanager 正在运行的配置文件内容,检查是否包含你刚刚添加的邮箱配置。

方式二:通过 kubectl 查看集群中的 Secret
Alertmanager 的配置最终会被 Helm 渲染并存储为一个 Secret,你可以直接解密查看该 Secret 的内容:

kubectl get secret alertmanager-prometheus-stack-kube-prom-alertmanager -n monitoring -o jsonpath="{.data.alertmanager\.yaml}" | base64 --decode

方式三:查看 Alertmanager Pod 日志
检查 Alertmanager 的日志,确认其成功启动或加载了配置,且没有报错信息:

kubectl logs -l app.kubernetes.io/name=alertmanager -n monitoring -c alertmanager

(注:新版本的 Prometheus Operator 会通过独立的 config-reloader sidecar 容器来处理配置更新,主容器 alertmanager 的日志中可能不会出现 reload 关键字,只要没有 Error 即代表正常运行)

5.1.2 验证邮件发送功能 (发送测试告警)

配置更新并生效后,可以通过向 Alertmanager 的 API 发送一条模拟告警来验证邮件是否能成功接收。

打开终端,使用 curl 命令发送一条级别为 warning 的模拟告警(由于配置中已将报警级别门槛设置为 warning 及以上,带有 warningcritical 标签均可触发)。

注意: 请根据你在 4.3 章节中选择的 Alertmanager 暴露方式,将下面命令末尾的 URL 替换为实际地址:

  • 如果配置了 Ingress:使用 http://alertmanager.aioil.top/api/v2/alerts
  • 如果配置了 NodePort:使用 http://<任意Node-IP>:32093/api/v2/alerts
  • 如果使用 Port-Forward:使用 http://localhost:9093/api/v2/alerts
curl -H "Content-Type: application/json" -d '[
  {
    "labels": {
      "alertname": "TestEmailAlert",
      "severity": "warning"
    },
    "annotations": {
      "summary": "这是一条测试邮件告警",
      "description": "用于验证 Alertmanager 的邮件发送功能是否配置成功。"
    }
  }
]' <请替换为你的 Alertmanager 实际地址>/api/v2/alerts

(注:执行成功后通常没有任何文本输出,这是正常的)

稍等片刻,登录你的接收邮箱,检查是否成功收到了标题包含 TestEmailAlert 的告警邮件。

关于重复发送告警的限制:

  • repeat_interval: 12h:如果同一个告警(比如上面你刚刚发的那条 TestEmailAlert)一直处于未恢复(firing)状态,Alertmanager 会等待 12 小时后才重新发送一次邮件,以防止邮件轰炸。如果你想多次测试同一条告警,可以临时修改 curl 命令中 alertname 的值(例如改为 TestEmailAlert2),或者在发送 info 级别测试邮件后,再发一条包含 "endsAt": "2023-10-25T12:00:00Z" 的解除告警,之后就能再次发送了。
5.1.3 如何通过日志排查邮件发送失败问题

如果你在邮箱中一直没有收到邮件,可以通过查看 Alertmanager 的日志来定位问题。

  1. 查看 Alertmanager 实时日志:
kubectl logs -f -l app.kubernetes.io/name=alertmanager -n monitoring -c alertmanager

(注:默认情况下,Alertmanager 日志级别为 info。因为生产环境中告警较多,“没有消息就是好消息”,邮件发送成功时控制台通常没有任何日志输出,只有发送失败或重载配置时才会打印。如果你想查看详细的发送成功日志,可以在 helm upgrade 时增加 --set alertmanager.alertmanagerSpec.logLevel=debug 参数来开启 Debug 模式)

  1. 常见错误及排查思路:
  • 如果日志中出现 AuthError535 Login Failauthorization failed:说明 smtp_auth_password (授权码) 填写错误,或者邮箱的 SMTP/POP3 服务未开启。
  • 如果日志中出现 connection refusedtimeout:说明 Kubernetes 集群网络无法连接到 smtp.qq.com:465,请检查服务器网络或防火墙策略。
  • 如果日志中出现 certificate signed by unknown authority 等 TLS 报错:可以检查配置中 smtp_require_tls: false 是否生效,或者尝试将端口改为 465 (SSL) 或 587 (TLS)。
5.1.4 Alertmanager 面板 Silence (静默) 功能说明

在 Alertmanager 的 Web UI 告警列表中,每条告警旁边都有一个 Silence(静默)按钮。

  • 作用:当集群出现已知故障或正在进行停机维护时,你可以点击 Silence 按钮,通过标签匹配(如指定 alertname="Watchdog")并设置一个时间段(例如 2 小时)。
  • 常见报错 (Silence is not yet valid):如果你在提交 Silence 时遇到 Could not submit the form, Silence is not yet valid,这不是代表没报警了,而是因为你设置的 Start 时间 (生效时间) 晚于当前服务器的真实时间。由于浏览器时间和服务器时间可能存在几十秒到几分钟的误差,或者时区不一致,导致你提交的时间被判定为“未来的时间”。
    • 解决办法:在创建 Silence 表单时,将 Start (开始时间) 手动往前调 1-2 分钟,然后再点击提交即可。
  • 效果:在这个时间段内,即使 Prometheus 不断触发这条告警发送给 Alertmanager,Alertmanager 也不会将它转发给接收者(不会发邮件/钉钉/飞书等)。
  • 使用场景:非常适合在日常系统维护发布、或者处理已知长时间故障时,防止持续收到骚扰邮件。静默期结束后,如果告警仍然存在,则会恢复发送。

5.2 配置钉钉和飞书报警 (需借助 Webhook 转发)

由于 Alertmanager 原生不支持钉钉和飞书,我们通常需要部署一个 Webhook 转换器(例如开源的 PrometheusAlert),将 Alertmanager 的 Webhook 请求转换为钉钉或飞书支持的 API 请求格式。

步骤 1:部署 PrometheusAlert(支持钉钉、飞书、企业微信等)

创建一个简单的 PrometheusAlert 部署文件 prometheusalert.yaml,并附带 Ingress 以便外部访问:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheusalert
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheusalert
  template:
    metadata:
      labels:
        app: prometheusalert
    spec:
      containers:
      - name: prometheusalert
        image: feiyu563/prometheus-alert:latest
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: prometheusalert
  namespace: monitoring
spec:
  selector:
    app: prometheusalert
  ports:
  - port: 8080
    targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prometheusalert-ingress
  namespace: monitoring
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod-dns
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: higress
  tls:
  - hosts:
    - prometheusalert.aioil.top
    secretName: prometheusalert-tls
  rules:
  - host: prometheusalert.aioil.top
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prometheusalert
            port:
              number: 8080

执行部署:

kubectl apply -f prometheusalert.yaml

部署完成后,你可以通过配置的域名访问其管理后台进行测试和模板配置:

  • 访问地址https://prometheusalert.aioil.top
  • 默认用户名prometheusalert
  • 默认密码prometheusalert
验证 TLS 证书是否正常签发

由于 Ingress 配置了 cert-manager.io/cluster-issuer 注解,部署后 cert-manager 会自动为 prometheusalert.aioil.top 申请证书。可通过以下命令确认证书状态:

# 1. 查看 Ingress 是否正确关联了 Higress
kubectl describe ingress prometheusalert-ingress -n monitoring
# 确认:Ingress Class 为 higress,且 TLS 证书 secretName 为 prometheusalert-tls

# 2. 查看 Certificate 资源状态(cert-manager 会自动创建 Certificate 资源)
kubectl get certificate -n monitoring | grep prometheusalert
# 正常情况下 STATE 应显示 Ready=True。如果卡在 Pending,往下逐级排查:
#   Certificate → CertificateRequest → Order → Challenge

# 3. 查看证书详情(含到期时间和续期计划)
kubectl describe certificate prometheusalert-tls -n monitoring
# 关键字段:
#   - Not After:  证书过期时间
#   - Not Before: 证书生效时间
#   - Renewal Time: 计划续期时间(通常在过期前 30 天)
#   - Status.Conditions 中 Ready=True 代表签发成功

# 4. 查看证书 Secret 是否包含 tls.crt 和 tls.key
kubectl get secret prometheusalert-tls -n monitoring
# 正常应显示 TYPE 为 kubernetes.io/tls,DATA 为 2(tls.crt + tls.key)

# 5. 如果证书一直未 Ready,逐级排查签发流程
kubectl get certificaterequest -n monitoring | grep prometheusalert
kubectl get order -n monitoring | grep prometheusalert
kubectl get challenge -n monitoring | grep prometheusalert
# 通过 kubectl describe 对应资源可查看具体失败原因(如 DNS 记录未生效、Webhook 凭证错误等)

# 6. 验证 HTTPS 访问
curl -v https://prometheusalert.aioil.top
# 确认输出中 TLS 握手成功,且证书 CN/SAN 匹配 prometheusalert.aioil.top

故障排查提示

  • 如果 Certificate 一直处于 Pending 状态,通常是因为 DNS-01 挑战未完成。可查看 alidns-webhook 日志:kubectl logs -f -n cert-manager deploy/alidns-webhook --tail=100
  • 如果 cert-manager Controller 未能识别 Ingress annotation,检查 ClusterIssuer letsencrypt-prod-dns 是否已创建且状态为 Ready:kubectl get clusterissuer letsencrypt-prod-dns
步骤 2:配置 Alertmanager 发送 Webhook

修改 values-alert.yaml 中的 Alertmanager 配置,将告警发送给 PrometheusAlert 的 Service 地址:

alertmanager:
  config:
    global:
      resolve_timeout: 5m
    route:
      # 将告警按照 alertname 进行分组
      group_by: ['alertname']
      # 当产生一个新分组的告警时,等待 10s 以收集同组的其他告警,然后一起发送(避免告警轰炸)
      group_wait: 10s
      # 当第一个告警发送后,如果该组又产生了新的告警,需等待 10s 后再将新告警合并发送
      group_interval: 10s
      # 注意:Alertmanager 原生不支持“阶梯式/递增式频率重发”(如前3次每60秒发一次,之后每1小时发一次)。
      # 它的重发频率是固定的,由 repeat_interval 决定(如 1h 代表永远是每隔 1 小时发一次)。
      # 如果有递增报警频率的复杂需求,必须借助外部的告警中心系统(如 夜莺 Nightingale、PrometheusAlert 深度定制开发、或自建 Webhook 服务)来实现。
      repeat_interval: 1h
      # 默认的接收者。如果没有匹配到下面 routes 里的规则,告警就会发给这个接收者。
      # 这里的名字必须和最下方 receivers 列表中的 name 保持一致。
      receiver: 'prometheusalert-webhook'
      routes:
      - receiver: 'prometheusalert-webhook'
        matchers:
          - severity=~"warning|critical"
    receivers:
    - name: 'prometheusalert-webhook'
      webhook_configs:
      # 钉钉报警配置示例 (注意替换 ddurl 为你的钉钉群机器人 Webhook 地址)
      - url: 'http://prometheusalert.monitoring.svc.cluster.local:8080/prometheusalert?type=dd&tpl=prometheus-dd&ddurl=https://oapi.dingtalk.com/robot/send?access_token=9de0877c213ac09b09f562951b1860070f2a6b5af87f585b3d86b8a2f61e3dbf'
        send_resolved: true
      
      # 飞书报警配置示例 (注意替换 fsurl 为你的飞书群机器人 Webhook 地址)
      # - url: 'http://prometheusalert.monitoring.svc.cluster.local:8080/prometheusalert?type=fs&tpl=prometheus-fs&fsurl=https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_FEISHU_TOKEN'
      #   send_resolved: true

说明:

  • url 参数中的 type=dd 代表钉钉,type=fs 代表飞书。
  • tpl 为在 PrometheusAlert 中内置的报警内容格式模板。
  • ddurlfsurl 分别为钉钉和飞书机器人的 Webhook 地址。

保存后再次更新 Helm Release:

# 如果是离线安装方式,请将 prometheus-community/kube-prometheus-stack 替换为本地的 chart 目录(例如:.)
helm upgrade prometheus-stack prometheus-community/kube-prometheus-stack -n monitoring \
  --reuse-values \
  -f values-alert.yaml
步骤 3:验证钉钉/飞书发送功能 (发送测试告警)

和前面测试邮件类似,我们可以向 Alertmanager 发送一条告警来验证 Webhook 是否能成功把消息推送到你的钉钉/飞书群。

打开终端,执行以下 curl 命令(发送 warning 级别告警触发我们刚配置的路由)。同样地,请根据你的 Alertmanager 部署方式替换 URL 地址:

curl -H "Content-Type: application/json" -d '[
  {
    "labels": {
      "alertname": "TestWebhookAlert",
      "severity": "warning"
    },
    "annotations": {
      "summary": "这是一条测试 Webhook 告警",
      "description": "用于验证 Alertmanager 通过 PrometheusAlert 转发给钉钉/飞书的功能是否配置成功。"
    }
  }
]' <请替换为你的 Alertmanager 实际地址>/api/v2/alerts

验证方法:

  1. 查看群消息:稍等片刻(大约 10 秒的 group_wait 时间),看看你的钉钉/飞书群是否收到了对应的机器人消息卡片。
  2. 排查错误:如果没有收到,可以通过查看 PrometheusAlert 的日志来排查原因:
    kubectl logs -f -l app=prometheusalert -n monitoring
    
    注:如果日志中提示 token is invalid 或类似报错,请检查你在 values-alert.yaml 中配置的 Webhook URL 是否准确,以及钉钉机器人的安全设置(如加签、关键字等)是否匹配。

6. 常见告警规则说明与修改

Prometheus 的告警状态分为三种:

  1. Inactive (未激活):正常状态,未触发报警。
  2. Pending (待触发):监控数据已满足报警条件,但尚未达到规则中配置的持续时间阈值(例如 for: 15m)。这是一种缓冲机制,用于防止短暂的网络抖动或服务重启引发误报。
  3. Firing (已触发):满足报警条件且持续时间超过了阈值,此时 Alertmanager 会向外发送报警通知(如邮件、钉钉等)。

如何查看和修改告警的 Pending 持续时间阈值?

告警的触发阈值是由 PrometheusRule 资源定义的。如果你觉得某个告警(比如 KubeDaemonSetRolloutStuck)反应太慢(默认需要等 15 分钟才报警),或者反应太快(稍微抖动就报警),你可以通过以下方式修改它:

  1. 查找对应的 PrometheusRule 资源
    使用命令搜索包含特定告警规则名称的资源:

    kubectl get prometheusrules -n monitoring
    
  2. 编辑告警规则
    找到对应的规则名称后(例如 prometheus-stack-kube-prom-kubernetes-apps),执行编辑命令:

    kubectl edit prometheusrules prometheus-stack-kube-prom-kubernetes-apps -n monitoring
    
  3. 修改 for 字段的值
    在打开的 YAML 文件中,找到你需要修改的告警规则(例如 alert: KubeDaemonSetRolloutStuck),修改其下方的 for 字段。
    例如,将 15 分钟(15m)改为 5 分钟(5m):

        - alert: KubeDaemonSetRolloutStuck
          annotations:
            description: DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} has not finished or progressed for at least 15m on cluster {{ $labels.cluster }}.
            runbook_url: https://runbooks.prometheus-operator.dev/runbooks/kubernetes/kubedaemonsetrolloutstuck
            summary: DaemonSet rollout is stuck.
          expr: |-
            # ... (此处省略复杂的 PromQL 表达式) ...
          for: 5m  # <--- 将这里的 15m 修改为你期望的 Pending 时间阈值
          labels:
            severity: warning
    
  4. 保存并退出
    保存文件后,Prometheus Operator 会自动检测到规则变化,并热重载 Prometheus 配置,新的时间阈值将立即生效。


7. 自定义告警配置指南 (以 Pod 异常为例)

kube-prometheus-stack 体系中,配置告警主要有两种方式:

  1. 基于 Kubernetes CRD (PrometheusRule) 配置 (官方推荐)
  2. 在 Grafana UI 中配置 (Grafana Managed Alerts)

💡 架构建议:强烈推荐通过 Alertmanager 统一发送告警

无论你是通过 YAML 还是在 Grafana 中配置告警规则,我们都强烈建议将告警路由给底层的 Alertmanager 处理(即前面配置的 PrometheusAlert + 钉钉),而不是让 Grafana 自身直接去发钉钉。

原因如下:

  1. 统一的告警收口:集群内置的告警(如节点宕机、API Server 异常等)都是由 Alertmanager 发送的。如果自定义告警用 Grafana 发,会导致告警渠道割裂,难以统一管理(比如统一静默、统一修改接收人)。
  2. 强大的去重与分组 (Grouping):Alertmanager 拥有强大的路由和分组能力,能把瞬间产生的几百个同类告警合并成一条发送,避免“告警风暴”把钉钉群淹没。而 Grafana 自身的通知机制在这方面较弱。
  3. 配置解耦:Grafana 专注负责“可视化”和“数据评估”,Alertmanager 专注负责“消息分发”,职责清晰。

7.1 方式一:使用 PrometheusRule CRD 配置 (推荐)

这是最符合云原生(GitOps)理念的做法,规则作为代码持久化在 Kubernetes 中,Pod 重启不会丢失。

1. 编写规则文件 custom-pod-alert.yaml

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: custom-pod-alerts
  namespace: monitoring
  labels:
    # 关键:此 Label 必须与 helm 部署时的 release name 一致,Operator 才会热加载
    release: prometheus-stack
spec:
  groups:
  - name: custom.pod.rules
    rules:
    - alert: CustomPodAbnormal
      # PromQL: 筛选出非 Running/Succeeded 状态的异常 Pod
      expr: kube_pod_status_phase{phase=~"Failed|Unknown|Pending"} == 1
      # Pending 缓冲期:持续 3 分钟才触发,防止网络抖动导致的误报
      for: 3m
      labels:
        severity: warning
      annotations:
        summary: "发现异常 Pod: {{ $labels.namespace }}/{{ $labels.pod }}"
        description: "Pod {{ $labels.pod }} 处于 {{ $labels.phase }} 状态已超过 3 分钟,请及时排查。"

2. 应用到集群

kubectl apply -f custom-pod-alert.yaml

应用后无需重启,Prometheus Operator 会自动热加载。只要包含了 severity: warning 等标签,触发后 Alertmanager 就会根据我们之前配置的路由规则自动发送到钉钉。

7.2 方式二:在 Grafana UI 中配置

如果你更习惯图形化操作,可以通过 Grafana 的统一告警界面进行配置。
(注意:请确保 Helm values.yaml 中已开启 grafana.persistence.enabled=true,否则重启后规则会丢失)

操作步骤:

  1. 新建规则: 登录 Grafana -> 左侧菜单 Alerting -> Alert rules -> 点击 + New alert rule
    • Rule name (步骤 1): 在最上方填入告警名称,如 Pod状态异常报警
  2. 定义查询 (Define query and condition):
    • 切换到 Code 模式,选择数据源为 Prometheus
    • 输入查询语句:kube_pod_status_phase{phase=~"Failed|Unknown|Pending"} == 1
    • Alert condition (告警条件) 保持默认:WHEN QUERY IS ABOVE 0
  3. 添加文件夹和标签 (Add folder and labels):
    • Folder: 点击 + New folder 新建一个文件夹(如 K8s-Alerts)用于归类保存该规则。
    • Labels (极其重要): 点击 + Add labels。这里必须添加一个与你 Alertmanager 路由匹配的标签,否则告警发不出去!例如添加 severity = warning
  4. 设置评估行为 (Set evaluation behavior):
    • Evaluation group (评估组): 点击 + New evaluation group 新建一个评估组。
      • 名字建议:建议以“时间间隔+业务类别”命名,例如 1m-k8s-core1m-eval-group
      • 作用:它决定了 Grafana 多久去查一次数据。放在同一个组里的规则,会按照相同的频率(如 1m 每分钟一次)依次执行,这样可以避免瞬间并发查询压垮数据库。
    • Pending period (挂起时间): 设为 3m。表示发现异常后,观察 3 分钟,如果依然异常才真正触发告警,可有效防止短暂的网络抖动或 Pod 正常重启导致的误报。
    • Keep firing for (保持触发状态时长): 保持默认的 None (0s)。如果遇到频繁的“恢复-告警”抖动,可将其调大(如 5m),表示恢复后依然保持告警状态 5 分钟,确认彻底稳定后再发恢复通知。
    • Configure no data and error handling (配置无数据和错误处理):
      • Alert state if no data or all values are null: 【非常关键】必须将默认的 No Data 修改为 OK (或 Normal)。因为当所有 Pod 都正常时,PromQL 是查不到异常数据的,如果保持 No Data 会导致误报!
      • Alert state if execution error or timeout: 保持默认的 Error 即可。
      • Missing series evaluations to resolve (序列丢失自动恢复): 保持默认的 2 即可。意思是如果某个异常的 Pod 被直接删除了(数据彻底消失),Grafana 在连续 2 次查询不到该 Pod 的数据后,会自动将该告警标记为已恢复 (Resolved)。
  5. 配置通知 (Configure notifications):
    • Contact point (联系点): 决定将告警发送到哪里。
      • 推荐方式一:留空/转交 Alertmanager(统一收口)
        • 强烈建议留空或选择指向 Alertmanager 的通道,让 Grafana 将触发的告警转交给外置的 Alertmanager 处理。
        • 注意:较新版本的 Grafana 可能不会显示名为 “Alertmanager” 的默认 Contact Point,而是显示一个名为 empty(或者由 Helm 注入的 grafana-default-email 等)的联系点,并提示 “No integrations configured”。
        • 如何手动添加 Alertmanager 通道(排障方案)? 如果你在 Alertmanager 界面中始终收不到告警,说明默认的通道可能未生效。此时你需要手动添加它:
          1. 在 Grafana 左侧菜单进入 Alerting -> Contact points
          2. 点击 + Add contact point
          3. Name: 填入 My-Alertmanager
          4. Integration: 下拉选择 Alertmanager
          5. URL: 填入你集群中 Alertmanager 内部 Service 地址,例如 http://alertmanager-operated.monitoring.svc:9093
          6. 保存后,回到告警规则编辑页,将 Contact point 明确选择为 My-Alertmanager
      • 方式二:直接在 Grafana 中配置钉钉 (ActionCard 格式)
        • 如果你不想经过 Alertmanager,可以直接让 Grafana 发送钉钉:
          1. Contact points 中新建,Name 填入 DingDing-Alerts
          2. Integration 选择 DingDing
          3. URL 填入钉钉机器人的 Webhook 地址。
          4. 展开 Optional DingDing settings,将 Message Type 改为 ActionCard(支持 Markdown 渲染)。
          5. Title 建议填入:{{ if eq .Status "firing" }}🔥 发生告警{{ else }}✅ 告警恢复{{ end }}: {{ .CommonLabels.alertname }}
          6. Message 建议填入:
            **告警状态**: {{ .Status }}
            **告警摘要**: {{ .CommonAnnotations.summary }}
            **详细描述**: {{ .CommonAnnotations.description }}
            
            **告警详情**:
            {{ range .Alerts -}}
              * 实例: {{ .Labels.instance }}
              * 命名空间: {{ .Labels.namespace }}
              * 触发时间: {{ .StartsAt.Local.Format "2006-01-02 15:04:05" }}
            {{ end }}
            
          7. (重要)如果在钉钉配置了“加签”,需在下方找到并填入 Secret。保存并在规则中选用该通道。
      • 方式三:同时发送给钉钉和 Alertmanager (多重路由)
        • 如果你希望告警既发送给 Alertmanager (走邮件流程) 又直接通过 Grafana 发给钉钉,你需要创建一个复合通道:
          1. Contact points 页面点击 + New contact point
          2. Name: 填入 DingDing-AND-Alertmanager
          3. Integration: 第一项选择 Alertmanager 并填好内部 Service URL。
          4. 向下滚动,点击 + Add contact point integration 添加第二个集成。
          5. 在新出现的配置块中,选择 DingDing,并按照“方式二”中的说明填好 Webhook、Title 和 Message。
          6. 保存该 Contact point,并在你的告警规则的步骤 5 中选择它。这样 Grafana 触发告警时就会并行发送给这两处。
    • Muting, grouping and timings (静默、分组和时间控制 - 进阶选项): 展开后可以对告警发送频率进行精细控制(通常保持默认即可,若有特殊需求可参考下方说明):
      • Mute / Active timings (静默/活跃时间): 用于设置在哪些特定时间段“绝对不发”或“只在此时段发”报警。适用于固定维护窗口或仅需在工作时间监控的边缘业务。
        • 注:这里只能下拉选择预先定义好的时间范围。如果你需要新建一个时间范围,请前往 Grafana 左侧菜单的 Alerting -> Notification configuration -> Time intervals 中进行创建。
      • Override grouping (覆盖分组): 决定发生大面积故障时,告警如何合并打包发送。保持关闭(默认按文件夹和告警名分组)已足够合理。
      • Override timings (覆盖时间控制): 决定告警的发送频率。开启后可修改三个核心参数:
        • Group wait (组等待): 发现第一个告警后,等多久才发(默认 30s,用于收集同期其他告警)。
        • Group interval (组间隔): 上波告警发完,如果有新告警,等多久再发(默认 5m)。
        • Repeat interval (重发间隔): 【最常用】如果故障一直没修好,多久重新提醒你一次?默认是 4h,如果觉得太久,可以开启此项并修改为 1h30m
  6. 配置告警消息 (Configure notification message):
    • Summary: 发现异常 Pod: {{ $labels.namespace }}/{{ $labels.pod }}
    • Description: Pod {{ $labels.pod }} 处于 {{ $labels.phase }} 状态已超过 3 分钟,请及时排查。
    • Runbook URL (可选): 填入你们内部的故障处理文档链接。
    • Link dashboard and panel (可选): 绑定一个相关的监控大屏,报警时可直接点击跳转查看图表。

最后,点击右上角的 Save rule and exit 即可完成配置。


8. 在 Alertmanager 中查看与管理告警

无论告警是通过 PrometheusRule (YAML) 还是 Grafana UI 配置产生的,只要它最终被路由到了 Alertmanager,你就可以在 Alertmanager 的原生界面中集中查看和管理它们。

8.1 访问 Alertmanager 界面

请参考文档 4.3 访问 Alertmanager 报警面板 章节。通常你可以通过以下方式访问:

  • 如果配置了 Ingress:访问 http://alertmanager.aioil.top
  • 如果配置了 NodePort:访问 http://<NodeIP>:32093
  • 如果临时使用端口转发:访问 http://localhost:9093

8.2 查看正在触发的告警 (Alerts)

登录 Alertmanager 界面后,默认首页即为 Alerts 页面:

  1. 查看告警列表:这里会展示当前集群中所有处于 Firing (触发中) 状态的告警。
  2. 按标签筛选:你可以在顶部的搜索框中输入 severity="warning"alertname="Pod状态异常报警" 来过滤特定的告警。
  3. 查看告警详情:点击任意一条告警前面的 + 号展开,你可以看到这条告警携带的所有 Labels(如 namespace、pod 名称)和 Annotations(如 summary 描述信息)。
  4. 查看告警来源:点击告警详情底部的 Source 链接,可以直接跳转回 Prometheus 或 Grafana 中触发该告警的原始图表或规则页面。

8.3 告警静默管理 (Silences)

如果你在 Alerts 页面发现了一些“已知故障”(比如某个节点正在进行计划内重启,导致疯狂报警),你可以直接在 Alertmanager 中对它们进行“静默”处理。

操作步骤:

  1. 在正在触发的告警卡片右上角,点击 Silence 按钮。
  2. 界面会自动跳转到新建静默规则页面,并且已经帮你填好了匹配这条告警的 Labels。
  3. Start / End:选择静默开始和结束的时间。
    (⚠️ 注意:如果你发现无法提交,提示 Silence is not yet valid,请手动把 Start 时间往前调 1-2 分钟,这是由于浏览器和服务器时间差导致的常见问题)
  4. Creator:填入你的名字。
  5. Comment:填入静默原因,例如 “正在对 node-01 进行升级维护,预计 2 小时后恢复”
  6. 点击 Create

在静默期间,Alertmanager 虽然仍然会收到这条告警,但不会再通过钉钉/邮件发送通知。静默期结束后,如果故障依然存在,通知会自动恢复发送。


9. 彻底卸载清理

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐