この記事はトレタ Advent Calendar 2022の22日目の記事です。
はじめに
こんにちは、3年連続で22日に記事を書くサーバーサイドエンジニアの @shiroemons です。
前回は、Cloud Buildでpsqldefを使用してCloud SQLにマイグレーションする方法を紹介しました。
Cloud Buildは便利ですが、結果を確認しに行かないといけないのが少々手間です。
そこで今回は、Cloud Buildの結果をSlackに通知する方法を紹介したいと思います。
今回のゴール
成功の場合の通知画面
- 成功ステータス(SUCCESS)と ✅ が表示されている
失敗の場合の通知画面
- 成功以外のステータス(FAILUREなど)と ❌ が表示されている
Slackアプリ
アプリを新規作成
専用のSlackがあるわけではないので、以下より新規作成してください。
アプリ名とアイコンは各自で設定してください。
ここでは、アプリ名を「Cloud Build 結果通知」としています。
アイコンは、アーキテクチャ図用のアイコンのライブラリ - Google Cloud PlatformのSVGとPNGのアイコンのものを設定しています。
Webhook URLを生成
- 作成したSlackアプリのIncoming Webhooksにアクセスする。
- [Add New Webhook to Workspace]ボタンをクリックする。
- 通知するチャンネルを選択する。
- [許可する]ボタンをクリックする。
- Webhook URLが生成される。
Google Cloud 側の作業
上記の資料を元に作業を行います。
必要なAPIを有効化
始める前に の[API を有効にする]ボタンから有効にできます。
Secret Manager
- Webhook URLを保存します。
- ここでは、シークレット名を
cloudbuild_slack_notifier_webhook_url
で保存しました。
- ここでは、シークレット名を
IAM
<プロジェクト番号>-compute@developer.gserviceaccount.com
に対して、- ロール
Secret Manager のシークレット アクセサー
を付与します。 - ロール
Storage オブジェクト閲覧者
を付与します。
- ロール
Google Cloud側の作業は以上です。
ローカル環境での作業
macOSを対象として記載しております。
事前準備
Google Cloud SDKをインストールする。
brew install --cask google-cloud-sdk # Homebrew のバージョンが 2.6 以前の場合 # brew cask install google-cloud-sdk
アカウント連携する。
gcloud auth login
- gcloud configの設定する。
- 対象プロジェクトに設定されているか確認します。
gcloud config list
- プロジェクトを設定する。
- 対象プロジェクトを設定します。
gcloud config set project <プロジェクトID>
- デフォルトのリージョンを設定する。
- リージョンを
asia-northeast1
(東京)に設定します。
gcloud config set run/region asia-northeast1
- リージョンを
Slack Notifier の clone
公式がGitHubで公開している GoogleCloudPlatform/cloud-build-notifiers をcloneします。
git clone git@github.com:GoogleCloudPlatform/cloud-build-notifiers.git
clone したディレクトリへ移動します。
cd cloud-build-notifiers
config ファイル(slack.yaml)の作成
exampleファイルからコピーして作成します。
cp ./slack/slack.yaml.example ./slack/slack.yaml
configファイル(slack.yaml)をカスタマイズします。
- カスタマイズの差分は、こちらです。
# Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: cloud-build-notifiers/v1 kind: SlackNotifier metadata: - name: example-slack-notifier + name: cloudbuild-slack-notifier spec: notification: - filter: build.status == Build.Status.SUCCESS + filter: build.status in [Build.Status.SUCCESS, Build.Status.FAILURE, Build.Status.INTERNAL_ERROR, Build.Status.TIMEOUT] params: buildStatus: $(build.status) + buildTriggerName: $(build.substitutions['TRIGGER_NAME']) + buildRepository: $(build.substitutions['REPO_NAME']) + buildBranch: $(build.substitutions['BRANCH_NAME']) + buildCommit: $(build.substitutions['SHORT_SHA']) delivery: webhookUrl: secretRef: webhook-url template: type: golang - uri: gs://example-gcs-bucket/slack.json + uri: gs://<プロジェクトID>-notifiers-config/slack.json secrets: - name: webhook-url - value: projects/example-project/secrets/example-slack-notifier-webhook-url/versions/latest + value: projects/<プロジェクトID>/secrets/<シークレット名>/versions/<バージョン>
- カスタマイズの内容は以下の通りです。
metadata.name
example
からcloudbuild
に変更します。
spec.notification.filter
- デフォルトのままだと成功しか通知しないため、失敗やタイムアウトも通知するように変更します。
spec.notification.params
- Slack通知時に情報が足りないのため以下の情報を追加します。
- トリガー名、リポジトリ名、ブランチ名、短いコミットハッシュ
- Slack通知時に情報が足りないのため以下の情報を追加します。
spec.notification.template.uri
- プロジェクトごとに変更が必要
- Slack Notifierのデプロイ時に自動で配置されるパスに変更します。
- ※※※注意事項: ここの設定はSlack Notifier の デプロイ後に使用する値です。デプロイ時には使用されないことに注意※※※
secrets.value
- プロジェクトごとに変更が必要
- WebhookURLを設定したSecret Managerのパスを設定します。
- バージョンは、基本的に
latest
のままで良いと思います。
Slackテンプレートファイル(slack.json) をカスタマイズ
- デフォルトのSlackテンプレートのままだと味気なく情報量も少ないのでカスタマイズします。
- 以下のslack.jsonの内容を
./slack/slack.json
に上書きする。
[ { "type": "section", "text": { "type": "mrkdwn", "text": "Cloud Build build state *{{.Params.buildStatus}}*. {{ if eq .Params.buildStatus `SUCCESS` }}✅{{ else }}❌{{ end }}" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Trigger:* {{.Params.buildTriggerName}}" } }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*ProjectId:*\n{{.Build.ProjectId}}" }, { "type": "mrkdwn", "text": "*Repository:*\n{{.Params.buildRepository}}" }, { "type": "mrkdwn", "text": "*Branch:*\n{{.Params.buildBranch}}" }, { "type": "mrkdwn", "text": "*Commit:*\n{{.Params.buildCommit}}" } ] }, { "type": "divider" }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Build Logs" }, "value": "click_me_123", "url": "{{.Build.LogUrl}}" } ] } ]
Setup シェル(setup.sh)の修正
- Cloud Storageのロケーションを設定する。
- デフォルトのままだと、マルチリージョンの
us
が設定されます。 upload_config
関数を修正し、デュアルリージョンのasia1
に設定しています。
- デフォルトのままだと、マルチリージョンの
upload_config() { # We allow this `mb` command to error since we rely on the `cp` command hard- # erroring if there's an actual problem (since `mb` fails if the bucket # already exists). - gsutil mb "${DESTINATION_BUCKET_URI}" + gsutil mb -l asia1 "${DESTINATION_BUCKET_URI}" gsutil cp "${SOURCE_CONFIG_PATH}" "${DESTINATION_CONFIG_PATH}" || fail "failed to copy config to GCS" if [ ! -z "${SOURCE_TEMPLATE_PATH}" ]; then gsutil cp "${SOURCE_TEMPLATE_PATH}" "${DESTINATION_TEMPLATE_PATH}" || fail "failed to copy template to GCS" fi }
- スケールできる最大数を設定する。
deploy_notifier
関数を修正し、最大1台までに設定しています。
deploy_notifier() {
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"
}
- サブスクリプションの有効期限を無期限に設定する。
create_pubsub_subscription() { gcloud pubsub subscriptions create "${SUBSCRIPTION_NAME}" \ --topic=cloud-builds \ --push-endpoint="${SERVICE_URL}" \ - --push-auth-service-account="${INVOKER_SA}" + --push-auth-service-account="${INVOKER_SA}" \ + --expiration-period="never" }
Slack Notifier の デプロイ
すべての設定が完了したのでsetupシェルを実行します。
./setup.sh slack ./slack/slack.yaml -t ./slack/slack.json
以下のように最後に出力されれば成功です。
+ echo '** NOTIFIER SETUP COMPLETE **' ** NOTIFIER SETUP COMPLETE **
- デプロイで実行される内容
- Cloud Storageに「
<project id>-notifiers-config
」を作成 - slack.yamlとslack.jsonを作成したCloud Storageにアップロード
- Cloud Runに「
slack-notifier
」をデプロイ - 必要なIAMの設定
- サービスアカウント「
Cloud Run Pub/Sub Invoker
」を作成 - 必要なIAMの設定
- Cloud Pub/Subトピックに「
cloud-builds
」を作成 - Cloud Pub/Subサブスクリプションに「
slack-subscription
」を作成
- Cloud Storageに「
失敗した場合は、ログやCloud Runのログを確認してください。
2回目以降の実行の場合は、作成済みのものは ERROR
と表示されますがとくに問題ありません。
動作確認
Slack Notifierのデプロイ成功後は、実際にCloud Buildを動かし、動作確認を行いましょう。
以下のような通知がSlackに届いていれば成功/完成です。
苦労したところ
Google Cloudに公式ガイドがあるのは嬉しいですね。Slack通知ようのアプリもあるのもありがたいです。
ただ既存のままだと情報量が少なくそっけなかったので、slack.jsonをカスタマイズして必要そうな情報も表示することができました。
カスタマイズを行うにあたり参照に記載したリンクからCloud BuildやSlackについて調べながら進めました。
苦労したところは、成功や失敗のステータスを絵文字(✅や❌)で表現するところです。
"Cloud Build build state *{{.Params.buildStatus}}*. {{ if eq .Params.buildStatus `SUCCESS` }}✅{{ else }}❌{{ end }}"
Go Templateの記載で解決することができました。
さいごに
今回は、Cloud Buildの結果をSlackに通知するための設定方法を紹介しました。
トレタでは、Cloud Buildを使用しているプロジェクトに今回の設定方法を共有し、 Cloud Buildの結果がSlack通知で届くように設定しています。
Cloud Buildの結果をSlack通知したいと悩んでいる方の助けになれば幸いです。
なお、トレタではエンジニアの募集を全方位で行なっております。
コロナ禍を乗り越えた飲食店の新しい姿を探求する仲間をお待ちしております。
参考
- Cloud Build
- https://cloud.google.com/build/docs/configuring-notifications/notifiers?hl=ja
- https://cloud.google.com/build/docs/configuring-notifications/configure-slack?hl=ja
- https://cloud.google.com/build/docs/api/reference/rest/v1/projects.builds?hl=ja
- https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values?hl=ja
- https://github.com/GoogleCloudPlatform/cloud-build-notifiers
- Slack