ArgoCD Resource Hooksを用いてsyncの完了の通知をSlackへ送信する

こんにちは、スタディサプリ ENGLISH SRE グループの中田です。現在アルバイトとしてチームに所属しています。

タイトルの通りですが、この記事ではArgoCD Resource Hooksを用いたArgoCDのsync通知をslackで受け取る方法をご紹介します。

前回の木村の記事1)Amazon EKSでのArgoCDを使ったGitOps CDで詳しい紹介がなされていますが、現在スタディサプリ ENGLISHではArgoCDを用いたCDのフローを構築しています。

現状sync完了のSlack通知を用意しておらず、ArgoCDのダッシュボードを見に行く必要があり、syncが終わっているのかわからない、syncが失敗していてもすぐに気がつくことができないといった問題がありました。

方法

syncの終了やsyncの失敗はArgoCD Resource Hooksを用いて検知することができます。

ArgoCD Resource Hooksは、PreSync(syncの実行前)やPostSync(sync完了)、SyncFail(sync失敗)などのsyncに関するイベントを検知して、KubernetesのJobを実行することができる機能です。Resource Hooksの公式の例としてもSlackへの通知を送るサンプルが記載されています。

以下のように、/metadata/annotationsargocd.argoproj.io/hookを指定することでspec以下に指定するJobの実行が特定のタイミングで行われます。

apiVersion: batch/v1
kind: Job
metadata:
  name: argotoslack-success-
  annotations:
    argocd.argoproj.io/hook: PostSync

これによってKubernetesのJobの実行が可能になります。

今回は、自前でGoで実装を行った通知用のアプリケーションを載せたコンテナを実行します。
実行されるコンテナでは、ArgoCDのApplication Controllerが管理している、Application CRDを利用してArgoCDのリソースの状態を取得しています。
現在syncされた(もしくはsyncに失敗した)リソースのrevisionを取得することや、今までのsyncの履歴なども取得することができます。そのためリソースの状態に応じたかなり自由度の高い動作をさせることが可能です。

今回はrevisionからGitHubAPIを通してAuthorを取得し、SlackAPIを通してAuthorに対するメンションを行うという流れで通知を行いました。

  1. Application CRDから「現在sync完了/失敗したrevision」を取得する
  2. GitHubAPIから1で取得したrevisionのcommitを取得し、authorを取得
  3. SlackAPIを通してuser情報の取得(メンションのためにuserIDが必要なため)
  4. SlackAPIを通してauthorにメンションを付けつつ通知を行う

また、1で一緒に過去のrevisionの取得も行い、現在のrevisionと過去のrevisionが同じ場合はArgoCDから手動で誰かがsyncをかけたと考えられるのでメンションを付けない、等の細かい点で通知の出し分けを行いました。

Kustomize/ArgoCDにおけるgenerateNameの使用に関して

全てのリソースにおいて、ArgoCD Resource Hooksを用いてSlack通知などの同一の動作を行わせたい場合、同一のyamlを利用するとnamespace内でリソースの名前のコンフリクトが発生する原因となります。

通常だとgenerateNameを扱いたくなるケースですが、Kustomizeは2020/11/13段階でgenerateNameの使用に対応していません。

そのため上記のissueにも記載がありますが2)https://github.com/argoproj/argo-cd/issues/1639#issuecomment-494999921、以下のようにworkaroundを行うことでgenerateNameを使用することができます。

# kustomization.yaml
---
resources:
- job.yaml
patchesJson6902:
- path: patches/job-generate-name.yaml
  target:
    group: batch
    version: v1
    kind: Job
    name: foo
# job.yaml
---
apiVersion: batch/v1
kind: Job
metadata:
  name: foo
spec: ...
# patches/job-generate-name.yaml
---
- op: move
  from: /metadata/name
  path: /metadata/generateName

しかし、それよりも根本的な問題として2020/11/13現在、ArgoCDにおいてgenerateNameを使用しても全てに同じsuffixがついてしまう問題が存在します。以下のPRにて修正されていますが、まだリリースには含まれていません。

そのため、generateNameの利用を諦め、以下のようにpatchesJson6092を利用して、/metadata/name に対して、namespace内でコンフリクトしない名前にreplaceすると言った処理を行いました。

- op: replace
  path: /metadata/name
  value: api1-argotoslack-success

終わりに

ArgoCD Resource HooksとArgoCD Application CRDを組み合わせることでかなり柔軟な通知の実現を行うことができました。Application CRDからは他のリソースの状態も確認することができるなど他にも多くの応用性がありそうです。

今回は通知の目的に使用したArgoCD Resource HooksもSyncに関する任意のタイミングでJobを走らせることができるので通知以外の目的にも勿論用いることができます。実際スタディサプリENGLISHではこれまた木村の記事にあるようにDB migrationの実行などにも利用しています。

これらの利用を検討する人の参考になれば嬉しいです。ここまで読んでくださりありがとうございました。