创建自己的通知程序

Cloud Build 可以通过向您的所需渠道发送通知来通知您构建状态更新。除了 由 Cloud Build 维护的通知程序(例如 SlackSMTP) 您还可以在 cloud-build-notifiers 来创建自己的通知程序。

本页面介绍如何创建您自己的通知程序。

准备工作

  • Enable the Cloud Build, Cloud Run, Pub/Sub, and Secret Manager APIs.

    Enable the APIs

  • 安装 Go 编程语言

  • 安装 Google Cloud CLI

设置

  1. 在您的机器上打开一个终端窗口。

  2. 克隆并导航至 cloud-build-notifiers 代码库:

      git clone https://github.com/GoogleCloudPlatform/cloud-build-notifiers.git && cd cloud-build-notifiers
    
  3. 为您自己的通知程序添加目录并导航到该目录中,其中 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 文件中,以确保您使用的是最新版本的通知程序:

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

现在您的依赖项已设置完毕,您可以创建自己的通知程序了。

创建自己的通知程序

cloud-build-notifiers 包含 lib/notifiers 目录。在 lib/notifiers 目录中,您将看到名为 notifier.go 的文件。此文件包含可用于创建您自己的通知程序的框架。

您需要定义两种方法以便在主文件中创建通知程序。

  1. 在新目录中,创建一个名为 main.go 的文件。

  2. main.go 中,导入通知程序库框架和任何其他依赖项:

    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. 为您的通知程序定义主方法。在此示例中,logger 是通知程序的名称:

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

    main 方法使用 notifier.go 文件中定义的 Main 方法,它用于设置通知程序二进制文件。

  4. 为通知程序定义一个结构体,您将在其中定义接口的变量。在此示例中,logger 是通知程序名称。例如,

    type logger struct {
    	filter notifiers.EventFilter
    }
    

接下来,添加通知程序功能。通知程序接口由两种方法定义:

  • SetUpSetUp 方法接受一种配置、提取密文并且从配置中拉取指定过滤条件,并将其存储为可用于发送通知的通用表达式语言谓词。如需详细了解 CEL,请参阅 cel-spec 代码库
  • SendNotificationSendNotification 方法用于向所需的渠道或服务发送通知。

    notifier.goGo 文档中提供了通知程序的定义。

    在以下示例中,通知程序接口使用 SetUpSendNotification 方法定义为输出构建日志,其中 logger 是您的通知程序的名称:

    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 用作通知程序的名称。

    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
    }
    

    定义好通知程序后,您可以按照以下步骤配置通知程序。

配置通知

  1. 编写通知程序配置文件以配置您的通知程序并过滤构建事件:

    在以下示例通知程序配置文件中,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 是通知程序的名称。

    如需了解可用于过滤的其他字段,请参阅构建资源。如需了解其他过滤示例,请参阅使用 CEL 过滤构建事件

  2. 将通知程序配置文件上传到 Cloud Storage 存储分区

    1. 如果没有 Cloud Storage 存储分区,请运行以下命令创建一个存储分区,其中 BUCKET_NAME 是您想要为存储分区指定的名称(须遵循命名要求部分)。

      gcloud storage buckets create gs://BUCKET_NAME/
      
    2. 将通知程序配置文件上传到您的存储分区:

      gcloud storage cp CONFIG_FILE_NAME gs://BUCKET_NAME/CONFIG_FILE_NAME
      

      其中:

      • BUCKET_NAME 是您的存储分区的名称。
      • CONFIG_FILE_NAME 是您的配置文件的名称。
  3. 构建和部署您的通知程序:

    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 文件构建和部署通知程序。

      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 是通知程序配置的路径,例如 gs://BUCKET_NAME/CONFIG_FILE_NAME.yaml

    要运行 cloudbuild.yaml,请将通知程序路径作为替代变量传入。

     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 订阅身份:

    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 主题以接收通知程序的构建更新消息:

    gcloud pubsub topics create cloud-builds
    
  8. 为通知程序创建 Pub/Sub 推送订阅者:

     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 为新服务生成的网址。
    • 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 服务日志输出以外的不同任务,您还可以运行 gcloud builds submit 命令来测试通知功能。如需检查与您的构建相关的错误,请检查服务的 Cloud Run 日志。如需了解详情,请参阅在 Cloud Run 中查看日志

后续步骤