webhook


使用Webhook擴展Alertmanager(釘釘版)

在某些情況下除了Alertmanager已經內置的集中告警通知方式以外,對於不同的用戶和組織而言還需要一些自定義的告知方式支持。通過Alertmanager提供的webhook支持可以輕松實現這一類的擴展。除了用於支持額外的通知方式,webhook還可以與其他第三方系統集成實現運維自動化,或者彈性伸縮等。

在Alertmanager中可以使用如下配置定義基於webhook的告警接收器receiver。一個receiver可以對應一組webhook配置。

1
2
3
name: <string>
webhook_configs:
[ - <webhook_config>, ... ]

每一項webhook_config的具體配置格式如下:

1
2
3
4
5
6
7
8
# Whether or not to notify about resolved alerts.
[ send_resolved: <boolean> | default = true ]

# The endpoint to send HTTP POST requests to.
url: <string>

# The HTTP client's configuration.
[ http_config: <http_config> | default = global.http_config ]

send_resolved用於指定是否在告警消除時發送回執消息。url則是用於接收webhook請求的地址。http_configs則是在需要對請求進行SSL配置時使用。

當用戶定義webhook用於接收告警信息后,當告警被觸發時,Alertmanager會按照以下格式向這些url地址發送HTTP Post請求,請求內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"version": "4",
"groupKey": <string>, // key identifying the group of alerts (e.g. to deduplicate)
"status": "<resolved|firing>",
"receiver": <string>,
"groupLabels": <object>,
"commonLabels": <object>,
"commonAnnotations": <object>,
"externalURL": <string>, // backlink to the Alertmanager.
"alerts": [
{
"labels": <object>,
"annotations": <object>,
"startsAt": "<rfc3339>",
"endsAt": "<rfc3339>"
}
]
}

使用Golang創建webhook服務

首先我們嘗試使用Golang創建用於接收webhook告警通知的服務。首先創建model包,用於映射ALertmanager發送的告警信息,Alertmanager的一個通知中根據配置的group_by規則可能會包含多條告警信息Alert。創建告警通知對應的結構體Notification。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package model

import "time"

type Alert struct {
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:annotations`
StartsAt time.Time `json:"startsAt"`
EndsAt time.Time `json:"endsAt"`
}

type Notification struct {
Version string `json:"version"`
GroupKey string `json:"groupKey"`
Status string `json:"status"`
Receiver string `json:receiver`
GroupLabels map[string]string `json:groupLabels`
CommonLabels map[string]string `json:commonLabels`
CommonAnnotations map[string]string `json:commonAnnotations`
ExternalURL string `json:externalURL`
Alerts []Alert `json:alerts`
}

這里使用gin-gonic框架創建用於接收Webhook通知的Web服務。定義路由/webhook接收來自Alertmanager的POST請求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"net/http"

"github.com/gin-gonic/gin"
model "github.com/yunlzheng/alertmanaer-dingtalk-webhook/model"
)

func main() {
router := gin.Default()
router.POST("/webhook", func(c *gin.Context) {
var notification model.Notification

err := c.BindJSON(&notification)

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{"message": " successful receive alert notification message!"})

})
router.Run()
}

與釘釘集成

釘釘,阿里巴巴出品,專為中國企業打造的免費智能移動辦公平台,提供了即時通訊以及移動辦公等豐富的功能。

釘釘群機器人是釘釘群的高級擴展功能。群機器人可以將第三方服務的信息聚合到群聊中,實現自動化的信息同步。例如:通過聚合GitHub,GitLab等源碼管理服務,實現源碼更新同步;通過聚合Trello,JIRA等項目協調服務,實現項目信息同步。不僅如此,群機器人支持Webhook協議的自定義接入,支持更多可能性。這里我們將演示如果將Alertmanager運維報警提醒通過自定義機器人聚合到釘釘群。

這里將繼續擴展webhook服務,以支持將Alertmanager的告警通知轉發到釘釘平台。完整的示例代碼可以從github倉庫https://github.com/yunlzheng/alertmanaer-dingtalk-webhook中獲取。

自定義webhook群機器人

通過釘釘客戶端(如:桌面或者手機)進入到群設置后選擇“群機器人”。將顯示如下界面:

群機器人

選擇“自定義機器人”,並且按照提示填寫機器人名稱,獲取機器人webhook地址,如下所示:

獲取webhook地址

webhook機器人創建成功后,用戶就可以使用任何方式向該地址發起HTTP POST請求,即可實現向該群主發送消息。目前自定義機器人支持文本(text),連接(link),markdown三種消息類型。

例如,可以向webhook地址以POST形式發送以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"msgtype": "markdown",
"markdown": {
"title":"Prometheus告警信息",
"text": "#### 監控指標\n" +
"> 監控描述信息\n\n" +
"> ###### 告警時間 \n"
},
"at": {
"atMobiles": [
"156xxxx8827",
"189xxxx8325"
],
"isAtAll": false
}
}

可以使用curl驗證釘釘webhook是否能夠成功調用:

1
2
$ curl -l -H "Content-type: application/json" -X POST -d '{"msgtype": "markdown","markdown": {"title":"Prometheus告警信息","text": "#### 監控指標\n> 監控描述信息\n\n> ###### 告警時間 \n"},"at": {"isAtAll": false}}' https://oapi.dingtalk.com/robot/send?access_token=xxxx
{"errcode":0,"errmsg":"ok"}

調用成功后,可以在釘釘應用群消息中接收到類似於如下通知消息:

測試消息

定義轉換器將告警通知轉化為Dingtalk消息對象

這里定義結構體DingTalkMarkdown用於映射Dingtalk的消息體。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package model

type At struct {
AtMobiles []string `json:"atMobiles"`
IsAtAll bool `json:"isAtAll"`
}

type DingTalkMarkdown struct {
MsgType string `json:"msgtype"`
At *At `json:at`
Markdown *Markdown `json:"markdown"`
}

type Markdown struct {
Title string `json:"title"`
Text string `json:"text"`
}

定義轉換器將Alertmanager發送的告警通知轉換為Dingtalk的消息體。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package transformer

import (
"bytes"
"fmt"

"github.com/yunlzheng/alertmanaer-dingtalk-webhook/model"
)

// TransformToMarkdown transform alertmanager notification to dingtalk markdow message
func TransformToMarkdown(notification model.Notification) (markdown *model.DingTalkMarkdown, err error) {

groupKey := notification.GroupKey
status := notification.Status

annotations := notification.CommonAnnotations

var buffer bytes.Buffer

buffer.WriteString(fmt.Sprintf("### 通知組%s(當前狀態:%s) \n", groupKey, status))

buffer.WriteString(fmt.Sprintf("#### 告警項:\n"))

for _, alert := range notification.Alerts {
annotations := alert.Annotations
buffer.WriteString(fmt.Sprintf("##### %s\n > %s\n", annotations["summary"], annotations["description"]))
buffer.WriteString(fmt.Sprintf("\n> 開始時間:%s\n", alert.StartsAt.Format("15:04:05")))
}

markdown = &model.DingTalkMarkdown{
MsgType: "markdown",
Markdown: &model.Markdown{
Title: fmt.Sprintf("通知組:%s(當前狀態:%s)", groupKey, status),
Text: buffer.String(),
},
At: &model.At{
IsAtAll: false,
},
}

return
}
創建Dingtalk通知發送包

notifier包中使用golang的net/http包實現與Dingtalk群機器人的交互。Send方法包含兩個參數:接收到的告警通知結構體指針,以及Dingtalk群機器人的Webhook地址。

通過包transformer.TransformToMarkdown將Alertmanager告警通知與Dingtalk消息進行映射。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package notifier

import (
"bytes"
"encoding/json"
"fmt"
"net/http"

"github.com/yunlzheng/alertmanaer-dingtalk-webhook/model"
"github.com/yunlzheng/alertmanaer-dingtalk-webhook/transformer"
)

func Send(notification model.Notification, dingtalkRobot string) (err error) {

markdown, err := transformer.TransformToMarkdown(notification)

if err != nil {
return
}

data, err := json.Marshal(markdown)
if err != nil {
return
}

req, err := http.NewRequest(
"POST",
dingtalkRobot,
bytes.NewBuffer(data))

if err != nil {
return
}

req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)

if err != nil {
return
}

defer resp.Body.Close()
fmt.Println("response Status:", resp.Status)
fmt.Println("response Headers:", resp.Header)

return
}
擴展啟動函數

首先為程序添加命令行參數支持,用於在啟動時添加全局的Dingtalk群聊機器人地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"flag"
...
"github.com/yunlzheng/alertmanaer-dingtalk-webhook/notifier"
)

var (
h bool
defaultRobot string
)

func init() {
flag.BoolVar(&h, "h", false, "help")
flag.StringVar(&defaultRobot, "defaultRobot", "", "global dingtalk robot webhook")
}

func main() {

flag.Parse()

if h {
flag.Usage()
return
}

...

}

同時通過notifier包的Send方法將告警通知發送給Dingtalk群聊機器人

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {

...

err = notifier.Send(notification, defaultRobot)

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})

}

c.JSON(http.StatusOK, gin.H{"message": "send to dingtalk successful!"})
}
使用Dingtalk擴展

運行並啟動dingtalk webhook服務之后,修改Alertmanager配置文件, 為default-receiver添加webhook配置,如下所示:

1
2
3
4
5
6
receivers:
- name: default-receiver
email_configs:
- to: yunl.zheng@wise2c.com
webhook_configs:
- url: http://localhost:8080/webhook

重啟Alertmanager服務后,手動拉高虛擬機CPU使用率觸發告警條件,此時Dingtalk即可接收到相應的告警通知信息:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM