Apollo配置更新通知

文章目录

    • 启用方式
    • hook编写
      • 服务部署
        • 本地部署
        • 容器化部署
          • 构建镜像
    • 使用

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

启用方式

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

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

1、webhook.supported.envs

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

DEV,FAT,UAT,PRO

Apollo配置更新通知_第1张图片

2、config.release.webhook.service.url

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

http://ip:port/webhook1,http://ip:port/webhook2

Apollo配置更新通知_第2张图片

hook编写

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

以下是代码展示:

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("******* 【 PRO环境 】Apollo 配置变更通知 *******\n"+
                ">项目名: %s\n"+
                ">配置空间: %s\n"+
                ">操作人员: %s\n"+
                ">更新时间: %s\n"+
                ">更新类型: %s\n"+
                ">更新内容: %s",
                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如下

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信息,发布成功之后数据就会通知到对应的企业微信群中

Apollo配置更新通知_第3张图片

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

Apollo配置更新通知_第4张图片

你可能感兴趣的:(运维这些事儿,监控,运维开发,运维,容器,apollo)