🐙

Argo CD のデプロイ結果を Slack へ通知させる方法

に公開

クラウドエース 北野です。
Argo CD の結果を Slack に通知する方法を紹介します。

概要

Argo CD の結果を Slack に通知するには、以下を実施します。

  • Slack アプリと通知先チャンネルの作成
  • Configmap argocd-notifications-cm に通知方法の定義
  • Application への通知設定 metadata.annotations の定義

Configmap argocd-notifications-cm の内容は次のとおりです。

cm-argocd-notification.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm

data:
  service.slack: |
    token: $slack-token

  context: |
    argocdUrl: <Argo CD URL>

  template.app-sync-succeeded: |
    slack:
      attachments: |
        [{
          "color": "#36a64f",
          "blocks": [{
            "type": "header",
            "text": {
               "type": "plain_text",
               "text": "【SUCCESS】 Argo CD {{.app.metadata.name}} Application Manifest Sync"
             }
          }]
        }]
      deliveryPolicy: Post
      groupingKey: ""
      notifyBroadcast: false
  trigger.on-sync-succeeded: |
    - description: Application syncing has succeeded
      send:
      - app-sync-succeeded
      when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded']

Application の metadata.annotations は次のとおりです。

application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: <APPLICATION NAME>
  namespace: argocd
  annotations:
    notifications.argoproj.io/subscribe.<TRIGGER NAME>.slack: <CHANNEL NAME>

spec:

はじめに

Argo CD でデプロイパイプラインを構築すると、連携されたリポジトリのコードが更新される度に自動的にデプロイが実施されます。そのため、変更を通知する機構がないと、Kubernetes や Argo CD のコンソールからでしか変更を確認できません。

そこで、この記事では、Argo CD の Application の状態の変化を Slack に通知する方法を紹介します。

Argo CD の通知機能

Argo CD は Application の状態を監視し、状態の変更を Slack やメールに通知する機能があります。この通知機能は Argo CD を Kubernetes 上にデプロイすると、作成される argocd-notifications-controller Deployment によって実行されます。
通知するにはメッセージの内容、通知条件と通知先を設定すると、Application の状態に応じてメッセージが通知されます。

通知するメッセージの内容とその方法、通知先の設定先は、項目によって異なります。それぞれの設定先は次の通りです。

  • 通知するメッセージの内容と通知条件: ConfigMap argocd-notifications-cm
  • メッセージの通知先: Application

通知するメッセージの内容と通知条件に基づいて通知する機能は、それぞれテンプレートとトリガーという機能を使い実現しています。

テンプレート

テンプレートは Go の html/template パッケージを使い実装されており、通知するメッセージの内容を定義します。次のように、ConfigMap argocd-notifications-cm の data に template で始まる内容で定義されます。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.sample-template: |
    message: |
      Application {{.app.metadata.name}} sync is {{.app.status.sync.status}}.
      Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}.

テンプレートでは、次の値を参照することができます。

  • app: Application が有する値 (Application 名、状態など)
  • context: ユーザー定義の値
  • secrets: argocd-notifications-secret に定義された値
  • serviceType: 通知の種別※
  • recipient: 通知先

※ Argo CD Notification で通知できるサービスの種類はこちらをご確認ください。

Secret からの参照方法

Argo CD Notification は、Secret argocd-notifications-secret の値を参照できます。

argocd-notifications-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  sampleWebhookToken: secret-token
type: Opaque
argocd-notifications-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  template.trigger-webhook: |
      webhook:
        sample-webhook:
          method: POST
          path: 'webhook/endpoint/with/auth'
          body: 'token={{ .secrets.sampleWebhookToken }}&variables[APP_SOURCE_PATH]={{ .app.spec.source.path }}

上の例は、webhook サービスを使って、通知するときにトークン情報を使う方法を表わしています。argocd-notifications-secret.yaml で sampleWebhookToken を定義し、argocd-notifications-cm.yaml のテンプレート定義で .secrets.sampleWebhookToken という変数でその値を参照しています。
Argo CD Notification で使う秘匿情報は、必ず Secret argocd-notifications-secret に定義してください。

トリガー

トリガーは antonmedv/expr を使い Application の状態を評価して、メッセージをいつ送付するか、通知するときにどのテンプレートを使うかを定義する機能です。次のように、ConfigMap argocd-notifications-cm の data に trigger で始まる内容で定義されます。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
data:
  trigger.on-sync-succeeded: |
    - when: app.status.sync.status == 'Succeeded'
      send: [sample-template]

when に通知されるトリガーが実行されるときの Application の状態を定義します。send にメッセージを通知するときに使うテンプレートを定義します。
expr による Application の状態の評価に使える演算子は、こちらをご確認ください。

通知先の設定

通知先の認証情報などの設定は、Configmap argocd-notifications-cmdata.service.<SERVICE KIND> に通知先のサービスの種類ごとに辞書型で定義します。例えば、Slack の場合は次のように定義します。

cm-argocd-notification.yaml
data:
  service.slack: |
    token: <SLACK APP TOKEN>

ここでの <SLACK APP TOKEN> は Slack アプリの認証トークンです。その他、Slack サービスに設定できる項目は、こちらをご確認ください。

Application のメッセージの受信

ConfigMap argocd-notifications-cm のテンプレートとトリガーを使い通知するには Application にどのトリガーを使いどこに通知するかを定義します。
Application の metadata.annotationsnotifications.argoproj.io/subscribe.<trigger>.<service>: <recipient> の形式で定義すると、状態に応じてメッセージが送信されます。以下は on-sync-succeeded トリガーを slack サービスを使って、Slack の channel チャンネルに通知させる例です。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.slack: channel

Application の状態を Slack へ通知

Argo CD でのデプロイ結果を Slack に通知するシステムを次のように構築します。

Google Cloud 上に Google Kubernetes Engine (以降 GKE と呼びます)を構築し、GKE 上に Argo CD をデプロイします。Argo CD のインターネットへの公開には、Gateway を使い公開します。また、External Secret を使い Google Cloud の Secret Manager の値を Secret argocd-notifications-secret に連携します。
Slack への通知は Slack アプリを使います。Slack アプリの認証情報を Secret Manager に登録します。

この構成を構築するために次を実施します。

  • Slack の設定
  • Google Cloud と Kubernetes でのリソース作成
  • Argo CD の設定

Slack の設定では、Slack アプリを作成し通知先のチャンネルに作成したアプリを追加します。Google Cloud と Kubernetes でのリソース作成では、Google Cloud 上に GKE を構築して、Argo CD をデプロイします。また、Slack アプリの認証情報を格納する Secret Manager を作成してデータを格納します。そして、GKE 上に External Secret を作成して、Secret argocd-notifications-secret に連携します。
最後に Argo CD の設定で、ConfigMap argocd-notifications-cm を作成して、テンプレートとトリガーを作成します。そして、通知する Application を作成して Slack に通知させます。

Slack の設定

Slack アプリを作成し、認証情報の作成と通知先のチャンネルの設定を紹介します。

まず、Slack api のページから、Argo CD への通知用のアプリを作成します。

From scratch を選び、App Name と 通知先の workspace を選択してアプリを作成します。

OAuth & Permissions から認証トークンを作成します。

ScopesBot Token ScopesAdd an OAuth Scope を選択し、Bot Token Scopes を作成します。このとき Scope に chat:write を選択して作成します。

同じページの Advanced token security via token rotationOAuth TokensInstall to <Workspace> をクリックし、Workspace にアプリケーションをインストールします。

Bot User OAuth Token を認証に使います。

続いて、通知先のチャンネルを作成します。

チャンネル詳細を開くのインテグレーションのアプリを追加するから作成したチャンネルに先のアプリケーションを追加します。



Google Cloud と Kubernetes でのリソース作成

Google Cloud で GKE、Secret Manager、Service Account の作成、Kubernetes で Argo CD、Secret Manager を作成する方法を紹介します。

Slack の認証情報を保存する Secret Manager は次のように作成します。

secret_manager.tf
resource "google_secret_manager_secret" "main" {
  secret_id = <SECRET MANAGER ID>
  project   = var.project
}

Cloud コンソールから Secret Manager にアクセスし、先程作成した Secret Manager に Slack アプリの Bot User OAuth Token を格納します。
続いて、Kubernetes から External Secret を使って Secret に連携するために Kubernetes で使うサービスアカウントを作成して、先の Secret Manager に roles/secretmanager.secretAccessor の権限を付与します。

service_account.tf
resource "google_service_account" "main" {
  account_id = <SERVICE ACCOUNT ID>

  project = var.project
}

resource "google_service_account_iam_member" "workload_identity_argocd-server" {
  service_account_id = google_service_account.main.id
  role               = "roles/iam.workloadIdentityUser"
  member             = format("serviceAccount:%s.svc.id.goog[%s/%s]", var.project, "argocd", "external-secret")
}

resource "google_secret_manager_secret_iam_member" "main" {
  secret_id = google_secret_manager_secret.main.secret_id

  project   = google_secret_manager_secret.main.project
  role      = "roles/secretmanager.secretAccessor"
  member    = google_service_account.main.member
}

GKE の構築、Argo CD のデプロイについては、こちらの記事をご確認ください。
最後に Kubernetes に External Secret を次のコマンドでインストールします。

#!/bin/bash

helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace

External Secret による Secret Manager のデータ連携

External Secret を使って、Google Cloud の Secret Manager のデータを Kubernetes の Secret argocd-notifications-secret に連携します。

まず、Kubernetes が使う Service Account を作成します。

service_account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-secret
  namespace: argocd
  annotations:
    iam.gke.io/gcp-service-account: <SERVICE ACCOUNT EMAIL>

次に ClusterSecretStore と ExternalSecret を作成して、Slack の認証情報を格納した Secret Manager を argocd-notifications-secret に連携します。

clustersecretstore.yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: argocd-css
  namespace: argocd
spec:
  provider:
    gcpsm:
      projectID: <PROJECT ID>
      auth:
        workloadIdentity:
          clusterLocation: <GKE REGION>
          clusterName: <GKE CLUSTER NAME>
          serviceAccountRef:
            name: external-secret
            namespace: argocd
es-slack-app-token.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: es-slack-app-token
  namespace: argocd
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: argocd-css
    kind: ClusterSecretStore
  target:
    name: argocd-notifications-secret
    creationPolicy: Owner
  data:
    - secretKey: slack-token
      remoteRef:
        key: <SECRET MANAGER ID>
        version: latest

Argo CD の設定

次のような条件で Slack に通知されるように ConfigMap argocd-notifications-cm に定義します。Application の状態が Succeeded のとき、app-sync-succeeded のテンプレートを使い通知させます。

テンプレート app-sync-succeeded は、【SUCCESS】 Argo CD <APPLICATION NAME> Application Manifest Sync というメッセージを Slack に通知します。
また、<APPLICATION NAME> は、Application の値を参照する app 変数を使い代入します。

Slack のメッセージを Slack の Legacy API を使い作成します。

cm-argocd-notification.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm

data:
  service.slack: |
    token: $slack-token
  template.app-sync-succeeded: |
    slack:
      attachments: |
        [{
          "color": "#36a64f",
          "blocks": [
          {
            "type": "header",
            "text": {
               "type": "plain_text",
               "text": "【SUCCESS】 Argo CD {{.app.metadata.name}} Application Manifest Sync"
             }
          }
          ]
        }]
      deliveryPolicy: Post
      groupingKey: ""
      notifyBroadcast: false
  trigger.on-sync-succeeded: |
    - description: Application syncing has succeeded
      send:
      - app-sync-succeeded
      when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded']

続いて、次のように metadata.annotations を定義して Application を作成して、作成した Slack チャンネル argocd-notification-sample に通知するようにします。

application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: helloworld
  namespace: argocd
  annotations:
    notifications.argoproj.io/subscribe.on-sync-succeeded.slack: 'argocd-notification-sample'

spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    path: <MANIFEST PATH>
    repoURL: <GITHUB REPOSITORY URL>
    targetRevision: HEAD
  syncPolicy:
    automated: null

Application を作成して、SYNC して Slack に成功メッセージを通知させてみます。


さいごに

Argo CD でのデプロイ結果を Slack に通知する方法を紹介しました。CD パイプラインはデプロイ作業を自動化するため、通知機能がないと失敗に気づけません。失敗時にメンションを飛ばすテンプレートを作成するなどして、すぐに失敗に気づけるようにしてみてください。

Discussion