Cloud Scheduler と Cloud Build トリガーを使用して、Image Builder の繰り返し実行をスケジュールできます。カスタム OS イメージのビルドをスケジュールすると、Cloud Build は、手動操作を必要とせずに、オペレーティング システム パッチと組織のセキュリティ ポリシーでベースライン イメージを自動的に更新します。
始める前に
- 環境を準備するで環境の設定手順を完了します。
-
まだ設定していない場合は、認証を設定します。認証では、 Cloud de Confiance by S3NS サービスと API にアクセスするための ID が確認されます。ローカル開発環境からコードまたはサンプルを実行するには、次のいずれかのオプションを選択して Compute Engine に対する認証を行います。
このページのサンプルをどのように使うかに応じて、タブを選択してください。
gcloud
-
Google Cloud CLI をインストールし、 フェデレーション ID を使用して gcloud CLI にログインします。ログイン後、次のコマンドを実行して Google Cloud CLI を初期化します。
gcloud init
-
- デフォルトのリージョンとゾーンを設定します。
-
Google Cloud CLI をインストールします。
-
フェデレーション ID(連携 ID)を使用するように gcloud CLI を構成します。
詳細については、連携 ID を使用して gcloud CLI にログインするをご覧ください。
-
ユーザー アカウントのローカル認証情報を作成します。
gcloud auth application-default login
認証エラーが返され、外部 ID プロバイダ(IdP)を使用している場合は、 フェデレーション ID を使用して gcloud CLI にログインしていることを確認します。
Go
ローカル開発環境でこのページの Go サンプルを使用するには、gcloud CLI をインストールして初期化し、ユーザー認証情報を使用してアプリケーションのデフォルト認証情報を設定します。
詳細については、 ローカル開発環境の認証を設定するをご覧ください。
必要なロール
トリガーの作成とビルドのスケジュール設定に必要な権限を取得するには、プロジェクトに対する次の IAM ロールの付与を管理者に依頼してください。
- Cloud Build 編集者 (
roles/cloudbuild.builds.editor) - Cloud Scheduler ジョブ実行者(
roles/cloudscheduler.jobRunner)または Cloud Scheduler 管理者(roles/cloudscheduler.admin) - サービス アカウント ユーザー(
roles/iam.serviceAccountUser)
ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。
必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。
スケジュール設定されたビルド パイプラインを作成する
定期的なイメージビルドは、gcloud CLI または Go クライアント SDK を使用して構成できます。
gcloud
gcloud CLI を使用して定期的な OS イメージビルドをスケジュールするには、次の操作を行います。
gcloud builds triggers create manualコマンドを実行して、ターゲットのcloudbuild.yamlファイルを指定する手動の Cloud Build ビルドトリガーを作成します。Cloud Scheduler はリポジトリ イベントではなく、このトリガーを手動で呼び出すため、push フィルタまたは pull リクエスト フィルタは指定しないでください。gcloud builds triggers create manual \ --name="TRIGGER_NAME" \ --region=REGION \ --build-config=CLOUDBUILD_YAML_PATH \ --project=PROJECT_IDgcloud builds triggers describeコマンドを実行して、新しいトリガー用に生成された一意の ID(trigger_id)を取得します。gcloud builds triggers describe TRIGGER_NAME \ --region=REGION \ --format="value(id)" \ --project=PROJECT_ID必要な Unix cron スケジュール(たとえば、
'0 6 * * 1'を使用して毎週月曜日の午前 6 時)に従って Cloud Build API(projects.locations.triggers.run)にHTTP POSTリクエストを送信する Cloud Scheduler ジョブを作成するには、gcloud scheduler jobs create httpコマンドを実行します。gcloud scheduler jobs create http JOB_NAME \ --schedule="CRON_SCHEDULE" \ --uri="https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/triggers/TRIGGER_ID:run" \ --message-body="{}" \ --oauth-service-account-email="SERVICE_ACCOUNT_EMAIL" \ --location=REGION \ --project=PROJECT_ID
次のように置き換えます。
TRIGGER_NAME: 手動の Cloud Build ビルドトリガーの名前(例:weekly-ubuntu-builder)。REGION: トリガーを作成するリージョン(例:us-central1)。CLOUDBUILD_YAML_PATH: ローカル ディレクトリ内のcloudbuild.yamlファイルのパス(例:cloudbuild.yaml)。PROJECT_ID: プロジェクト ID。JOB_NAME: Cloud Scheduler の cron ジョブの名前(例:weekly-custom-os-patching)。CRON_SCHEDULE: UNIX cron スケジュール式('0 6 * * 1'など)。TRIGGER_ID: トリガー用に生成された一意の ID(trigger_id)。SERVICE_ACCOUNT_EMAIL: Cloud Scheduler がトリガーを呼び出すことを承認するサービス アカウントのメールアドレス。このサービス アカウントにはroles/cloudbuild.builds.editor権限が必要です。
Go
Cloud de Confiance Go API クライアント ライブラリ(cloudbuild/v1 と cloudscheduler/v1)を使用して、エンタープライズ アプリケーション内でパイプラインをプログラムでスケジュールできます。
次の完全な Go の例は、コマンドライン フラグを解析し、imagebuilder.yaml 定義から Build リクエストを作成する方法を示しています。プログラムは、--cron_schedule フラグを指定すると、手動の Cloud Build トリガーを登録し、Cloud Scheduler ジョブをプロビジョニングします。
// Program main demonstrates how to submit or schedule a Image Builder pipeline using Go SDKs.
package main
import (
"context"
"flag"
"fmt"
"os"
"google.golang.org/api/cloudbuild/v1"
"google.golang.org/api/cloudscheduler/v1"
)
var (
projectID = flag.String("project_id", "", "The target Project ID")
region = flag.String("region", "us-central1", "Region of resources")
gcsWorkdir = flag.String("gcs_workdir", "", "The storage workspace directory URI, e.g. gs://my-bucket/workdir/")
serviceAccount = flag.String("service_account", "", "Service account email to run the worker VM")
imageBuilderYAML = flag.String("config_path", "imagebuilder.yaml", "Path to the imagebuilder.yaml configuration file")
arRepositoryID = flag.String("ar_repo_id", "os-images", "Name of the target generic Artifact Registry repository")
arPackageName = flag.String("ar_package_name", "custom-os", "Package identifier for OS images")
cronSchedule = flag.String("cron_schedule", "", "Optional cron schedule to run this build periodically (e.g. '0 6 * * 1')")
)
func main() {
flag.Parse()
if *projectID == "" || *serviceAccount == "" || *gcsWorkdir == "" {
fmt.Fprintln(os.Stderr, "Error: --project_id, --gcs_workdir, and --service_account are required flags")
flag.Usage()
os.Exit(1)
}
ctx := context.Background()
if *cronSchedule != "" {
fmt.Printf("Scheduling build with cron schedule: %s\n", *cronSchedule)
if err := scheduleBuild(ctx); err != nil {
fmt.Fprintf(os.Stderr, "Failed to schedule Cloud Build: %v\n", err)
os.Exit(1)
}
} else {
fmt.Println("Submitting build request immediately to Cloud Build API...")
if err := triggerBuild(ctx); err != nil {
fmt.Fprintf(os.Stderr, "Failed to trigger Cloud Build: %v\n", err)
os.Exit(1)
}
}
}
func createBuildRequest() *cloudbuild.Build {
subs := map[string]string{
"_GCS_WORKDIR": *gcsWorkdir,
"_SERVICE_ACCOUNT": fmt.Sprintf("projects/%s/serviceAccounts/%s", *projectID, *serviceAccount),
"_IMAGE_OUTPUT_PATH": "image-builder/binaryOut",
"_IMAGE_BUILDER_CONFIG_PATH": *imageBuilderYAML,
"_ARTIFACT_REGISTRY_RESOURCE_URI": fmt.Sprintf("projects/%s/locations/%s/repositories/%s/packages/%s/versions/v${BUILD_ID}", *projectID, *region, *arRepositoryID, *arPackageName),
}
return &cloudbuild.Build{
Steps: []*cloudbuild.BuildStep{
{
Name: "us-central1-docker.pkg.dev/image-builder-official/release/builder:stable",
Script: "#!/usr/bin/env bash\n/build",
Id: "imagebuilder-customize",
},
{
Name: "us-central1-docker.pkg.dev/image-builder-official/release/validator:stable",
Script: "#!/usr/bin/env bash\n/validate",
Id: "imagebuilder-validate",
},
{
Name: "us-central1-docker.pkg.dev/image-builder-official/release/builder:stable",
Script: "#!/usr/bin/env bash\n/publish",
Id: "imagebuilder-publish",
},
},
Substitutions: subs,
Options: &cloudbuild.BuildOptions{
AutomapSubstitutions: true,
RequestedVerifyOption: "VERIFIED",
SubstitutionOption: "ALLOW_LOOSE",
DynamicSubstitutions: true,
},
Timeout: "3600s",
}
}
func triggerBuild(ctx context.Context) error {
cbService, err := cloudbuild.NewService(ctx)
if err != nil {
return err
}
build := createBuildRequest()
op, err := cbService.Projects.Locations.Builds.Create(fmt.Sprintf("projects/%s/locations/%s", *projectID, *region), build).Do()
if err != nil {
return err
}
fmt.Printf("Build submitted: %s\n", op.Name)
return nil
}
func scheduleBuild(ctx context.Context) error {
cbService, err := cloudbuild.NewService(ctx)
if err != nil {
return err
}
csService, err := cloudscheduler.NewService(ctx)
if err != nil {
return err
}
// 1. Create a manual Cloud Build trigger
trigger := &cloudbuild.BuildTrigger{
Build: createBuildRequest(),
Name: "scheduled-image-builder-trigger",
Description: "Manual trigger invoked periodically via Cloud Scheduler for Image Builder",
}
createdTrigger, err := cbService.Projects.Locations.Triggers.Create(fmt.Sprintf("projects/%s/locations/%s", *projectID, *region), trigger).Do()
if err != nil {
return fmt.Errorf("failed creating trigger: %w", err)
}
fmt.Printf("Created Cloud Build trigger with ID: %s\n", createdTrigger.Id)
// 2. Create the Cloud Scheduler job
targetURI := fmt.Sprintf("https://cloudbuild.googleapis.com/v1/projects/%s/locations/%s/triggers/%s:run", *projectID, *region, createdTrigger.Id)
job := &cloudscheduler.Job{
Name: fmt.Sprintf("projects/%s/locations/%s/jobs/weekly-image-builder-job", *projectID, *region),
Schedule: *cronSchedule,
Description: "Scheduled job to run custom OS Image Builder pipeline",
HttpTarget: &cloudscheduler.HttpTarget{
Uri: targetURI,
HttpMethod: "POST",
OauthToken: &cloudscheduler.OAuthToken{
ServiceAccountEmail: *serviceAccount,
},
},
}
createdJob, err := csService.Projects.Locations.Jobs.Create(fmt.Sprintf("projects/%s/locations/%s", *projectID, *region), job).Do()
if err != nil {
return fmt.Errorf("failed creating scheduler job: %w", err)
}
fmt.Printf("Successfully scheduled job: %s\n", createdJob.Name)
return nil
}
スケジュールされた Go アプリケーションを実行する
コンパイルされた Go バイナリを実行し、毎週月曜日の午前 6 時に定期的な実行をスケジュールするには、次のコマンドを実行します。
go run main.go \ --project_id PROJECT_ID \ --region us-central1 \ --gcs_workdir gs://STAGING_BUCKET/workdir/ \ --service_account SERVICE_ACCOUNT_EMAIL \ --config_path gs://STAGING_BUCKET/imagebuilder.yaml \ --cron_schedule '0 6 * * 1'
次のステップ
- Terraform を使用して、Git の push、タグ、マージ イベントで リポジトリ イベントのビルドを自動化する方法を学習する。
- カスタマイズ レシピ スキーマを確認して、ソフトウェア パッケージと検証手順を定義します。