
开发背景:
单位在内网使用了Rancher作为容器平台,没用办法使用Rancher提供的其他告警方式,但是内网有短信告警平台,所以我准备将Rancher的告警接入内网的短信告警平台,尝试使用Rancher提供的webhook方式。
需求分析:
内网提供的告警平台只需要我们把告警信息写入数据库即可,我们需要开发一个web服务器,接收Rancher发来的Json,然后拼接告警信息,再将信息写入数据库。
代码实现:
Rancher发来的Json示例内容如下
# 此处示例为pod告警json
{
"receiver": "p-rh2r8:pag-m2xs2",
"status": "resolved",
"alerts": [ # 这里面是我们用到的东西, !:平台是在不停的重启pod的,如果勾选了已解决告警,alerts内部会有多个告警信息,包括已解决信息、告警信息,这个信息会不断的更新。
{
"status": "resolved", # 告警时pod的状态
"labels": { # pod的信息
"alert_name": "go-test", # 告警名称
"alert_type": "podNotRunning", # 告警类型
"cluster_name": "local (ID: c-qvhh4)", # 集群名称
"container_name": "go-test", # 容器名称
"group_id": "p-rh2r8:pag-m2xs2",
"logs": "Back-off pulling image \"xxx/go/app:13\"", # 告警日志
"namespace": "default", # 命名空间
"pod_name": "go-test-6574b67dd6-7vwzt", # 告警pod
"project_name": "Default (ID: c-qvhh4:p-rh2r8)", # 项目名称
"rule_id": "p-rh2r8:pag-m2xs2_par-9h4jr",
"severity": "critical",
"workload_name": "go-test" # 工作负载
},
"annotations": {},
"startsAt": "2020-05-21T10:10:00.047662184Z", # 开始时间
"endsAt": "2020-05-21T10:15:30.046352922Z", # 结束时间, 如果没有恢复,结束时间全为0
"generatorURL": ""
},
{
"status": "resolved",
"labels": {
"alert_name": "gotest",
"alert_type": "podNotRunning",
"cluster_name": "local (ID: c-qvhh4)",
"container_name": "go-test",
"group_id": "p-rh2r8:pag-m2xs2",
"logs": "Back-off pulling image \"xxx/go/app:13\"",
"namespace": "default",
"pod_name": "go-test-6574b67dd6-7vwzt",
"project_name": "Default (ID: c-qvhh4:p-rh2r8)",
"rule_id": "p-rh2r8:pag-m2xs2_par-g4klr",
"severity": "critical",
"workload_name": "go-test"
},
"annotations": {},
"startsAt": "2020-05-21T10:05:00.059679579Z",
"endsAt": "2020-05-21T10:13:30.051427628Z",
"generatorURL": ""
}
],
"groupLabels": {
"group_id": "p-rh2r8:pag-m2xs2"
},
"commonLabels": { # 同样也是告警信息
"alert_type": "podNotRunning",
"cluster_name": "local (ID: c-qvhh4)",
"container_name": "go-test",
"group_id": "p-rh2r8:pag-m2xs2",
"logs": "Back-off pulling image \"xxx/go/app:13\"",
"namespace": "default",
"pod_name": "go-test-6574b67dd6-7vwzt",
"project_name": "Default (ID: c-qvhh4:p-rh2r8)",
"severity": "critical",
"workload_name": "go-test"
},
"commonAnnotations": {},
"externalURL": "http://alertmanager-cluster-alerting-0:9093",
"version": "4",
"groupKey": "{}/{group_id=\"p-rh2r8:pag-m2xs2\"}:{group_id=\"p-rh2r8:pag-m2xs2\"}"
}
Go代码
-
main.go
package mainimport ( "RancherMSG/MsgStruct"
"RancherMSG/sql"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io/ioutil"
"log")func msg(c *gin.Context) {
# 这里的json信息我们使用结构体反序列化
# 声明一个 RancherMsg 结构体 var m MsgStruct.RancherMsg
# 从Body里面读取json
jsonData, _ := ioutil.ReadAll(c.Request.Body)
# log.Println(string(jsonData)) # 调试使用,打印源信息
# json反序列化 if err := json.Unmarshal(jsonData, &m); err != nil {
log.Println(err) return
}
# 获取 被通知人联系电话
phoneNum := c.Query("phone")
# 遍历Alerts切片,获取所有的告警信息,在不监控pod的状态下,里面信息一般只有一个。for i := 0; i < len(m.Alerts); i++ {
alerts := m.Alerts[i]
# 拼接告警信息
alertMsg := fmt.Sprintf(`
告警类型:%s
告警信息:%s
当前状态:%s
告警集群: %s
告警容器: %s
告警Pod:%s
告警负载:%s
容器命名空间:%s
开始时间:%s
结束时间:%s
`, alerts.Labels.AlertType, alerts.Labels.Logs, alerts.Status, alerts.Labels.ClusterName, alerts.Labels.ContainerName,
alerts.Labels.PodName, alerts.Labels.WorkloadName, alerts.Labels.Namespace, alerts.StartsAt, alerts.EndsAt)
# 打印拼接好的告警信息
log.Println(alertMsg, phoneNum)
# 将告警信息插入短信数据库
err := sql.ConnSql(alertMsg, phoneNum) if err != nil {
log.Println(err)
}
}
}func main() {
# 创建gin引擎
r := gin.Default()
# 设置url
r.POST("/msg", msg)
# 启动gin if err := r.Run("192.168.111.2:8080"); err != nil { return
}
}
-
msgStruct.go
package MsgStruct
#
type RancherMsg struct {
# 这里我们只保留alerts里面的信息,其他的丢弃,如果有需要可以再加上
Alerts []Alerts `json:"alerts"` }type Alerts struct {
Status string `json:"status"`
Labels Labels `json:"labels"`
Annotations Annotations `json:"annotations"`
StartsAt string `json:"startsAt"`
EndsAt string `json:"endsAt"`
GeneratorURL string `json:"generatorURL"`}type Labels struct {
AlertName string `json:"alert_name"`
AlertType string `json:"alert_type"`
ClusterName string `json:"cluster_name"`
ContainerName string `json:"container_name"`
ComponentName string `json:"component_name"`
GroupId string `json:"group_id"`
Logs string `json:"logs"`
RuleId string `json:"rule_id"`
Severity string `json:"severity"`
Namespace string `json:"namespace"`
PodName string `json:"pod_name"`
ProjectName string `json:"project_name"`
WorkloadName string `json:"workload_name"`}type Annotations struct{} -
sqlOper.go
package sqlimport ( "database/sql"
"log"
"strings")import (
_ "github.com/mattn/go-adodb")type Mssql struct {
*sql.DB
dataSource string
database string
windows bool
sa SA
}type SA struct {
user string
passwd string}func (m *Mssql) Open() (err error) { var conf []string
conf = append(conf, "Provider=SQLOLEDB")
conf = append(conf, "Data Source="+m.dataSource)
conf = append(conf, "Initial Catalog="+m.database)
conf = append(conf, "user id="+m.sa.user)
conf = append(conf, "password="+m.sa.passwd)
log.Println(strings.Join(conf, ";"))
m.DB, err = sql.Open("adodb", strings.Join(conf, ";")) if err != nil { return err
} return nil}func ConnSql(msg, mob string) (err error) {
db := Mssql{
dataSource: "数据库连接地址",
database: "数据库",
sa: SA{
user: "xxx",
passwd: "xxx",
},
} // 连接数据库
err = db.Open() if err != nil {
log.Println("sql open:", err) return err
} defer db.Close() // 执行SQL语句
stmt, err := db.Prepare("insert into USERWakeMessage (Msg, MobileNo) values (?,?)") if err != nil {
log.Println("Prepare: ", err) return err
}
rs, err := stmt.Exec(msg, mob) if err != nil {
log.Println("Exec :", err) return err
} // id, _ := rs.LastInsertId()
affect, _ := rs.RowsAffected()
log.Printf("向%s发送了%d消息", mob, affect) return nil}
配置Rancher的通知:
-
进入集群通知配置界面
-
点击添加通知
-
选择webhook通知方式,配置完成
-
制作一个坏镜像,使用Rancher启动它,然后配置告警
-
配置告警,选择需要监控的pod,选择刚刚配置的通知。
注意:
如果要使用Prometheus表达式,需要安装项目级监控。
-
测试结果
相关推荐