Argo CD 優化以及使用釘釘接收狀態消息
本文我們將介紹 Argo CD 通過 webhook 來優化應用檢測、使用 Prometheus 監控 Argo CD,已經使用釘釘來接收 Argo CD 應用狀態變化的消息通知。
webhook 配置
我們知道 Argo CD 會自動檢查到配置的應用變化,這是因為 Argo CD 會每隔三分鐘去輪詢一次 Git 存儲庫來檢測清單的變化,為了消除這種輪詢延遲,我們也可以將 API 服務端配置為接收 webhook 事件的方式,這樣就能實時獲取到 Git 存儲庫中的變化了。Argo CD 支持來著 GitHub、GitLab、Bitbucket、Bitbucket Server 和 Gogs 的 Git webhook 事件,這里我們仍然以上面的 GitLab 為例來說明如果配置 Webhook。
進入到 GitLab 項目倉庫 http://git.k8s.local/course/devops-demo-deploy 中配置 Webhooks:

配置 Webhooks
Webhook 的地址填寫 Argo CD 的 API 接口地址 http://argocd.k8s.local/api/webhook,下面的 Secret token 是可選的,建議添加上,任意定義即可。另外需要注意這里我們使用的是自簽名的 https 證書,所以需要在下方去掉 啟用SSL驗證。
然后需要將上面配置的 Secret token 添加到 Argo CD 的 Secret 配置中:
- ➜ ~ kubectl edit secret argocd-secret -n argocd
- apiVersion: v1
- kind: Secret
- metadata:
- name: argocd-secret
- namespace: argocd
- type: Opaque
- data:
- ...
- stringData:
- # gitlab webhook secret
- webhook.gitlab.secret: youdianzhishi
保存后,更改會自動生效,我們可以在 GitLab 這邊測試配置的 Webhook,查看 Argo CD 的 API 服務 Pod 日志,正常就可以收到 Push 事件了:
- ➜ ~ kubectl logs -f argocd-server-5cc96b75b4-zws2c -n argocd
- time="2021-07-08T07:15:32Z" level=info msg="finished streaming call with code OK" grpc.code=OK grpc.method=Watch grpc.service=application.ApplicationService grpc.start_time="2021-07-08T07:15:01Z" grpc.time_ms=31314.16 span.kind=server system=grpc
- time="2021-07-08T07:15:37Z" level=info msg="Received push event repo: http://git.k8s.local/course/devops-demo-deploy, revision: master, touchedHead: true"
- time="2021-07-08T07:15:37Z" level=info msg="Requested app 'devops-demo' refresh"
Metrics 指標
Argo CD 作為我們持續部署的關鍵組件,對于本身的監控也是非常有必要的,Argo CD 本身暴露了兩組 Prometheus 指標,所以我們可以很方便對接監控報警。
默認情況下 Metrics 指標通過端點 argocd-metrics:8082/metrics 獲取指標,包括:
- 應用健康狀態指標
- 應用同步狀態指標
- 應用同步歷史記錄
關于 Argo CD 的 API 服務的 API 請求和響應相關的指標(請求數、響應碼值等等...)通過端點 argocd-server-metrics:8083/metrics 獲取。
然后可以根據我們自己的需求來配置指標抓取任務,比如我們是手動維護 Prometheus 的方式,并且開啟了 endpoints 這種類型的服務自動發現,那么我們可以在幾個指標的 Service 上添加 prometheus.io/scrape: "true" 這樣的 annotation:
- ➜ ~ kubectl edit svc argocd-metrics -n argocd
- apiVersion: v1
- kind: Service
- metadata:
- annotations:
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"metrics","app.kubernetes.io/name":"argocd-metrics","app.kubernetes.io/part-of":"argocd"},"name":"argocd-metrics","namespace":"argocd"},"spec":{"ports":[{"name":"metrics","port":8082,"protocol":"TCP","targetPort":8082}],"selector":{"app.kubernetes.io/name":"argocd-application-controller"}}}
- prometheus.io/scrape: "true"
- creationTimestamp: "2021-07-03T06:16:47Z"
- labels:
- app.kubernetes.io/component: metrics
- app.kubernetes.io/name: argocd-metrics
- app.kubernetes.io/part-of: argocd
- ......
- ➜ ~ kubectl edit svc argocd-server-metrics -n argocd
- apiVersion: v1
- kind: Service
- metadata:
- annotations:
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"server","app.kubernetes.io/name":"argocd-server-metrics","app.kubernetes.io/part-of":"argocd"},"name":"argocd-server-metrics","namespace":"argocd"},"spec":{"ports":[{"name":"metrics","port":8083,"protocol":"TCP","targetPort":8083}],"selector":{"app.kubernetes.io/name":"argocd-server"}}}
- prometheus.io/scrape: "true"
- prometheus.io/port: "8083" # 指定8084端口為指標端口
- creationTimestamp: "2021-07-03T06:16:47Z"
- labels:
- app.kubernetes.io/component: server
- app.kubernetes.io/name: argocd-server-metrics
- app.kubernetes.io/part-of: argocd
- ......
- ➜ ~ kubectl edit svc argocd-repo-server -n argocd
- apiVersion: v1
- kind: Service
- metadata:
- annotations:
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/component":"repo-server","app.kubernetes.io/name":"argocd-repo-server","app.kubernetes.io/part-of":"argocd"},"name":"argocd-repo-server","namespace":"argocd"},"spec":{"ports":[{"name":"server","port":8081,"protocol":"TCP","targetPort":8081},{"name":"metrics","port":8084,"protocol":"TCP","targetPort":8084}],"selector":{"app.kubernetes.io/name":"argocd-repo-server"}}}
- prometheus.io/scrape: "true"
- prometheus.io/port: "8084" # 指定8084端口為指標端口
- creationTimestamp: "2021-07-03T06:16:47Z"
- labels:
- app.kubernetes.io/component: repo-server
- app.kubernetes.io/name: argocd-repo-server
- app.kubernetes.io/part-of: argocd
- ......
配置完成后正常就可以自動發現上面的幾個指標任務了:
argocd metrics
如果你使用的是 Prometheus Operator 方式,則可以手動創建 ServiceMonitor 對象來創建指標對象。
然后我們可以在 Grafana 中導入 Argo CD 的 Dashboard,地址:https://github.com/argoproj/argo-cd/blob/master/examples/dashboard.json
argocd grafana
消息通知
上面我們配置了 Argo CD 的監控指標,我們可以通過 AlertManager 來進行報警,但是有的時候我們可能希望將應用同步的狀態發送到指定的渠道,這樣方便我們了解部署流水線的結果,Argo CD 本身并沒有提供內置的同步狀態通知功能,但是我們可以與第三方的系統進行集成。
- ArgoCD Notifications - Argo CD 通知系統,持續監控 Argo CD 應用程序,旨在與各種通知服務集成,例如 Slack、SMTP、Telegram、Discord 等。
- Argo Kube Notifier - 通用 Kubernetes 資源控制器,允許監控任何 Kubernetes 資源并在滿足配置的規則時發送通知。
- Kube Watch - 可以向 Slack/hipchat/mattermost/flock 頻道發布通知,它監視集群中的資源變更并通過 webhook 通知它們。
我們知道 Argo CD 本身是提供 resource hook 功能的,在資源同步前、中、后提供腳本來執行相應的動作, 那么想在資源同步后獲取應用的狀態,然后根據狀態進行通知就非常簡單了,通知可以是很簡單的 curl 命令:
- PreSync: 在同步之前執行相關操作,這個一般用于比如數據庫操作等
- Sync: 同步時執行相關操作,主要用于復雜應用的編排
- PostSync: 同步之后且app狀態為health執行相關操作
- SyncFail: 同步失敗后執行相關操作,同步失敗一般不常見
但是對于 PostSync 可以發送成功的通知,但對于狀態為 Processing 的無法判斷,而且通知還是沒有辦法做到誰執行的 pipeline 誰接收通知的原則,沒有辦法很好地進行更細粒度的配置。ArgoCD Notifications 就可以來解決我們的問題,這里我們就以 ArgoCD Notifications 為例來說明如何使用釘釘來通知 Argo CD 的同步狀態通知。
首先下載 ArgoCD Notifications 官方安裝資源清單:
- ➜ ~ wget https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/stable/manifests/install.yaml
然后我們需要在釘釘群中創建一個機器人,現在的機器人安全認證有幾種方式,這里我們就選擇關鍵字的方式,配置包含 ArgoCD 關鍵字的機器人:
add dingtalk robot
然后我們需要修改 install.yaml 文件中的 argocd-notifications-cm 添加相關配置才能支持釘釘。
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: argocd-notifications-cm
- data:
- service.webhook.dingtalk: |
- url: https://oapi.dingtalk.com/robot/send?access_token=31429a8a66c8cd5beb7c4295ce592ac3221c47152085da006dd4556390d4d7e0
- headers:
- - name: Content-Type
- value: application/json
- context: |
- argocdUrl: http://argocd.k8s.local
- template.app-sync-change: |
- webhook:
- dingtalk:
- method: POST
- body: |
- {
- "msgtype": "markdown",
- "markdown": {
- "title":"ArgoCD同步狀態",
- "text": "### ArgoCD同步狀態\n> - app名稱: {{.app.metadata.name}}\n> - app同步狀態: {{ .app.status.operationState.phase}}\n> - 時間:{{.app.status.operationState.startedAt}}\n> - URL: [點擊跳轉ArgoCD]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true) \n"
- }
- }
- trigger.on-deployed: |
- - description: Application is synced and healthy. Triggered once per commit.
- oncePer: app.status.sync.revision
- send: [app-sync-change] # template names
- # trigger condition
- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'
- trigger.on-health-degraded: |
- - description: Application has degraded
- send: [app-sync-change]
- when: app.status.health.status == 'Degraded'
- trigger.on-sync-failed: |
- - description: Application syncing has failed
- send: [app-sync-change] # template names
- when: app.status.operationState.phase in ['Error', 'Failed']
- trigger.on-sync-running: |
- - description: Application is being synced
- send: [app-sync-change] # template names
- when: app.status.operationState.phase in ['Running']
- trigger.on-sync-status-unknown: |
- - description: Application status is 'Unknown'
- send: [app-sync-change] # template names
- when: app.status.sync.status == 'Unknown'
- trigger.on-sync-succeeded: |
- - description: Application syncing has succeeded
- send: [app-sync-change] # template names
- when: app.status.operationState.phase in ['Succeeded']
- subscriptions: |
- - recipients: [dingtalk] # 可能有bug,正常應該是webhook:dingtalk
- triggers: [on-sync-running, on-deployed, on-sync-failed, on-sync-succeeded]
其中 argocd-notifications-cm 中添加了一段如下所示的配置:
- subscriptions: |
- - recipients: [dingtalk]
- triggers: [on-sync-running, on-deployed, on-sync-failed, on-sync-succeeded]
這個是為定義的觸發器添加通知訂閱,正常這里的 recipients 是 webhook:dingtalk,不知道是否是因為該版本有 bug,需要去掉前綴才能正常使用。
此外還可以添加一些條件判斷,如下所示:
- subscriptions:
- # global subscription for all type of notifications
- - recipients:
- - slack:test1
- - webhook:github
- # subscription for on-sync-status-unknown trigger notifications
- - recipients:
- - slack:test2
- - email:test@gmail.com
- trigger: on-sync-status-unknown
- # global subscription restricted to applications with matching labels only
- - recipients:
- - slack:test3
- selector: test=true
然后可以根據不同的狀態來配置不同的觸發器,如下所示:
- trigger.on-sync-status-unknown: |
- - description: Application status is 'Unknown'
- send: [app-sync-change] # template names
- when: app.status.sync.status == 'Unknown'
該觸發器定義包括名稱、條件和通知模板引用:
- send:表示通知內容使用的模板名稱
- description:當前觸發器的描述信息
- when:條件表達式,如果應發送通知,則返回 true
然后下面就是配置發送的消息通知模板:
- template.app-sync-change: |
- webhook:
- dingtalk:
- method: POST
- body: |
- {
- "msgtype": "markdown",
- "markdown": {
- "title":"ArgoCD同步狀態",
- "text": "### ArgoCD同步狀態\n> - app名稱: {{.app.metadata.name}}\n> - app同步狀態: {{ .app.status.operationState.phase}}\n> - 時間:{{.app.status.operationState.startedAt}}\n> - URL: [點擊跳轉ArgoCD]({{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true) \n"
- }
- }
該模板用于生成通知內容,該模板利用 Golang 中的 html/template 包定義,允許定義通知標題和正文,可以重用,并且可以由多個觸發器引用。每個模板默認都可以訪問以下字段:
- app:保存應用程序對象
- context:是用戶定義的字符串映射,可能包含任何字符串鍵和值
- notificationType 保留通知服務類型名稱,該字段可用于有條件地呈現服務特定字段
然后記得使用釘釘機器人的 webhook 地址替換掉上面的 argocd-notifications-secret 中的 url 地址。
配置完成后直接創建整個資源清單文件:
- ➜ ~ kubectl apply -f install.yaml
- ➜ ~ kubectl get pods -n argocd
- NAME READY STATUS RESTARTS AGE
- argocd-application-controller-0 1/1 Running 0 5d4h
- argocd-dex-server-76ff776f97-ds7mm 1/1 Running 0 5d4h
- argocd-notifications-controller-5c548f8dc9-dx824 1/1 Running 0 9m22s
- argocd-redis-747b678f89-w99wf 1/1 Running 0 5d4h
- argocd-repo-server-6fc4456c89-586zl 1/1 Running 0 5d4h
- argocd-server-5cc96b75b4-zws2c 1/1 Running 0 4d22h
安裝完成后重新去修改下應用代碼觸發整個 GitOps 流水線,正常就可以在釘釘中收到如下所示的消息通知了,如果沒有正常收到消息,可以通過 argocd-notifications 的 CLI 命令進行調試:
- ➜ ~ kubectl exec -it argocd-notifications-controller-5c548f8dc9-dtq7h -n argocd -- /app/argocd-notifications template notify app-sync-change guestbook --recipient dingtalk
- DEBU[0000] Sending request: POST /robot/send?access_token=31429a8a66c8cd5beb7c4295ce592ac3221c47152085da006dd4556390d4d7e0 HTTP/1.1
- Host: oapi.dingtalk.com
- Content-Type: application/json
- {
- "msgtype": "markdown",
- "markdown": {
- "title":"ArgoCD同步狀態",
- "text": "### ArgoCD同步狀態\n> - app名稱: guestbook\n> - app同步狀態: Succeeded\n> - 時間:2021-07-03T12:53:44Z\n> - URL: [點擊跳轉ArgoCD](http://argocd.k8s.local/applications/guestbook?operation=true) \n"
- }
- } service=dingtalk
- DEBU[0000] Received response: HTTP/2.0 200 OK
- Cache-Control: no-cache
- Content-Type: application/json
- Date: Thu, 08 Jul 2021 11:45:12 GMT
- Server: Tengine
- {"errcode":0,"errmsg":"ok"} service=dingtalk
釘釘通知
關于 ArgoCD Notification 的更多使用可以參考官方文檔了解更多:https://argocd-notifications.readthedocs.io/en/stable/。