DevOps全链路实战 | 第 13 天:告警规则与 Alertmanager:钉钉/邮件通知渠道配置(重制版)

本文为「DevOps全链路实战」系列重制版,基于 2026 年最新 kube-prometheus-stack (v0.85+) 与 Alertmanager v0.28 重新撰写,涵盖钉钉企业版 Webhook v2 签名验证、邮件 TLS 1.3 配置及告警分组与抑制策略。

K8s

引言

在 Kubernetes 生产环境中,可观测性的最后一环就是告警。Prometheus 采集的指标再多、Grafana 看板再精美,如果没有一套可靠、及时、低噪声的告警通知体系,线上故障就无法第一时间被感知。本篇是系列的第 13/19 天,我们将在前面已经部署好的 kube-prometheus-stack 基础上,完成 Alertmanager 的深度配置——包括钉钉机器人通知(带加签验证)、邮件告警通道(TLS 加密),以及告警分组、抑制、路由规则等高阶玩法。

与原版相比,本重制版重点更新了以下内容:

  • kube-prometheus-stack Helm Chart v0.85+ 的 Alertmanager 配置方式(从 Secret 管理转为 Helm values 直配)
  • 钉钉企业版 Webhook v2 新增的加签模式(timestamp + secret HMAC-SHA256),替代旧的 token-only 模式
  • Alertmanager v0.28 的 keep_firing_for 字段与 active_time_interval 调度窗口
  • 邮件通道升级至 SMTP TLS 1.3 与 STARTTLS 双向认证

核心概念

Alertmanager 架构与工作流

Alertmanager 是 Prometheus 生态中独立告警路由与通知组件,其核心工作流为:

  1. 告警接收:Prometheus Server 根据 alerting.alertmanagers 配置,将 ALERTING(已触发)的告警推送到 Alertmanager
  2. 分组(Grouping):按 group_by 指定的标签(如 alertname、cluster)将相同标签的告警合并为一条通知
  3. 抑制(Inhibition):当高优先级告警触发时,自动静默相关低优先级告警,避免告警风暴
  4. 路由(Routing):根据 routes 中定义的标签匹配规则,将告警分发到不同的 receiver
  5. 通知发送(Notify):到达 group_wait + group_interval + repeat_interval 计时条件后,触发 webhook/email/slack 等通知渠道

关键时间参数

💻 代码示例

# Alertmanager 路由参数说明

route:

group_by: ['alertname', 'cluster'] # 分组维度

group_wait: 30s # 首次告警等待时间,聚合同组告警

group_interval: 5m # 同组后续告警的间隔

repeat_interval: 4h # 相同告警重复发送间隔

# v0.28 新增:保持触发状态展示

receiver: 'webhook-default'

这三个时间参数是控制告警噪声与及时性的关键旋钮。group_wait 太短会导致告警碎片化,太长则延迟首次通知;repeat_interval 太短会造成告警骚扰,太长可能让人遗忘未解决的故障。

实战步骤

第一步:部署钉钉 Webhook 转发服务

钉钉机器人 Webhook v2 的加签模式要求请求体在发送时附带 timestamp 和 sign 参数。由于 Alertmanager 原生 webhook 只支持固定 URL + JSON body,我们需要一个轻量转发层。社区中最常用的是 dingtalk-prometheus 中间件,这里我们用 Helm 部署:

💻 代码示例

# 添加 dingtalk helm 仓库

helm repo add dingtalk https://cowboy-bebop.github.io/dingtalk-charts

helm repo update

 

# 部署钉钉转发服务

helm upgrade –install dingtalk-webhook dingtalk/dingtalk-py

–namespace monitoring

–set dingtalk.token="SEC-your-dingtalk-token"

–set dingtalk.secret="SEC-your-dingtalk-secret"

–set dingtalk.phone="13800138000,13900139000"

–set replicaCount=2

 

# 验证服务状态

kubectl get pods -n monitoring -l app.kubernetes.io/name=dingtalk-py

部署完成后,转发服务会在集群内部暴露 http://dingtalk-py.monitoring.svc.cluster.local:8765/alertmanager 端点,Alertmanager 的 webhook receiver 指向这个地址即可。

第二步:配置 Alertmanager Helm Values

在 kube-prometheus-stack v0.85+ 中,Alertmanager 的配置直接通过 Helm values 中的 alertmanager.config 字段注入,无需再手动管理 Secret:

💻 代码示例

# alertmanager-values.yaml — 基于 kube-prometheus-stack v0.85

alertmanager:

config:

global:

smtp_smarthost: 'smtp.exmail.qq.com:465'

smtp_from: 'alerts@yourcompany.com'

smtp_auth_username: 'alerts@yourcompany.com'

smtp_auth_password: 'your-smtp-password'

smtp_require_tls: false # 465端口用隐式TLS

resolve_timeout: 5m

 

templates:

– '/etc/alertmanager/templates/*.tmpl'

 

route:

group_by: ['alertname', 'cluster', 'namespace']

group_wait: 30s

group_interval: 5m

repeat_interval: 4h

receiver: 'dingtalk'

routes:

# 紧急告警 → 钉钉 + 邮件双通道

– matchers: ['severity="critical"']

receiver: 'dingtalk-and-email'

group_wait: 10s

repeat_interval: 1h

# 告警静默窗口:非工作时间降低频率

– matchers: ['severity="warning"']

receiver: 'dingtalk'

active_time_intervals:

– 'business-hours'

repeat_interval: 8h

 

# v0.28 新增:工作时间区间定义

time_intervals:

– name: 'business-hours'

time_intervals:

– weekdays: ['monday:friday']

times:

– start_time: '09:00'

end_time: '22:00'

 

inhibit_rules:

# 节点宕机时抑制该节点的容器告警

– source_matchers: ['alertname="NodeDown"']

target_matchers: ['alertname=~"PodDown|ContainerCrashLoopBackOff"']

equal: ['node']

# 集群不可达时抑制所有子告警

– source_matchers: ['alertname="APIServerDown"']

target_matchers: ['namespace="monitoring"']

equal: []

 

receivers:

– name: 'dingtalk'

webhook_configs:

– url: 'http://dingtalk-py.monitoring.svc.cluster.local:8765/alertmanager'

send_resolved: true

max_alerts: 50

 

– name: 'email'

email_configs:

– to: 'ops-team@yourcompany.com'

send_resolved: true

headers:

Subject: '【告警】{{ .CommonLabels.alertname }} – {{ .CommonLabels.cluster }}'

 

– name: 'dingtalk-and-email'

webhook_configs:

– url: 'http://dingtalk-py.monitoring.svc.cluster.local:8765/alertmanager'

send_resolved: true

email_configs:

– to: 'ops-team@yourcompany.com,oncall@yourcompany.com'

send_resolved: true

应用配置:

💻 代码示例

# 更新 Helm Release

helm upgrade –install kube-prometheus-stack prometheus/kube-prometheus-stack

–namespace monitoring

-f alertmanager-values.yaml

–version 65.x

 

# 确认 Alertmanager 配置已热加载

kubectl exec -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0

— wget -qO- localhost:9093/api/v1/status | python3 -m json.tool | grep configYaml

第三步:配置钉钉加签验证模板

钉钉 Webhook v2 的加签算法需要对 timestamp + "n" + secret 进行 HMAC-SHA256 并 Base64 编码。转发服务在发送 HTTP 请求前自动计算签名并附加到 URL query 参数中。下面是转发服务的核心签名逻辑(Python 实现):

💻 代码示例

import time

import hmac

import hashlib

import base64

import urllib.parse

import requests

 

def build_dingtalk_url(webhook_url: str, secret: str) -> str:

"""构建带加签参数的钉钉 Webhook URL"""

timestamp = str(round(time.time() * 1000))

string_to_sign = f"{timestamp}n{secret}"

hmac_code = hmac.new(

key=secret.encode("utf-8"),

msg=string_to_sign.encode("utf-8"),

digestmod=hashlib.sha256

).digest()

sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))

return f"{webhook_url}&timestamp={timestamp}&sign={sign}"

 

def send_dingtalk(alert_data: dict, webhook_url: str, secret: str) -> bool:

"""解析 Alertmanager Webhook 并发送钉钉消息"""

url = build_dingtalk_url(webhook_url, secret)

alerts = alert_data.get("alerts", [])

 

status_emoji = {"firing": "🔴", "resolved": "✅"}

title = f"[{alert_data.get('status', 'firing').upper()}] {len(alerts)} 条告警"

 

markdown_lines = [f"### {title}n"]

for alert in alerts[:20]:

labels = alert.get("labels", {})

annotations = alert.get("annotations", {})

emoji = status_emoji.get(alert.get("status", "firing"), "⚠️")

name = labels.get("alertname", "Unknown")

namespace = labels.get("namespace", "N/A")

desc = annotations.get("description", "")

summary = annotations.get("summary", "")

markdown_lines.append(f"{emoji} **{name}** ({namespace})n> {summary}n> {desc}n")

 

payload = {

"msgtype": "markdown",

"markdown": {"title": title, "text": "n".join(markdown_lines)},

}

resp = requests.post(url, json=payload, timeout=10)

return resp.json().get("errcode") == 0

第四步:编写 Prometheus 告警规则

以下告警规则覆盖了 K8s 集群最核心的告警场景,使用 PrometheusRule CRD 定义:

💻 代码示例

# prometheus-rules.yaml

apiVersion: monitoring.coreos.com/v1

kind: PrometheusRule

metadata:

name: devops-core-alerts

namespace: monitoring

labels:

prometheus: kube-prometheus-stack-prometheus

spec:

groups:

– name: k8s-node-alerts

interval: 30s

rules:

– alert: NodeDown

expr: up{job="node-exporter"} == 0

for: 3m

labels:

severity: critical

cluster: prod-cluster

annotations:

summary: "节点 {{ $labels.node }} 宕机"

description: "节点 {{ $labels.node }} ({{ $labels.instance }}) 已离线超过 3 分钟"

 

– alert: HighCPUUsage

expr: |

100 – (avg by (node) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85

for: 10m

labels:

severity: warning

cluster: prod-cluster

annotations:

summary: "节点 {{ $labels.node }} CPU 使用率过高"

description: "节点 {{ $labels.node }} CPU 使用率 {{ $value | printf "%.1f" }}% 超过阈值 85%"

 

– name: pod-alerts

interval: 30s

rules:

– alert: PodCrashLooping

expr: |

increase(kube_pod_container_status_restarts_total[15m]) > 5

for: 5m

labels:

severity: critical

annotations:

summary: "Pod {{ $labels.pod }} 频繁重启"

description: "命名空间 {{ $labels.namespace }} 中的 Pod {{ $labels.pod }} 在 15 分钟内重启 {{ $value }} 次"

 

# v0.28 新字段:keep_firing_for

– alert: PersistentVolumeSpaceLow

expr: |

kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes > 0.85

for: 5m

labels:

severity: warning

annotations:

summary: "PV {{ $labels.persistentvolumeclaim }} 空间不足"

description: "PVC 剩余空间低于 15%"

keep_firing_for: 30m

应用告警规则:

💻 代码示例

kubectl apply -f prometheus-rules.yaml

 

# 验证规则已加载

kubectl exec -n monitoring kube-prometheus-stack-prometheus-0

— wget -qO- localhost:9090/api/v1/rules | python3 -m json.tool | grep name

第五步:验证端到端告警链路

使用 Prometheus HTTP API 手动触发一条告警来验证通知链路是否通畅:

💻 代码示例

# 1. 检查 Alertmanager 中是否有告警

kubectl exec -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0

— wget -qO- localhost:9093/api/v2/alerts | python3 -m json.tool

 

# 2. 检查 Alertmanager 配置状态

kubectl exec -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0

— wget -qO- localhost:9093/api/v2/status | python3 -c "

import sys, json

data = json.load(sys.stdin)

print('Config loaded:', data['config'].get('original', '')[:80] + '…')

print('Version:', data['versionInfo']['version'])

print('Uptime:', data['uptime'])

"

 

# 3. 模拟告警:临时降低 NodeDown 的 for 时间来触发

# 或直接使用 amtool 发送测试告警

kubectl exec -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0

— amtool alert add

alertname=TestAlert severity=warning

–annotation=summary='Test Alert'

–annotation=description='End-to-end alert test'

–alertmanager.url=http://localhost:9093

 

# 4. 检查钉钉群是否收到测试告警消息

# 检查转发服务日志

kubectl logs -n monitoring -l app.kubernetes.io/name=dingtalk-py –tail=20

常见问题

问题一:钉钉消息发送失败,返回 errcode 310000

这是钉钉 Webhook v2 加签校验失败。根本原因是时间偏差:钉钉服务端要求 timestamp 与服务端时间偏差不超过 60 分钟,但实际推荐偏差在 1 分钟内。解决方法:

  1. 确认 Pod 所在节点的 NTP 时间同步正常:chronyc tracking
  2. 检查转发服务中的 secret 是否与钉钉机器人配置页完全一致
  3. 确认使用的是 HMAC-SHA256 而非 SHA1 或 MD5

问题二:告警一直不触发,但 Prometheus 中能看到指标

常见原因:for 持续时间未达到,或者 PrometheusRule 的 prometheus label 不匹配。用以下命令排查:

💻 代码示例

# 查看 Prometheus 当前加载的规则

kubectl exec -n monitoring kube-prometheus-stack-prometheus-0

— wget -qO- 'localhost:9090/api/v1/rules?type=alert'

| python3 -c "import sys,json; [print(r['name']) for r in json.load(sys.stdin)['data']['groups']]"

 

# 查看告警评估结果

kubectl exec -n monitoring kube-prometheus-stack-prometheus-0

— wget -qO- 'localhost:9090/api/v1/alerts' | python3 -m json.tool | grep -A2 state

问题三:告警风暴导致钉钉被限流

钉钉机器人默认每分钟最多发送 20 条消息。当大规模故障(如集群网络抖动)触发几十条告警时,后续消息会被丢弃。解决方法:

  1. 合理使用 group_by 将同类型告警合并
  2. 设置 inhibit_rules 让高优先级告警抑制低优先级告警
  3. 在转发服务中增加消息队列缓冲和限流逻辑
  4. 对于关键告警同时配置邮件通道作为兜底

问题四:Alertmanager 配置不生效

kube-prometheus-stack v0.85 改变了 Alertmanager 配置管理方式。如果通过 kubectl edit secret 修改了旧的 Secret,Helm 升级时会覆盖。务必通过 Helm values 的 alertmanager.config 字段管理配置,然后执行 helm upgrade 触发滚动更新。

总结

本篇重制版基于 2026 年最新版本重新梳理了 Alertmanager 的完整配置链路,覆盖了从钉钉加签 webhook 转发、邮件 TLS 通道、告警分组与抑制策略,到 PrometheusRule CRD 定义、端到端验证的完整流程。相比原版,重点更新了:

  • Alertmanager v0.28 新增的 keep_firing_for(告警恢复后继续展示 30 分钟)和 active_time_interval(工作时间调度窗口)
  • kube-prometheus-stack v0.85 的 Helm values 直配模式,替代手动 Secret 管理
  • 钉钉 Webhook v2 加签模式的完整 Python 实现
  • 更完善的告警抑制规则,避免告警风暴

一套好的告警体系的标准是:故障发生时你能在 1 分钟内收到通知,但正常运维期间你不会被噪声打扰。分组、抑制和时间窗口调度正是实现这一目标的关键工具。

下期预告

下一篇我们将进入渐进式交付的世界——第 14 天:Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义,开始将前面搭建的 CI/CD 管道升级为支持金丝雀发布的先进交付系统。

系列大纲

  1. 全链路架构总览:从代码提交到灰度发布的完整管道设计
  2. K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
  3. Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
  4. GitLab CE 自托管部署:代码仓库与项目管理平台
  5. GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
  6. GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
  7. Harbor 镜像版本管理与 Tag 策略配置
  8. Argo CD 部署与 GitOps 配置仓库创建
  9. CI 与 CD 联动:从代码提交到部署的全自动闭环
  10. SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成
  11. Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
  12. Grafana 看板搭建:K8s 标准面板与自定义业务看板
  13. 告警规则与 Alertmanager:钉钉/邮件通知渠道配置(重制版)(今天)
  14. Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
  15. 金丝雀发布实战:setWeight 流量分割与 pause 步骤
  16. AnalysisTemplate 指标分析与自动回滚机制
  17. 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
  18. 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
  19. 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签
微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容