无论你是学习go的还是学习ts,欢迎加入wedm开发团队 : https://github.com/andrewbytecoder/wedm
在这里插入图片描述

WEDM 是一个免费、跨平台的 ETCD v3 客户端和图形界面工具,基于 Wails v2、Go 和 Vue 3 构建。
本项目的目标是为 Windows、Linux 和 macOS 提供一个高效、现代化的桌面应用程序,覆盖 ETCD 的所有功能。凡是你能够使用 etcdctl 完成的操作,都应该能够通过本工具轻松实现。

以一个完整的告警流程为例,从配置到具体告警的整个流程,详细剖析各个环节
整体流程的时序图如下:

Notification Channel (Webhook/Email/Slack) Alertmanager (端口: 9093) Alert Rules Engine (内部组件) Prometheus Server (端口: 9090) Node Exporter (端口: 9100) Notification Channel (Webhook/Email/Slack) Alertmanager (端口: 9093) Alert Rules Engine (内部组件) Prometheus Server (端口: 9090) Node Exporter (端口: 9100) 阶段 1: 数据采集 (Scraping) 阶段 2: 规则计算 (Evaluation) 规则示例: IF avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) < 0.9 THEN CPU > 10% 阶段 3: 告警触发与发送 (Firing) 包含: - labels (实例名, 严重等级) - annotations (详细描述) - startsAt 时间戳 alt [条件满足 (CPU > 10%)] [条件不满足] 阶段 4: 告警处理与通知 (Routing & Notify) 流程结束,等待下一个评估周期 暴露指标 (Metrics) http://node-ip:9100/metrics (包含 node_cpu_seconds_total 等) GET /metrics (每 15s) 返回原始文本数据 将采集的数据存入 TSDB 周期性评估告警规则 (例如:每 30s 执行一次) 状态变更: Pending ->> Firing 发送 POST /api/v2/alerts (JSON 格式的告警对象) 状态维持: Inactive 或 Resolved 发送 resolved 状态 (如果之前已触发) 1. 去重 (Deduplication) 2. 分组 (Grouping) 3. 抑制 (Inhibition) 4. 静默 (Silencing) 调用配置的 Receiver (例如: POST http://webhook.site/...) 返回接收确认 (200 OK)

配置

prometheus中关于告警的配置如下,主要包含两部分,一个是告警labels管理部分,主要进行labels的替换重命名过滤等操作,另外一部分是指定可用的告警器。

// AlertingConfig configures alerting and alertmanager related configs.type 
AlertingConfig struct {  
    // 告警 labels relabel  config    
    AlertRelabelConfigs []*relabel.Config `yaml:"alert_relabel_configs,omitempty"`  
    // Alertmanager configs  
    AlertmanagerConfigs AlertmanagerConfigs `yaml:"alertmanagers,omitempty"`  
}

relabel.Config

// Config is the configuration for relabeling of target label sets.type Config 
struct {  
    // A list of labels from which values are taken and concatenated  
    // with the configured separator in order.    
    SourceLabels model.LabelNames `yaml:"source_labels,flow,omitempty" json:"sourceLabels,omitempty"`  
    // Separator is the string between concatenated values from the source labels.    // 将标签的value值进行合并时,使用的分隔符  
    Separator string `yaml:"separator,omitempty" json:"separator,omitempty"`  
    // Regex against which the concatenation is matched.    
    // Default is '(.*)'.    
    Regex Regexp `yaml:"regex,omitempty" json:"regex,omitempty"`  
    // Modulus to take of the hash of concatenated values from the source labels.    
    Modulus uint64 `yaml:"modulus,omitempty" json:"modulus,omitempty"`  
    // TargetLabel is the label to which the resulting string is written in a replacement.    // Regexp interpolation is allowed for the replace action.    
    TargetLabel string `yaml:"target_label,omitempty" json:"targetLabel,omitempty"`  
    // Replacement is the regex replacement pattern to be used.    // 匹配成功则将匹配到的内容进行替换,默认为$1  
    Replacement string `yaml:"replacement,omitempty" json:"replacement,omitempty"`  
    // Action is the action to be performed for the relabeling.    
    Action Action `yaml:"action,omitempty" json:"action,omitempty"`  
}

AlertmanagerConfigs

// AlertmanagerConfigs is a slice of *AlertmanagerConfig.
type AlertmanagerConfigs []*AlertmanagerConfig

// AlertmanagerConfig configures how Alertmanagers can be discovered and communicated with.
type AlertmanagerConfig struct {
	// We cannot do proper Go type embedding below as the parser will then parse
	// values arbitrarily into the overflow maps of further-down types.

	ServiceDiscoveryConfigs discovery.Configs       `yaml:"-"`
	HTTPClientConfig        config.HTTPClientConfig `yaml:",inline"`
	SigV4Config             *sigv4.SigV4Config      `yaml:"sigv4,omitempty"`

	// The URL scheme to use when talking to Alertmanagers.
	Scheme string `yaml:"scheme,omitempty"`
	// Path prefix to add in front of the push endpoint path.
	PathPrefix string `yaml:"path_prefix,omitempty"`
	// The timeout used when sending alerts.
	Timeout model.Duration `yaml:"timeout,omitempty"`

	// The api version of Alertmanager.
	APIVersion AlertmanagerAPIVersion `yaml:"api_version"`

	// List of Alertmanager relabel configurations.
	RelabelConfigs []*relabel.Config `yaml:"relabel_configs,omitempty"`
	// Relabel alerts before sending to the specific alertmanager.
	AlertRelabelConfigs []*relabel.Config `yaml:"alert_relabel_configs,omitempty"`
}

配置示例

alerting:
  alertmanagers:
  # 静态告警配置
  - static_configs:
    # 以下填写自己的告警器地址,这里使用的是在本机启动的alertmanager,监听的端口 9093
    - targets:
      - localhost:9093
   # 可选:配置警报重标记
  alert_relabel_configs:
  # 实际告警时,有些labels可能需要过滤或者隐藏或者进行替换,这个时候就需要使用 alert_relabel_configs 
  # source_labels 指明哪些lables需要处理
    - source_labels: [instance]
      regex: '([^:]+):\d+'
      target_label: hostname
      replacement: $1

关于alertmanagers字段怎样解析的可以阅读代码:

func readConfigs(structVal reflect.Value, startField int) (Configs, error) {
	var (
		configs Configs
		targets []*targetgroup.Group
	)
	for i, n := startField, structVal.NumField(); i < n; i++ {
		field := structVal.Field(i)
		if field.Kind() != reflect.Slice {
			panic("discovery: internal error: field is not a slice")
		}
		for k := 0; k < field.Len(); k++ {
			val := field.Index(k)
			if val.IsZero() || (val.Kind() == reflect.Ptr && val.Elem().IsZero()) {
				key := configFieldNames[field.Type().Elem()]
				key = strings.TrimPrefix(key, configFieldPrefix)
				return nil, fmt.Errorf("empty or null section in %s", key)
			}
			switch c := val.Interface().(type) {
			case *targetgroup.Group:
				// Add index to the static config target groups for unique identification
				// within scrape pool.
				c.Source = strconv.Itoa(len(targets))
				// Coalesce multiple static configs into a single static config.
				targets = append(targets, c)
			case Config:
				configs = append(configs, c)
			default:
				panic("discovery: internal error: slice element is not a Config")
			}
		}
	}
	if len(targets) > 0 {
		configs = append(configs, StaticConfig(targets))
	}
	return configs, nil
}

以下是对 alert_relabel_configs 配置的详细解析

alert_relabel_configs:
  # 实际告警时,有些labels可能需要过滤或者隐藏或者进行替换,这个时候就需要使用 alert_relabel_configs 
  # source_labels 指明哪些lables需要处理
    - source_labels: [instance]
      # 使用正则表达式匹配values 
      regex: '([^:]+):\d+'
      # 将匹配的labels的key替换成 hostname
      target_label: hostname
      # 将匹配的values替换成 首个正则匹配的值, 这里就是 ([^:]+) 匹配的值
      # 如果value的值是 localhost:9100,那么这里匹配的就是 localhost
      replacement: $1
      # Action 没有指定默认是替换 replace,这里的替换是 将对应lable替换成指定内容,如果是向剔除掉对应的label可以指定Action为 labeldrop

replace只是使用新的label替换原先的label,在保留原先label存在的情况下,新增一个label

举个例子

node_cpu_seconds_total 指标的完整数据如下:

node_cpu_seconds_total{cpu="0", instance="localhost:9100", job="node_export", mode="idle"}

经过以上relable处理,告警给alertmanger的数据就会变成

node_cpu_seconds_total{cpu="0", instance="localhost:9100", hostname="localhost", job="node_export", mode="idle"}

环境搭建:

给prometheus配置个告警,当系统CPU使用率大于 10%的时候就进行告警

  • 将添加告警rules配置
    环境搭建过程中是使用docker-compose搭建的,因此这里需要将本地的告警配置文件先通过docker-compose.yml挂在到prometheus容器内部
services:
  prometheus-compose:
    image: prom/prometheus
    container_name: prometheus-compose
    volumes:
      - ./yaml/prometheus/:/prometheus/
        # 本地的告警规则放到了 ./yaml/prometheus/rules/
      - ./yaml/prometheus/rules/:/prometheus/rules/
      - ./data:/prometheus/data
    command:
      - --web.listen-address=:9800
    network_mode: host
    pid: host
    depends_on:
      - node_exporter
  • 创建alert_rules.yml并添加告警规则
groups:
  - name: host_alerts
    rules:
      # CPU 使用率警报
      - alert: HighCPUUsage
        expr: |
          100 - (
            avg by(instance) (
              rate(node_cpu_seconds_total{mode="idle"}[5m])
            ) * 100
          ) > 10
        for: 30s  # 持续30s才触发
        labels:
          severity: warning
          team: infrastructure
          alert_type: resource
        annotations:
          summary: "高CPU使用率 (实例 {{ $labels.instance }})"
          description: |
            {{ $labels.instance }} 的CPU使用率超过10%。
            当前值: {{ $value | printf "%.2f" }}%
            阈值: 10%
          dashboard: " http://localhost:3000/d/node-exporter-full "
          runbook: " https://example.com/runbooks/high-cpu-usage "
  • 在promehteus的配置字段rule_files中指定告警配置
global:
rule_files:
  - /prometheus/rules/alert_rules.yml
  • 创建alertmanager.yml配置
global:
  # 全局配置
  smtp_smarthost: 'smtp.gmail.com:587'  # 如果使用邮件通知
  smtp_from: 'alerts@example.com'
  smtp_auth_username: 'your-email@gmail.com'
  smtp_auth_password: 'your-app-password'
  smtp_require_tls: true
# 路由配置
route:
  group_by: ['alertname', 'severity', 'instance']
  group_wait: 30s      # 等待时间,收集同一组的警报
  group_interval: 5m   # 同一组警报发送间隔
  repeat_interval: 4h  # 重复警报发送间隔
  receiver: 'default-receiver'
  
  # 子路由(可根据标签路由到不同接收器)
  routes:
    - match:
        severity: critical
      receiver: 'critical-receiver'
      group_wait: 10s
      repeat_interval: 30m
    
    - match:
        severity: warning
      receiver: 'warning-receiver'
      group_wait: 1m
      repeat_interval: 2h

# 抑制规则(减少重复警报)
inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'instance']

# 接收器配置
receivers:
  # 默认接收器(Webhook 示例)
  - name: 'default-receiver'
    webhook_configs:
      - url: 'http://webhook.site/your-unique-url'  # 测试用
        send_resolved: true
    
    # 邮件通知(可选)
    email_configs:
      - to: 'admin@example.com'
        send_resolved: true
        headers:
          subject: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'
    
  # 关键警报接收器
  - name: 'critical-receiver'
    webhook_configs:
      - url: 'http://webhook.site/critical-alerts'
        send_resolved: true
    email_configs:
      - to: 'oncall-team@example.com'
        send_resolved: true

  # 警告接收器
  - name: 'warning-receiver'
    webhook_configs:
      - url: 'http://webhook.site/warning-alerts'
        send_resolved: true
  • 使用chaosblade创建CPU异常,保证CPU使用率能大于10%
./blade create cpu load --cpu-percent 30
  • 以上工作做完我们就可以启动prometheus了
    因为使用的是prometheus-compose因此启动环境很简单,只需要在docker-compose.yml文件所在的文件夹执行 docker-compose up -d 就可以

告警数据分析

告警发生时我们会在alertmanager界面上看到如下告警信息
在这里插入图片描述

我们逐个字段分析下这些信息的来源

  • alertname=“HighCPUUsage”
    alertname=“HighCPUUsage”,alertname来自告警规则 alert_rules.yml中的 groups.rules.alert字段,用来标识告警是由哪个告警规则产生的

  • instance=“localhost:9100”
    instance 是node_cpu_seconds_total指标本身自带的标签

  • severity=“warning”
    severity 来自告警规则 alert_rules.yml中的 groups.rules.labels.severity,定义告警规则时,可以指定新的labels,这些labels以及指标经过告警规则处理之后自带的labels都能被alertmanager作为告警路由组划分的依据,比如这里是按照 group_by: [‘alertname’, ‘severity’, ‘instance’] 三个字段进行告警组划分,一旦告警组划分之后就可以对这个逻辑组绑定一些共用的告警规则

  • alert_type=“resource”

alert_type 来自告警规则的配置

  • hostname=“localhost”
    hostname来自 promtheus的告警信息relabel

  • team=“infrastructure”
    来自告警器配置

对告警信息进行抓包可以看到告警上报的信息如下:
因为中文编码有问题,其中的 …就是中文注释部分

[
    {
        "annotations": {
            "dashboard": " http://localhost:3000/d/node-exporter-full ",
            "description": "localhost:9100 ...CPU...............10%...\n.........: 30.24%\n......: 10%\n",
            "runbook": " https://example.com/runbooks/high-cpu-usage ",
            "summary": "...CPU......... (...... localhost:9100)"
        },
        "endsAt": "2026-03-07T08:35:58.194Z",
        "startsAt": "2026-03-07T08:31:58.194Z",
        "generatorURL": "http://andrew:9800/graph?g0.expr=100+-+%28avg+by+%28instance%29+%28rate%28node_cpu_seconds_total%7Bmode%3D%22idle%22%7D%5B5m%5D%29%29+%2A+100%29+%3E+10&g0.tab=1",
        "labels": {
            "alert_type": "resource",
            "alertname": "HighCPUUsage",
            "hostname": "localhost",
            "instance": "localhost:9100",
            "severity": "warning",
            "team": "infrastructure"
        }
    }
]
Logo

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

更多推荐