独自の Notifier の作成

Cloud Build は、選択したチャネルに通知を送信することで、ビルド ステータスの更新を通知します。Cloud Build によって管理される通知機能(SlackSMTP など)に加え、提供されたライブラリを cloud-build-notifiers リポジトリで使用して、独自の Notifier を作成することもできます。

このページでは、独自の Notifier の作成方法について説明します。

始める前に

  • Cloud Build, Cloud Run, Pub/Sub, and Secret Manager API を有効にします。

    API を有効にする

  • Go プログラミング言語をインストールします。

  • Google Cloud CLI をインストールする

設定

  1. マシンでターミナル ウィンドウを開きます。

  2. cloud-build-notifiers リポジトリのクローンを作成し、そのリポジトリに移動します。

      git clone https://github.com/GoogleCloudPlatform/cloud-build-notifiers.git && cd cloud-build-notifiers
    
  3. 独自の Notifier 用のディレクトリを追加して、そのディレクトリに移動します。DIRECTORY_NAME はディレクトリの名前です。

      mkdir DIRECTORY_NAME && cd DIRECTORY_NAME
    
  4. 新しいディレクトリで Go モジュールを初期化します。DIRECTORY_NAME は新しいディレクトリの名前です。

      go mod init github.com/GoogleCloudPlatform/cloud-build-notifiers/DIRECTORY_NAME
    

    これで、ディレクトリに go.mod ファイルが表示されます。

  5. 次の行を go.mod ファイルに追加して、最新バージョンの Notifier を使用していることを確認します。

     replace github.com/GoogleCloudPlatform/cloud-build-notifiers/lib/notifiers => ../
    

これで依存関係がセットアップされ、独自の Notifier を作成する準備ができました。

独自の Notifier の作成

cloud-build-notifiers には lib/notifiers ディレクトリが含まれています。lib/notifiers ディレクトリには notifier.go という名前のファイルがあります。このファイルには、独自の Notifier を作成するために使用できるフレームワークが含まれています。

メインファイル内に Notifier を作成するには、2 つのメソッドを定義する必要があります。

  1. 新しいディレクトリに、main.go という名前のファイルを作成します。

  2. main.go で、Notifier ライブラリ フレームワークとその他の依存関係をインポートします。

    package main
    
    import (
    	"context"
    	"fmt"
    
    	cbpb "cloud.google.com/go/cloudbuild/apiv1/v2/cloudbuildpb"
    	"github.com/GoogleCloudPlatform/cloud-build-notifiers/lib/notifiers"
    	log "github.com/golang/glog"
    	"google.golang.org/protobuf/encoding/prototext"
    )
    
  3. Notifier のメイン メソッドを定義します。この例では、logger は Notifier の名前です。

    func main() {
    	if err := notifiers.Main(new(logger)); err != nil {
    		log.Fatalf("fatal error: %v", err)
    	}
    }
    

    main メソッドは、notifier.go ファイルで定義された Main メソッドを使用します。これは、Notifier バイナリの設定に使用されます。

  4. インターフェースの変数を定義する Notifier の構造体を定義します。この例では、logger は Notifier の名前です。例:

    type logger struct {
    	filter notifiers.EventFilter
    }
    

次に、Notifier 機能を追加します。この Notifier インターフェースは、以下の 2 つのメソッドで定義されます。

  • SetUp: SetUp メソッドは構成を受け入れ、シークレットを取得して、指定されたフィルタを構成から pull し、通知の送信に使用できる Common Expression Language 述語として格納します。CEL の詳細については、cel-spec リポジトリをご覧ください。
  • SendNotification: SendNotification メソッドは、目的のチャンネルまたはサービスに通知を送信するために使用されます。

    Notifier の定義は、notifier.goGo のドキュメントで確認できます。

    以下の例では、Notifier インターフェースが、ビルドログを出力するための SetUpSendNotification メソッドを使用して定義されています。logger は Notifier の名前です。

    func (h *logger) SetUp(_ context.Context, cfg *notifiers.Config, _ notifiers.SecretGetter, _ notifiers.BindingResolver) error {
    	prd, err := notifiers.MakeCELPredicate(cfg.Spec.Notification.Filter)
    	if err != nil {
    		return fmt.Errorf("failed to create CELPredicate: %w", err)
    	}
    	h.filter = prd
    	return nil
    }
    
    func (h *logger) SendNotification(ctx context.Context, build *cbpb.Build) error {
    	// Include custom functionality here.
    	// This example logs the build.
    	if h.filter.Apply(ctx, build) {
    		log.V(1).Infof("printing build\n%s", prototext.Format(build))
    	} else {
    		log.V(1).Infof("build (%q, %q) did NOT match CEL filter", build.ProjectId, build.Id)
    	}
    
    	return nil
    }
    

    最終的な main.go ファイルは以下のようになります。この例では、logger が Notifier の名前として使用されます。

    package main
    
    import (
    	"context"
    	"fmt"
    
    	cbpb "cloud.google.com/go/cloudbuild/apiv1/v2/cloudbuildpb"
    	"github.com/GoogleCloudPlatform/cloud-build-notifiers/lib/notifiers"
    	log "github.com/golang/glog"
    	"google.golang.org/protobuf/encoding/prototext"
    )
    
    func main() {
    	if err := notifiers.Main(new(logger)); err != nil {
    		log.Fatalf("fatal error: %v", err)
    	}
    }
    
    type logger struct {
    	filter notifiers.EventFilter
    }
    
    func (h *logger) SetUp(_ context.Context, cfg *notifiers.Config, _ notifiers.SecretGetter, _ notifiers.BindingResolver) error {
    	prd, err := notifiers.MakeCELPredicate(cfg.Spec.Notification.Filter)
    	if err != nil {
    		return fmt.Errorf("failed to create CELPredicate: %w", err)
    	}
    	h.filter = prd
    	return nil
    }
    
    func (h *logger) SendNotification(ctx context.Context, build *cbpb.Build) error {
    	// Include custom functionality here.
    	// This example logs the build.
    	if h.filter.Apply(ctx, build) {
    		log.V(1).Infof("printing build\n%s", prototext.Format(build))
    	} else {
    		log.V(1).Infof("build (%q, %q) did NOT match CEL filter", build.ProjectId, build.Id)
    	}
    
    	return nil
    }
    

    これで Notifier を定義できたので、次の手順に従って Notifier を構成します。

通知の構成

  1. Notifier 構成ファイルを作成し、ビルドイベントに Notifier とフィルタを構成します。

    次の Notifier 構成ファイルの例では、filter フィールドで CEL と使用可能な変数 build を使用して、SUCCESS ステータスのビルドイベントをフィルタリングしています。

    apiVersion: cloud-build-notifiers/v1
    kind: YourNotifier
    metadata:
      name: logging-sample
    spec:
      notification:
        filter: build.status == Build.Status.SUCCESS

    ここで

    • logging-sample は、Notifier の名前です。

    フィルタに使用できるその他のフィールドについては、ビルドリソースをご覧ください。フィルタリングに関するその他の例については、CEL を使用してビルドイベントをフィルタリングするをご覧ください。

  2. 通知機能構成ファイルを Cloud Storage バケットにアップロードします。

    1. Cloud Storage バケットがない場合は、次のコマンドを実行してバケットを作成します。ここで、BUCKET_NAME命名要件に従って、バケットに付ける名前です。

      gsutil mb gs://BUCKET_NAME/
      
    2. Notifier 構成ファイルをバケットにアップロードします。

      gsutil cp CONFIG_FILE_NAME gs://BUCKET_NAME/CONFIG_FILE_NAME
      

      ここで

      • BUCKET_NAME はバケットの名前です。
      • CONFIG_FILE_NAME は構成ファイルの名前です。
  3. Notifier をビルドしてデプロイします。

    1. logging-sample の Dockerfile を作成します。

      
      FROM golang AS build-env
      COPY . /go-src/
      WORKDIR /go-src/
      RUN go build -o /go-app .
      
      # From the Cloud Run docs:
      # https://cloud.google.com/run/docs/tutorials/pubsub#looking_at_the_code
      # Use the official Debian slim image for a lean production container.
      # https://hub.docker.com/_/debian
      # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
      FROM debian:buster-slim
      RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
          ca-certificates && \
          rm -rf /var/lib/apt/lists/*
      
      FROM gcr.io/distroless/base
      COPY --from=build-env /go-app /
      ENTRYPOINT ["/go-app", "--v=1", "--alsologtostderr"]
      
    2. 次の cloudbuild.yaml ファイルを使用して Notifier をビルドしてデプロイします。

      steps:
      - # Build the binary and put it into the builder image.
        name: gcr.io/cloud-builders/docker
        args: ['build', '--tag=gcr.io/$PROJECT_ID/logging-sample', '.']
      
      - # Push the container image to Container Registry
        name: gcr.io/cloud-builders/docker
        args: ['push', 'gcr.io/$PROJECT_ID/logging-sample']
      
      - # Deploy to Cloud Run
        name: google/cloud-sdk
        args:
          - gcloud
          - run
          - deploy
          - logging-sample-notifier
          - --platform=managed
          - --region=us-central1
          - --image=gcr.io/$PROJECT_ID/logging-sample
          - --no-allow-unauthenticated
          - --update-env-vars=CONFIG_PATH=${_CONFIG_PATH}
      
      # Push the image with tags.
      images:
      - gcr.io/$PROJECT_ID/logging-sample

      ここで

      • _CONFIG_PATH は、Notifier 構成へのパスです(gs://BUCKET_NAME/CONFIG_FILE_NAME.yaml など)。

    cloudbuild.yaml を実行するには、Notifier パスを置換変数として渡します。

     gcloud builds submit .  --substitutions=_CONFIG_PATH=gs://BUCKET_NAME/CONFIG_FILE_NAME
    
  4. プロジェクトに認証トークンを作成する Pub/Sub 権限を付与します。

     gcloud projects add-iam-policy-binding PROJECT_ID \
       --member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
       --role=roles/iam.serviceAccountTokenCreator
    

    ここで

    • PROJECT_ID は、Google Cloud プロジェクトの ID です。
    • PROJECT_NUMBER は Google Cloud プロジェクト番号です。
  5. Pub/Sub サブスクリプション ID を表すサービス アカウントを作成します。

    gcloud iam service-accounts create cloud-run-pubsub-invoker \
      --display-name "Cloud Run Pub/Sub Invoker"
    

    cloud-run-pubsub-invoker を使用するか、Google Cloud プロジェクト内で一意の名前を使用します。

  6. cloud-run-pubsub-invoker サービスアカウントに Cloud Run Invoker 権限を付与します。

    gcloud run services add-iam-policy-binding SERVICE_NAME \
       --member=serviceAccount:cloud-run-pubsub-invoker@PROJECT_ID.iam.gserviceaccount.com \
       --role=roles/run.invoker
    

    ここで

    • SERVICE_NAME は、イメージをデプロイする Cloud Run サービスの名前です。
    • PROJECT_ID は、Google Cloud プロジェクトの ID です。
  7. cloud-builds トピックを作成して、Notifier のビルド更新メッセージを受信します。

    gcloud pubsub topics create cloud-builds
    
  8. Notifier に Pub/Sub push サブスクライバーを作成します。

     gcloud pubsub subscriptions create subscriber-id \
       --topic=cloud-builds \
       --push-endpoint=service-url \
       --push-auth-service-account=cloud-run-pubsub-invoker@project-id.iam.gserviceaccount.com
    

    ここで

    • subscriber-id は、サブスクリプションに付ける名前です。
    • service-url は、Cloud Run によって生成された、新しいサービスの URL です。
    • project-id は、Google Cloud プロジェクトの ID です。

これで Cloud Build プロジェクトの通知が設定されました。次にビルドを呼び出したときに、構成したフィルタとビルドが一致すると、チャネルに通知が届きます。

通知のテスト

gcloud builds submit コマンドを実行してビルドを呼び出し、このガイドで説明される例の通知機能をテストできます。

次の例では、構成パスとして success.yaml を指定しています。このコマンドを実行すると、最小限のビルドが成功します。また、ビルドログの出力を確認できます。

 gcloud builds submit --no-source --config=success.yaml

ここで、success.yaml は次のようになります。

 steps:
 - name: busybox
   args: ["true"]

次の例では、構成パスとして failure.yaml を指定しています。このコマンドを実行すると、ビルドが失敗します。ビルドログの出力ではなく、ソースで指定した CEL フィルタに一致する項目がないことを示す出力が表示されます。

gcloud builds submit --no-source --config=failure.yaml

ここで、failure.yaml は次のようになります。

 steps:
 - name: busybox
   args: ["false"]

Cloud Run サービスログへのログ出力以外のタスクを実行するように構成された Notifier を作成している場合、gcloud builds submit コマンドを実行して通知機能をテストできます。ビルドに関連するエラーを確認するには、サービスの Cloud Run ログを確認します。詳しくは、Cloud Run でログを表示するをご覧ください。

次のステップ