Grafana Grafana

Provision 告警规则、联系点与通知策略

用 YAML 定义整条告警管线,使其像代码一样被审查和版本化。

15 min 中级

Grafana 告警有四个活动部件:告警规则判断何时出了问题,联系点说明通知发往何处,通知策略将告警路由到联系点,静默时段和模板则决定消息何时、以何种方式发出。这四者都可以通过 provisioning/alerting 文件夹中的 YAML 进行 provision,这使告警可审查,而不是一堆 UI 设置。本指南构建一条小型的可用管线。

被 provision 的告警资源无法在 UI 中编辑,并且导入已存在的资源会造成冲突,所以请先移除手工创建的重复项。每个文件都以 apiVersion: 1 开头。

联系点

provisioning/alerting/contact-points.yaml:

apiVersion: 1

contactPoints:
  - orgId: 1
    name: team-slack
    receivers:
      - uid: team-slack-1
        type: slack
        disableResolveMessage: false
        settings:
          url: ${SLACK_WEBHOOK_URL}
          recipient: '#alerts'

  - orgId: 1
    name: oncall-email
    receivers:
      - uid: oncall-email-1
        type: email
        settings:
          addresses: oncall@example.com

说明:

  • 每个 receiver 上的 uid 必须唯一且稳定。Grafana 用它来原地更新该 receiver。
  • type 是集成类型,例如 slack、email、webhook、pagerduty、opsgenie 或 prometheus-alertmanager。settings 下的键取决于类型,所以请查阅你所用类型的文档。
  • 密钥通过 $VAR 或 ${VAR} 来自环境变量,所以 webhook URL 永远不会存在于 Git 中。用 $$ 保留字面的美元符号。
  • 要移除某个联系点,添加 deleteContactPoints,并附上它的 orgId 和 uid。

通知策略

策略树决定哪个联系点处理哪个告警。整棵树是一个资源,并且 provision 它会覆盖所有现有策略。

provisioning/alerting/policies.yaml:

apiVersion: 1

policies:
  - orgId: 1
    receiver: team-slack            # default for anything not matched below
    group_by: ['alertname', 'namespace']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 4h
    routes:
      - receiver: oncall-email
        object_matchers:
          - ['severity', '=', 'critical']
        repeat_interval: 1h
      - receiver: team-slack
        object_matchers:
          - ['team', '=', 'platform']
        mute_time_intervals:
          - weekends
  • 顶层的 receiver 是兜底的联系点。
  • group_by 将相关的告警批量合并为一条通知。
  • group_wait、group_interval、repeat_interval 控制第一条消息多快发出、某个组多久发送一次更新,以及未解决的告警多久重复一次。
  • routes 是使用相同字段的子策略。除非设置 continue: true,否则第一个匹配的路由获胜。
  • object_matchers 是 [label, operator, value] 三元组。操作符有 =、!=、=~ 和 !~。

要将树重置为 Grafana 的默认值,请使用 resetPolicies: [1] 并带上组织 ID。

静默时段

apiVersion: 1

muteTimes:
  - orgId: 1
    name: weekends
    time_intervals:
      - weekdays: ['saturday', 'sunday']
        location: 'UTC'

times(带 start_time 和 end_time)、weekdays、months、years 和 days_of_month 可以组合使用,范围使用冒号,例如 'monday:friday'。用 deleteMuteTimes 删除。静默时段的名称和间隔不能使用变量插值。

通知模板

apiVersion: 1

templates:
  - orgId: 1
    name: slack_title
    template: |
      {{ define "slack_title" }}
        [{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}
      {{ end }}

在联系点的设置中引用模板(例如 Slack 的 title 字段),写作 {{ template "slack_title" . }}。模板的名称和内容不支持变量插值,所以请按字面书写。

告警规则

规则被组织成组,共享一个评估间隔并位于一个文件夹中。每条规则都有一个查询与表达式步骤的列表,以及一个指明由哪一步决定是否触发的 condition。

provisioning/alerting/rules.yaml:

apiVersion: 1

groups:
  - orgId: 1
    name: webapp
    folder: Applications
    interval: 1m
    rules:
      - uid: webapp-down
        title: Webapp targets down
        condition: C
        for: 5m
        noDataState: NoData
        execErrState: Error
        labels:
          severity: critical
          team: platform
        annotations:
          summary: 'No healthy webapp targets for 5 minutes'
          runbook_url: https://runbooks.example.com/webapp-down
        data:
          - refId: A
            relativeTimeRange:
              from: 600
              to: 0
            datasourceUid: prometheus
            model:
              refId: A
              expr: sum(up{job="webapp"})
              instant: true
          - refId: B
            datasourceUid: __expr__
            model:
              refId: B
              type: reduce
              expression: A
              reducer: last
              datasource:
                type: __expr__
                uid: __expr__
          - refId: C
            datasourceUid: __expr__
            model:
              refId: C
              type: threshold
              expression: B
              conditions:
                - evaluator:
                    type: lt
                    params: [1]
              datasource:
                type: __expr__
                uid: __expr__

如何阅读它:

  • 步骤 A 通过你 provision 的数据源 uid,向 Prometheus 查询过去十分钟内健康目标的数量。relativeTimeRange 以秒为单位。
  • 步骤 B 将结果 reduce 为单个值。表达式使用特殊的数据源 UID __expr__。
  • 步骤 C 是一个阈值:当值小于 1 时触发。condition: C 将它标记为决定性步骤。
  • for: 5m 要求条件持续五分钟才触发告警,以避免抖动。
  • noDataState 和 execErrState 说明当查询没有返回数据或失败时怎么办:前者可选 NoData、Alerting 或 OK,后者可选 Error、Alerting 或 OK。
  • labels 馈入通知策略树,所以 severity: critical 正是让这条告警走向上面 oncall-email 路由的原因。
  • uid(最多 40 个字符,可含字母、数字、- 和 _)必须唯一且稳定。可选地添加 dashboardUid 和 panelId,将规则链接到某个面板。
  • 文件夹: 使用一个已存在的文件夹。最简单的方式是复用你的仪表板 provider 所创建文件夹的标题。

变量插值在规则注解、relativeTimeRange、查询 model 或模板内容中不起作用,所以请把这些值写出来。

要删除某条规则,添加 deleteRules,并附上它的 orgId 和 uid:

apiVersion: 1

deleteRules:
  - orgId: 1
    uid: webapp-down

应用与验证

告警资源在启动时读取,所以更改文件之后请重启 Grafana:

docker compose restart grafana

curl -s -u admin:$GRAFANA_ADMIN_PASSWORD \
  http://localhost:3000/api/v1/provisioning/alert-rules | jq '.[] | {uid, title, folderUID}'
curl -s -u admin:$GRAFANA_ADMIN_PASSWORD \
  http://localhost:3000/api/v1/provisioning/contact-points | jq '.[].name'
curl -s -u admin:$GRAFANA_ADMIN_PASSWORD \
  http://localhost:3000/api/v1/provisioning/policies | jq .receiver

然后通过暂时降低阈值,或从联系点的 API 发送一条测试通知,来测试投递。

更快地编写规则

规则 YAML 很冗长。在一个临时实例中构建一次规则,然后通过告警 provisioning API(/api/v1/provisioning/ 下带 ?format=yaml 的 export 路由)以 provisioning 格式导出它,并带着稳定的 uid 提交结果。对于许多相似的规则,请在 CI 中从模板生成 YAML,或者使用同样提供告警规则资源的 Terraform 或 Grafana Operator 来管理。

热门指南