作者:Alexander Matyushentsev
Argoproj 社区已经研究通知功能有一段时间了。我们尝试了几种不同的方法,并从早期用户那里学到了很多东西。根据我们的学习,我们提出了通知引擎的想法[1],它解决了所有 Argo 项目甚至其他项目的各种通知相关用例。
第一个通知引擎使用者是argocd-notifications[2]项目,它为 Argo CD Application CRD 和快为 Argo Rollouts 提供通知。今天,我们很高兴地宣布第一个版本的通知引擎[3](Notifications Engine)?!
通知引擎是一个基于 Golang 的库,它实现了 Kubernetes 控制器的通知功能。一流的通知支持通常是 Kubernetes 控制器的第二个想法。这在一般情况下很难解决,因为通知本质上是非常主观的。很难预测最终用户希望收到什么类型的事件通知,特别是通知应该是什么样子的。此外,有很多通知服务,所以很难决定先支持哪一个。通知引擎正试图解决这些挑战:
通知引擎提供的特性支持以下用例:
一旦将通知引擎集成到项目中,项目最终用户将获得一个强大的配置驱动机制,用于向数十个通知服务发送通知。
该引擎引入了通知触发器和模板,允许捕获重要的定制资源事件并发送完全定制的通知。触发器是一个命名条件,它监视 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
为了查看控制器的运行情况,我们仍然需要设置演示环境。不幸的是,它不适合一个博客,但这里有一些链接:
最后,运行控制器,享受 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