TL;DR
簡(jiǎn)單來(lái)說(shuō), 我希望把 `kubectl get event`事件對(duì)接到集群外面, 直接推送到企業(yè)微信.
0x01 原理
直接使用開(kāi)源組件 kubewatch
這個(gè)組件支持 http webhook , 我們只需要另行簡(jiǎn)單開(kāi)發(fā)一個(gè) webhook接口就好了.
按官方文檔部署時(shí), 有一個(gè)坑, webhook一直無(wú)法被調(diào)用.
最后還是按自己的方式嘗試解決:
在啟動(dòng)Pod時(shí) 添加env , 指定webhook的 URL參數(shù): KW_WEBHOOK_URL
0x02 部署文件
下面這個(gè)文件可以直接部署: kubectl apply -f a.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kubewatch
data:
.kubewatch.yaml: |
resource:
deployment: true
replicationcontroller: true
replicaset: true
daemonset: true
services: true
pod: true
secret: true
configmap: true
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kubewatch
rules:
- apiGroups: ["", "apps"]
resources: ["namespaces","deployments","pods","services", "replicationcontrollers"]
verbs: ["get", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubewatch
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubewatch
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubewatch
subjects:
- kind: ServiceAccount
name: kubewatch
namespace: default
---
apiVersion: v1
kind: Pod
metadata:
name: kubewatch
namespace: default
spec:
serviceAccountName: kubewatch
containers:
- image: bitnami/kubewatch
imagePullPolicy: Always
name: kubewatch
volumeMounts:
- name: config-volume
mountPath: /root
env:
- name: KW_WEBHOOK_URL
value: "http://10.10.10.10:8080"
restartPolicy: Always
volumes:
- name: config-volume
configMap:
name: kubewatch
0x03 Webhook數(shù)據(jù)結(jié)構(gòu)
查看源碼發(fā)現(xiàn)調(diào)用webhook時(shí), 會(huì)發(fā)起一個(gè)post請(qǐng)求, body 為 json 字符串
下面是go語(yǔ)言的處理實(shí)現(xiàn):
import (
"fmt"
"github.com/gin-gonic/gin"
"os"
"time"
)
// WebhookMessage for messages
type WebhookMessage struct {
EventMeta EventMeta `json:"eventmeta"`
Text string `json:"text"`
Time time.Time `json:"time"`
}
// EventMeta containes the meta data about the event occurred
type EventMeta struct {
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace"`
Reason string `json:"reason"`
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var body WebhookMessage
if c.BindJSON(&body) != nil {
c.JSON(200, gin.H{"err": "invalid param"})
return
}
// 發(fā)送微信消息: SendTextMessage(body.ToWeChatString())
c.JSON(200, gin.H{"reason": body.EventMeta.Reason})
})
r.Run(":8080")
}
關(guān)于微信發(fā)消息, 自行baidu, 不再贅述.