上篇文章我们主要是针对告警路由进行了讲解,告警路由使用无疑是非常方便的,但是缺少一些告警处理人相关提醒,所以我们本篇文章讲解一下告警认领的功能实现
通过上图我们可以发现,告警主要是Alertmanager
组件管理,所以我们需要提供一个hook接收Alertmanager
的告警信息,然后对告警数据进行处理,以达到我们实现告警认领的目的
使用gin+gorm、来实现一个hook,使得我们可以处理Alertmanager
发送过来的告警数据,钉钉outgoing机制传递用户ID,使用钉钉dtmd
来自动实现回复功能
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master-50.57 Ready control-plane,master 96d v1.20.5
k8s-node-50.58 Ready <none> 96d v1.20.5
k8s-node-50.59 Ready <none> 96d v1.20.5
# kubectl get pod -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-main-0 2/2 Running 0 8d
alertmanager-main-1 2/2 Running 0 8d
alertmanager-main-2 2/2 Running 0 8d
blackbox-exporter-55c457d5fb-5m7ql 3/3 Running 0 8d
grafana-9df57cdc4-gpzsq 1/1 Running 0 8d
kube-state-metrics-56dbb74497-gpkn9 3/3 Running 0 8d
node-exporter-4wl6d 2/2 Running 0 8d
node-exporter-b4595 2/2 Running 0 8d
node-exporter-g4l99 2/2 Running 0 8d
prometheus-adapter-59df95d9f5-tnt4w 1/1 Running 0 8d
prometheus-adapter-59df95d9f5-xhz5v 1/1 Running 0 8d
prometheus-k8s-0 2/2 Running 1 8d
prometheus-k8s-1 2/2 Running 1 10m
prometheus-operator-c46b8b7c9-mg9cv 2/2 Running 0 8d
登录钉钉后台创建机器人
本篇文章机器人名称为:test
type PrometheusAlert struct {
ID uint `gorm:"primarykey" json:"id" form:"id"`
CreatedAt time.Time `gorm:"column:creation_time" json:"created_at" form:"created_at"`
UpdatedAt time.Time `gorm:"column:update_time" json:"updated_at" form:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:delete_time;index" json:"deleted_at" form:"deleted_at"`
AlertName string `gorm:"comment: '告警名称';size:500;not null" json:"alert_name" form:"alert_name"`
Instance string `gorm:"comment: '告警实例';size:500" json:"instance" form:"instance"`
Server string `gorm:"comment: '告警环境';size:64" json:"server" form:"server"`
Severity string `gorm:"comment: '告警级别';size:64" json:"severity" form:"severity"`
AlertInfo string `gorm:"comment: '告警详情';size:500" json:"alert_info" form:"alert_info"`
IsAlert bool `gorm:"comment: '是否告警';size:1;default:1" json:"is_alert" form:"is_alert"`
FirstAlertTime time.Time `gorm:"comment: '第一次告警时间'" json:"first_alert_time" form:"first_alert_time"`
EndAlertTime time.Time `gorm:"comment: '结束告警时间'" json:"end_alert_time" form:"end_alert_time"`
IsClaim bool `gorm:"comment: '是否认领';size:1;default:0" json:"is_claim" form:"is_claim"`
Pod string `gorm:"comment: 'pod名称';size:255" json:"pod" form:"pod"`
Container string `gorm:"comment: '容器名称';size:255" json:"container" form:"container"`
Namespace string `gorm:"comment: '名称空间';size:255" json:"namespace" form:"namespace"`
ClaimUsers string `gorm:"comment: '认领人';size:500" json:"claim_users" form:"claim_users"`
UID string `gorm:"comment: '告警UID';size:500;not null;unique" json:"uid" form:"uid"`
}
主要说一下UID字段含义,主要功能是对每一条告警增加一个
UID
,用于区分是否为同一条告警记录,进而绑定认领人,这里的UID
使用md5
的方式加密告警字段
func (cbd *callBackDing) CallBack(ctx *gin.Context) {
var dingBody = new(model.DingTalkCallBackBody)
err := check.ParamsCheck(ctx, &dingBody)
if err != nil {
response.ReturnContext(ctx).Failed("fail", err)
return
}
err = service.PrometheusAlert.UpdatePrometheusAlertClaimUsers(dingBody.SenderStaffId, dingBody.Text.Content)
if err != nil {
response.ReturnContext(ctx).Failed("fail", err)
return
}
response.ReturnContext(ctx).Successful("success", err)
}
func (pa *prometheusAlert) UpdatePrometheusAlertClaimUsers(userID, uid string) (err error) {
uid = strings.TrimSpace(uid)
data, err := db.PrometheusAlert.SelectPrometheusAlert(uid)
if err != nil {
return err
}
if strings.Contains(data.ClaimUsers, userID) {
//已经存在该用户了
common.TPLogger.Info("已经存在该用户了")
return nil
}
userIDs := utils.StringToSlice(data.ClaimUsers)
userIDs = append(userIDs, fmt.Sprintf("\"%s\"", userID))
fmt.Println("此时用户ID,", userIDs)
err = db.PrometheusAlert.UpdatePrometheusAlertClaimUsers(fmt.Sprintf("%s", userIDs), uid)
if err != nil {
common.TPLogger.Error("更新认领人失败", err)
return err
}
common.TPLogger.Info("更新认领人成功")
return nil
}
这里主要功能为接受钉钉的回调事件,并提取userid,发送内容(该内容不用输入,我们使用dtmd功能实现)
{
"conversationId": "cidkxS5Uphxg1sdgXkltSWi/A==", # 加密的会话ID
"atUsers": [ # 被@人的信息 dingtalkId:加密的发送者ID staffId:当前企业内部群中员工userid值。
{
"dingtalkId": "$:LWCP_v1:$+av1jFT6ZUh9e10G0DuOSS9MrDOOSiz/"
}
],
"chatbotCorpId": "xxxxxxxxxxxxxxxxxxxx", # 加密的机器人所在的企业corpId。
"chatbotUserId": "xxxxxxxxxxxxxxxxxxxxxxxxx", # 加密的机器人ID。
"msgId": "xxxxxxxxxxxxxxxxxxxxxxxx", # 加密的消息ID
"senderNick": "张行雷", # 发送者昵称
"isAdmin": false, # 是否为管理员
"senderStaffId": "xxxxxxxxxxxxxxxxxxxxxxxxx", # 企业内部群中@该机器人的成员userid。
"sessionWebhookExpiredTime": 1664276341892, # 当前会话的Webhook地址过期时间 单位ms
"createAt": 1664270941724, # 消息时间戳,单位ms
"senderCorpId": "xxxxxxxxxxxxxxxxxxxxxxxxx", # 企业内部群有的发送者当前群的企业corpId。
"conversationType": "2", # 单聊还是群聊 1:单聊 2:群聊
"senderId": "xxxxxxxxxxxxxxxxxxxxxxxxx", # 加密的发送者ID
"conversationTitle": "自动回复机器人调试", # 群聊时才有的会话标题
"isInAtList": true, # 是否再@列表中
"sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxxxxxxxxxxxxxxxxxxxxxx", # 该钉钉机器人的webhook地址
"text": {
"content": " 123" # 消息文本
},
"robotCode": "xxxxxxxxxxxxxxxxxxxxxxxxx",
"msgtype": "text" # 目前只支持text,消息类型
}
# cat alertmanager-secret.yaml
apiVersion: v1
kind: Secret
metadata:
labels:
alertmanager: main
app.kubernetes.io/component: alert-router
app.kubernetes.io/name: alertmanager
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 0.21.0
name: alertmanager-main
namespace: monitoring
stringData:
alertmanager.yaml: |-
## Alertmanager 配置文件
global:
resolve_timeout: 1m # 该参数定义了当Alertmanager持续多长时间未接收到告警后标记告警状态为resolved(已解决)
# 路由分组
route:
receiver: devops # 默认的接收器名称
group_wait: 30s # 在组内等待所配置的时间,如果同组内,30秒内出现相同报警,在一个组内发送报警。
group_interval: 1m # 如果组内内容不变化,合并为一条警报信息,5m后发送。
repeat_interval: 1m # 发送报警间隔,如果指定时间内没有修复,则重新发送报警。
group_by: [alertname,instance] # 报警分组
# 接收器指定发送人以及发送渠道
receivers:
- name: devops
webhook_configs:
- url: http://192.168.10.70:8899/api/v1/prometheus/alert
send_resolved: true
type: Opaque
# kubectl apply -f alertmanager-secret.yaml
这里的
http://192.168.10.70:8899/api/v1/prometheus/alert
是我们项目接受告警的地址
当我们点击告警认领
按钮时会自定艾特机器人,并发送一个消息(消息内容可以自定义,但是需要包含UID,主要是为了区分认领的是那一条告警)
说明:该UID是用
告警名称
,告警级别
、告警时间
、告警pod
、告警名称空间
进行md5
加密而成的字符串
当然认领可以支持多人认领
告警代码领取方式,可以添加下方二维码
告警认领功能到此已经添加完成,当然其中还有一些地方不够完善的,例如告警静默,告警指派、告警升级等功能,如果有需要后期会慢慢完善。