作者:Alexander Matyushentsev
Argoproj 社群已經研究通知功能有一段時間了。我們嘗試了幾種不同的方法,並從早期使用者那裡學到了很多東西。根據我們的學習,我們提出了通知引擎的想法[1],它解決了所有 Argo 專案甚至其他專案的各種通知相關用例。
第一個通知引擎使用者是argocd-notifications[2]專案,它為 Argo CD Application CRD 和快為 Argo Rollouts 提供通知。今天,我們很高興地宣佈第一個版本的通知引擎[3](Notifications Engine)!
通知引擎是什麼?
通知引擎是一個基於 Golang 的庫,它實現了 Kubernetes 控制器的通知功能。一流的通知支援通常是 Kubernetes 控制器的第二個想法。這在一般情況下很難解決,因為通知本質上是非常主觀的。很難預測終端使用者希望收到什麼型別的事件通知,特別是通知應該是什麼樣子的。此外,有很多通知服務,所以很難決定先支援哪一個。通知引擎正試圖解決這些挑戰:
-
提供一個靈活的設定驅動的觸發器和模板機制,允許 CRD 控制器管理員適應終端使用者的需求,而無需進行任何程式碼更改;
-
提供與數十個通知服務(Slack、SMTP、Telegram 等)的開箱即用的整合,還有更多的整合尚未到來;
通知引擎提供的特性支援以下用例:
-
通知使用者 Kubernetes 叢集中發生的重要事件。事件範例是降級部署;無效的證書設定;成功地完成工作等。
-
在叢集中的資源和公司外部工具之間構建自定義整合。例如,你可能在 Argo CD Application 成功部署後觸發 CI 流水線,或者在外部祕密控制器未能從 AWS secret Manager 檢索祕密時開啟 Jira 票據。
-
設定一個審計系統,用於捕獲重要事件的資訊並將其推播到持久儲存中。
特性
一旦將通知引擎整合到專案中,專案終端使用者將獲得一個強大的設定驅動機制,用於向數十個通知服務傳送通知。
通知、觸發器和模板
該引擎引入了通知觸發器和模板,允許捕獲重要的客製化資源事件並行送完全客製化的通知。觸發器是一個命名條件,它監視 Kubernetes 資源並決定是否該傳送通知,而通知模板是一個無狀態函數,用於生成通知內容。
觸發器和模板通常由控制器維護人員設定一次,並由執行控制器的管理員自定義。下面的例子演示了一個通知使用者 Argo CD 應用程式問題的觸發器:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
trigger.on-sync-status-unknown: |
- when: app.status.sync.status == 'Unknown'
send: [app-sync-status]
template.app-sync-status: |
message: |
Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.
通知服務
除了觸發器和模板之外,管理員還需要設定與支援的通知服務的整合。通知引擎開箱即用支援 Slack、MS Teams、Email、Mattermost、Telegram、Rocket Chat、OpsGenie。支援的整合列表並不僅僅以基於文字的通知結束。使用者可以利用通知引擎更新 Github 中的提交狀態,建立 Grafana 註解或設定完全自定義整合使用通用的基於 webhook 的服務。下面的例子演示了與 Slack 的整合:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
service.slack: |
token: $slack-token
---
apiVersion: v1
kind: Secret
metadata:
name: argocd-notifications-secret
stringData:
slack-token: <my-slack-token>
使用者友好的訂閱
一旦管理員設定了觸發器、模板和服務,終端使用者只需「訂閱」他們感興趣的觸發器。為了訂閱,使用者需要新增 notifications.argoproj.io/subscribe. . 註釋,並在註釋值中指定通知收件人。以下範例建立 on-sync-succeeded 觸發器的訂閱,向兩個 Slack 通道傳送通知:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2
view raw
如何整合通知引擎?
你是否對通知引擎感到興奮,並希望將其整合到你的專案中?你必須編寫一些 Golang 程式碼,但好訊息是你不需要編寫太多程式碼。通常,你必須建立一個 main.go 檔案,其中包含與 Kubernetes 通訊的樣板程式碼,以及引導通知控制器的幾行程式碼。
演示!
一個演示勝過千言萬語。在庫的情況下,演示是演示如何使用庫的教學。下面的段落解釋瞭如何為Cert-Manager[4] Certificate CRD 構建通知。完整的範例可以在通知引擎倉庫中的examples/certmanager[5]目錄中找到。
控制器
監視自定義資源和傳送通知所需的工作由通知控制器執行。製造控制器所需的工作由pkg/controller[6]和pkg/api[7]包提供。在開始實現控制器之前,我們需要編寫樣板程式碼,這些程式碼需要與 Kubernetes 叢集通訊,並通過觸發器和模板提供對 Kubernetes ConfigMap 和 Secret 的存取:
informersFactory := informers.NewSharedInformerFactoryWithOptions(
kubernetes.NewForConfigOrDie(restConfig),
time.Minute,
informers.WithNamespace(namespace))
secrets := informersFactory.Core().V1().Secrets().Informer()
configMaps := informersFactory.Core().V1().ConfigMaps().Informer()
notificationsFactory := api.NewFactory(api.Settings{
ConfigMapName: "cert-manager-notifications-cm",
SecretName: "cert-manager-notifications-secret",
InitGetVars: func(cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (api.GetVars, error) {
return func(obj map[string]interface{}, dest services.Destination) map[string]interface{} {
return map[string]interface{}{"cert": obj}
}, nil
},
}, namespace, secrets, configMaps)
下一步是編寫程式碼來範例化控制器本身:
certClient := dynamic.NewForConfigOrDie(restConfig).Resource(schema.GroupVersionResource{
Group: "cert-manager.io", Version: "v1", Resource: "certificates",
})
certsInformer := cache.NewSharedIndexInformer(&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
return certClient.List(context.Background(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
return certClient.Watch(context.Background(), metav1.ListOptions{})
},
}, &unstructured.Unstructured{}, time.Minute, cache.Indexers{})
ctrl := controller.NewController(certClient, certsInformer, notificationsFactory)
最後一步是啟動控制器:
go informersFactory.Start(context.Background().Done())
go certsInformer.Run(context.Background().Done())
if !cache.WaitForCacheSync(context.Background().Done(), secrets.HasSynced, configMaps.HasSynced, certsInformer.HasSynced) {
log.Fatalf("Failed to synchronize informers")
}
ctrl.Run(10, context.Background().Done())
我們差不多完成了!控制器已經準備好。要開始使用它,我們需要設定觸發器、模板,並設定與一些通知服務的整合。以下 YAML 將我們的通知控制器與 Slack 整合在一起,並在證書管理器成功設定任何證書時向我們傳送訊息:
apiVersion: v1
kind: ConfigMap
metadata:
name: cert-manager-notifications-cm
data:
trigger.on-cert-ready: |
- when: any(cert.status.conditions, {.reason == 'Ready' && .status == 'True'})
send: [cert-ready]
template.cert-ready: |
message: |
Certificate {{.cert.metadata.name}} is ready!
service.slack: |
token: $slack-token
為了檢視控制器的執行情況,我們仍然需要設定演示環境。不幸的是,它不適合一個部落格,但這裡有一些連結:
-
獲取 Minikube 叢集:https://minikube.sigs.k8s.io/docs/start/
-
安裝 Cert Manager:https://cert-manager.io/docs/installation/
-
設定 Slack 整合:https://github.com/argoproj/notifications-engine/blob/master/docs/services/slack.md
最後,執行控制器,享受 Slack 的通知!
下一步
除了控制器工具箱之外,通知引擎還包括故障排除工具。這些工具包括幫助建立和驗證觸發器和模板的 Prometheus 指標和 CLI。在通知引擎檔案[8]中瞭解關於這些特性的更多資訊。不要猶豫,在CNCF Slack 頻道[9]分享你的反饋,或建立 Github 問題,要求更多的整合或報告一個 bug!
參考資料
[1] 想法: https://docs.google.com/document/d/1nw0i7EAehNnjEkbpx-I3BVjfZvRgetUFUZby4iMUSWU/edit#heading=h.efmu907hcczu
[2] argocd-notifications: https://github.com/argoproj-labs/argocd-notifications
[3] 通知引擎: https://github.com/argoproj/notifications-engine
[4] Cert-Manager: https://cert-manager.io/
[5] examples/certmanager: https://github.com/argoproj/notifications-engine/tree/master/examples/certmanager
[6] pkg/controller: https://github.com/argoproj/notifications-engine/blob/master/pkg/controller
[7] pkg/api: https://github.com/argoproj/notifications-engine/blob/master/pkg/api
[8] 檔案: https://github.com/argoproj/notifications-engine/tree/master/docs
[9] CNCF Slack 頻道: https://cloud-native.slack.com/archives/C01UKS2NKK3