Apollo配置更新通知

文章目录

⚡️: 应领导要求想要把 Apollo 配置变更信息更新到企业微信群中,线上出现异常可根据变更时间,快速反应是否是配置变更导致异常

启用方式

🌛: 前提有一个可正常使用的Apollo服务

配置项统一存储在ApolloPortalDB.ServerConfig表中,也可以通过管理员工具 - 系统参数页面进行配置,修改完一分钟实时生效。

1、webhook.supported.envs

开启 webhook 的环境列表,多个环境以英文逗号分隔,如

复制代码
DEV,FAT,UAT,PRO

2、config.release.webhook.service.url

webhook 通知的 url 地址,需要接收 HTTP POST 请求。如有多个地址,以英文逗号分隔,如

shell 复制代码
http://ip:port/webhook1,http://ip:port/webhook2

hook编写

🏴: 这里使用的 golang 进行hook编写,拿到信息之后数据格式以 MakeDown 形式发送到企业微信小机器人上,key 根据实际替换

以下是代码展示:

go 复制代码
package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io"
        "log"
        "net/http"
        "time"
)

const (
        weChatWebhookURL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx-xxx-xxx-xxx"    #
)

type ApolloChange struct {
        AppID          string `json:"appId"`
        NamespaceName  string `json:"namespaceName"`
        Operator       string `json:"operator"`
        ReleaseComment string `json:"releaseComment"`
        Operation      int64  `json:"operation"`
        Time           string `json:"time"`
}

const (
        OperatorNormalRelease  = "0"
        OperatorConfigRollback = "1"
        OperatorGrayRelease    = "2"
        OperatorFullRelease    = "3"
)

func main() {
        fmt.Println("**** 开启apollo配置监听 ****")
        http.HandleFunc("/apollo/webhook", HandleWarning)
        if err := http.ListenAndServe(":8080", nil); err != nil {
                log.Printf("Error listening HTTP: %s", err.Error())
        }
}

func HandleWarning(w http.ResponseWriter, r *http.Request) {
        time.Sleep(time.Second)
        body, err := io.ReadAll(r.Body)
        if err != nil {
                http.Error(w, "Error reading HTTP request", http.StatusBadRequest)
                log.Printf("Error reading HTTP request: %s", err.Error())
                return
        }

        var change ApolloChange
        if err := json.Unmarshal(body, &change); err != nil {
                http.Error(w, "Error parsing JSON", http.StatusBadRequest)
                log.Printf("Error parsing JSON: %s", err.Error())
                return
        }

        apolloType := getApolloType(change.Operator)
        change.Time = time.Now().Format("2006-01-02 15:04:05.000")

        message := fmt.Sprintf("******* <font color=\"info\">【 PRO环境 】Apollo 配置变更通知</font> *******\n"+
                ">项目名: <font color=\"comment\">%s</font>\n"+
                ">配置空间: <font color=\"comment\">%s</font>\n"+
                ">操作人员: <font color=\"comment\">%s</font>\n"+
                ">更新时间: <font color=\"comment\">%s</font>\n"+
                ">更新类型: <font color=\"comment\">%s</font>\n"+
                ">更新内容: <font color=\"comment\">%s</font>",
                change.AppID, change.NamespaceName, change.Operator, change.Time, apolloType, change.ReleaseComment)

        fmt.Println(message)

        payload, err := json.Marshal(map[string]interface{}{
                "msgtype": "markdown",
                "markdown": map[string]interface{}{
                        "content": message,
                },
        })
        if err != nil {
                http.Error(w, "Error creating JSON payload", http.StatusInternalServerError)
                log.Printf("Error creating JSON payload: %s", err.Error())
                return
        }

        resp, err := http.Post(weChatWebhookURL, "application/json", bytes.NewBuffer(payload))
        if err != nil {
                http.Error(w, "Error sending HTTP request", http.StatusInternalServerError)
                log.Printf("Error sending HTTP request: %s", err.Error())
                return
        }
        defer resp.Body.Close()

        if resp.StatusCode == http.StatusOK {
                fmt.Println("Message sent successfully!")
        } else {
                fmt.Println("Error sending message. Status code:", resp.StatusCode)
        }
}

func getApolloType(operator string) string {
        switch operator {
        case OperatorNormalRelease:
                return "正常发布"
        case OperatorConfigRollback:
                return "配置回滚"
        case OperatorGrayRelease:
                return "灰度发布"
        case OperatorFullRelease:
                return "全量发布"
        default:
                return "正常发布"
        }
}

服务部署

本地部署

最简单直接跑在宿主机上,详细操作就不讲解了

容器化部署

构建镜像

Dockerfile如下

dockerfile 复制代码
FROM golang:1.21.1-alpine3.18 AS builder

COPY . /src
WORKDIR /src

RUN GOPROXY=https://goproxy.cn go build   -o bin/apollo-webhook

FROM alpine:3.18.3

COPY --from=builder /src/bin /app

WORKDIR /app

# 同步时区
RUN apk --update add tzdata && \
	cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
	echo "Asia/Shanghai" > /etc/timezone && apk del tzdata && \
	rm -rf /var/cache/apk/*

EXPOSE 8080

CMD ["./apollo-webhook"]

构建好镜像之后直接使用就好了,可根据自己的方式部署好,把地址 正确填写到 Apollo 的config.release.webhook.service.url

使用

在Apollo更新配置,点击发布时填写对应的Comment信息,发布成功之后数据就会通知到对应的企业微信群中

样例展示,在企业微信群中能够看到以下内容

相关推荐
EMTime4 小时前
Docker运行OpenWRT
运维·docker·容器
lolo大魔王5 小时前
Linux 文件系统超全面详解(原理、结构、挂载、分区、inode、日志、管理命令)
linux·运维·服务器
zyl837217 小时前
Docker 使用手册
运维·docker·容器
古月方枘Fry8 小时前
MGRE实验
运维·服务器
stolentime8 小时前
FreeDomain 本地开发环境快速搭建指南
运维·服务器·网络
bush49 小时前
嵌入式linux学习记录四
linux·运维·学习
maomao大哥闯天下10 小时前
K8s如何实现滚动更新、健康检查与探测机制
docker·容器·kubernetes
lihao lihao11 小时前
软硬链接
linux·运维·服务器
TOWE technology11 小时前
智能安防监控系统如何做好防雷?——视频信号SPD综合应用方案解析
运维·服务器·防雷产品·信号保护·信号防雷·spd
楼田莉子11 小时前
Docker学习:Docker介绍及其架构介绍
运维·后端·学习·docker·容器·架构