Pub/Subを使いCloudBuildの実行結果をSlackに通知する。
はじめに
CloudBuild の実行完了結果をSlackへ通知した時の備忘録を書きます。
構成ファイルにSlack通知を行うステップを追加することも可能ですが、
- 複数のcloudbuildトリガーが存在する場合、それぞれの構成ファイルに同じ処理を書くのは冗長になる
- Buildと通知を分離しないと通知の変更がデプロイに影響を与えてしまう
ため構成ファイルを書き換えない方針で通知を実現できないか調査しました。
こちらの記事を見つけたので、記事に従って構築しました。
カスタマイズした点に絞って、説明を記載していきます。
環境構築に必要な項目は以下となります。
-
Cloud Build, Compute Engine, Cloud Run, Pub/Sub, and Secret Manager API が有効化されたGCP環境
有効化はこちら -
Webhook設定の済んだ Slackワークスペース
概要
- トリガーに応じてCloudBuildでデプロイが実行される
- デプロイの実行が終了する
- Pub/Sub へビルドの実行終了がPushされる
- Pub/Sub のビルドの実行終了をサブスクライブしているCloudRunがイベントを受信する
- 受信したイベントに応じてSlackへ通知を行う
注意事項としてCloudBuildで使用される Pub/Subのトピック名は cloud-builds
と固定されています。
各サービスが具体的にどのような役割を担っているかは下記の記事が分かりやすかったので、参照ください。
セットアップ
GCPの公式によってテンプレートが提供されているので、
こちらを使って構築していきます。
リポジトリはこちら
フィルターをカスタマイズ
apiVersion: cloud-build-notifiers/v1
kind: SlackNotifier
metadata:
name: example-slack-notifier
spec:
notification:
filter: true
secrets:
- name: webhook-url
value:
設定ファイルの filter プロパティでフィルター条件をカスタマイズすることができます。
カスタマイズの種類を何種類か記載します。
より詳細な情報は Slack 通知を構成する を参照してください。
- トリガーID によるフィルタリング
以下のように指定することで、指定したトリガーのみで通知を実行することが可能です。
トリガの名称ではなく、IDであることに注意してください
filter: build.build_trigger_id == trigger-id
またトリガーのIDは
gcloud beta builds triggers list |grep -E '^(id|name|---)'
で取得することが可能です。
- ステータスによるフィルタリング
Buildのステータスによってフィルタリングすることが可能です。
また in
を使って複数の状態でフィルタリングすることも可能です。
filter: build.status == Build.Status.SUCCESS && build.build_trigger_id == trigger-id
filter: build.status in [Build.Status.FAILURE, Build.Status.TIMEOUT]
- タグによるフィルタリング
build.tags
を使用することでトリガーに紐づくタグで
フィルタリングすることが可能です。
filter: tag-name in build.tags
- 変数によるフィルタリング
build.substitutions
を使うことで柔軟なフィルタを行うことが可能です。
filter: build.substitutions[substitution-variable] == substitution-value
build.substitutions["BRANCH_NAME"] == "main"
メッセージをカスタマイズ
デフォルトの通知メッセージでは味気ないことやどのトリガーが実行された結果なのか
URLをクリックして見に行かないといけないため、メッセージをカスタマイズしました。
リポジトリの中を見ると
writeMessage
関数でメッセージを作る処理をしているので、アレンジしていきます。
複数トリガがある + 複数のブランチでデプロイしているので、
トリガ名とブランチ名を通知内容に含めます。
func (s *slackNotifier) writeMessage() (*slack.WebhookMessage, error) {
+ subs := build.Substitutions
+ triggerName := ""
+if val, ok := subs["TRIGGER_NAME"]; ok {
+ triggerName = val
+}
+
+var branch string
+if val, ok := subs["BRANCH_NAME"]; ok {
+ branch = val
+}
+
+txt := fmt.Sprintf(
+ "Cloud Build でデプロイが完了しました。\n trigger: %s \n branch: %s \n status: +%s",
+ triggerName,
+ branch,
+ build.Status,
+)
---
+ atch := slack.Attachment{
+ Text: txt
ソースコードの修正が完了したら再度デプロイを行なっていきます。
デプロイ時に Buildと gcrへのpushを追加で実行します。
- IMAGE_PATH="us-east1-docker.pkg.dev/gcb-release/cloud-build-notifiers/${NOTIFIER_TYPE}:latest"
+ IMAGE_PATH="asia.gcr.io/${PROJECT_ID}/notifier:latest"
}
deploy_notifier() {
+ docker build . -t ${IMAGE_PATH} --platform linux/amd64 -f "./slack/Dockerfile"
+ docker push ${IMAGE_PATH}
gcloud run deploy "${SERVICE_NAME}" \
--image="${IMAGE_PATH}" \
--no-allow-unauthenticated \
+ --max-instances=1 \
--update-env-vars="CONFIG_PATH=${DESTINATION_CONFIG_PATH},PROJECT_ID=${PROJECT_ID}" ||
fail "failed to deploy notifier service -- check service logs for configuration error"
}
再度デプロイコマンドを実行して、準備完了です!
bash ./setup.sh slack ./slack/slack.yaml
実際に通知すると画像のようになります!
補足
ソースコードを直接変更するのはあまり良い解決策ではないと思うので、filter
と同じように
テンプレートを作って、埋め込みができるようにするというのが良い修正方法であるかなと思っています。
Issue にもあるので、トライしたい気持ちもあります。
むすびに
sweeepでは一緒に働くエンジニアを募集しています!
自動化大好き!インフラ効率化したい!技術大好き!
なエンジニアの方一緒に働きましょう!
参考
執筆にあたり以下の記事を参考にさせてもらいました。大変助かりました。
Discussion