Erstellung benutzerdefinierter Betriebssystem-Images planen

Sie können wiederkehrende Image Builder-Ausführungen mit Cloud Scheduler- und Cloud Build-Triggern planen. Wenn Sie benutzerdefinierte Betriebssystem-Image-Builds planen, aktualisiert Cloud Build Ihre Baseline-Images automatisch mit Betriebssystem-Patches und Sicherheitsrichtlinien der Organisation, ohne dass ein manueller Eingriff erforderlich ist.

Hinweis

Erforderliche Rollen

Bitten Sie Ihren Administrator, Ihnen die folgenden IAM-Rollen für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Erstellen von Triggern und Planen von Builds benötigen:

  • Cloud Build-Bearbeiter (roles/cloudbuild.builds.editor)
  • Cloud Scheduler-Job-Ausführer (roles/cloudscheduler.jobRunner) oder Cloud Scheduler-Administrator (roles/cloudscheduler.admin)
  • Service Account User (roles/iam.serviceAccountUser)

Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

Geplante Build-Pipeline erstellen

Sie können wiederkehrende Image-Builds mit der gcloud CLI oder der Go-Clientbibliothek konfigurieren:

gcloud

So planen Sie wiederkehrende Betriebssystem-Image-Builds mit der gcloud CLI:

  1. Erstellen Sie einen manuellen Cloud Build-Trigger, der Ihre cloudbuild.yaml-Zieldatei angibt, indem Sie den Befehl gcloud builds triggers create manual ausführen. Da Cloud Scheduler diesen Trigger manuell und nicht bei Repository-Ereignissen aufruft, geben Sie keine Push- oder Pull-Anfragefilter an:

    gcloud builds triggers create manual \
        --name="TRIGGER_NAME" \
        --region=REGION \
        --build-config=CLOUDBUILD_YAML_PATH \
        --project=PROJECT_ID
    
  2. Rufen Sie die eindeutige ID (trigger_id) ab, die für den neuen Trigger generiert wurde. Führen Sie dazu den Befehl gcloud builds triggers describe aus:

    gcloud builds triggers describe TRIGGER_NAME \
        --region=REGION \
        --format="value(id)" \
        --project=PROJECT_ID
    
  3. Wenn Sie einen Cloud Scheduler-Job erstellen möchten, der gemäß Ihrem erforderlichen Unix-Cron-Zeitplan eine HTTP POST-Anfrage an die Cloud Build API (projects.locations.triggers.run) sendet, z. B. wöchentlich montags um 6:00 Uhr mit '0 6 * * 1', führen Sie den gcloud scheduler jobs create http-Befehl aus:

    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
    

Ersetzen Sie Folgendes:

  • TRIGGER_NAME: der Name für Ihren manuellen Cloud Build-Trigger, z. B. weekly-ubuntu-builder.
  • REGION: die Region, in der der Trigger erstellt werden soll, z. B. us-central1.
  • CLOUDBUILD_YAML_PATH: der Pfad zu Ihrer cloudbuild.yaml-Datei in Ihrem lokalen Verzeichnis, z. B. cloudbuild.yaml.
  • PROJECT_ID: Ihre Projekt-ID.
  • JOB_NAME: der Name für Ihren Cloud Scheduler-Cronjob, z. B. weekly-custom-os-patching.
  • CRON_SCHEDULE: der Unix-Cron-Zeitplanausdruck, z. B. '0 6 * * 1'.
  • TRIGGER_ID: die eindeutige ID (trigger_id), die für Ihren Trigger generiert wurde.
  • SERVICE_ACCOUNT_EMAIL: die E-Mail-Adresse des Dienstkontos, die Cloud Scheduler zum Aufrufen des Triggers autorisiert. Für dieses Dienstkonto sind roles/cloudbuild.builds.editor-Berechtigungen erforderlich.

Go

Wenn Sie Pipelines programmatisch mit den Go-Clientbibliotheken von Cloud Build und Cloud Scheduler planen möchten, verwenden Sie die Funktion scheduleBuild.

Bevor Sie dieses Beispiel ausführen, müssen die folgenden Voraussetzungen erfüllt sein:

  • Laden Sie die Konfigurationsdatei imagebuilder.yaml in Ihren Cloud Storage-Bucket hoch, z. B. gs://STAGING_BUCKET/imagebuilder.yaml.
  • Weisen Sie dem Planungsdienstkonto cloud-build-trigger-scheduler@PROJECT_ID.iam.gserviceaccount.com die Rolle „Cloud Build-Bearbeiter“ (roles/cloudbuild.builds.editor) für Ihr Projekt und die Rolle „Dienstkontonutzer“ (roles/iam.serviceAccountUser) für das Dienstkonto zu, das den Build ausführt. Weitere Informationen finden Sie in der Cloud Build-Dokumentation unter Builds planen.
import (
	"context"
	"fmt"
	"io"

	scheduler "cloud.google.com/go/scheduler/apiv1"
	"cloud.google.com/go/scheduler/apiv1/schedulerpb"
	"google.golang.org/api/cloudbuild/v1"
)

// scheduleBuild creates a manual Cloud Build trigger that runs an Image
// Builder pipeline, and a Cloud Scheduler job that runs the trigger every day.
//
// Before you run this sample, upload your imagebuilder.yaml configuration file
// to Cloud Storage, create a generic Artifact Registry repository, and create a
// service account to run the build.
//
// The job runs the trigger as the default scheduling service account,
// cloud-build-trigger-scheduler@PROJECT_ID.iam.gserviceaccount.com. Grant that
// service account the Cloud Build Editor role, and the Service Account User
// role on the service account that runs the build. For details, see
// https://cloud.google.com/build/docs/schedule-builds.
func scheduleBuild(w io.Writer, projectID, gcsWorkdir, configPath, serviceAccount string) error {
	// projectID := "my-project-id"
	region := "us-central1"
	// gcsWorkdir := "gs://my-bucket/workdir/"
	// configPath := "gs://my-bucket/imagebuilder.yaml"
	repository := "vm-images"
	packageName := "custom-os-images"
	// serviceAccount := "image-builder@my-project-id.iam.gserviceaccount.com"
	triggerName := "scheduled-image-builder"
	jobName := "scheduled-image-builder-job"
	schedule := "0 9 * * *"

	ctx := context.Background()
	cbService, err := cloudbuild.NewService(ctx)
	if err != nil {
		return fmt.Errorf("cloudbuild.NewService: %w", err)
	}
	schedulerClient, err := scheduler.NewCloudSchedulerClient(ctx)
	if err != nil {
		return fmt.Errorf("scheduler.NewCloudSchedulerClient: %w", err)
	}
	defer schedulerClient.Close()

	parent := fmt.Sprintf("projects/%s/locations/%s", projectID, region)
	sa := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, serviceAccount)

	trigger := &cloudbuild.BuildTrigger{
		Name:        triggerName,
		Description: "Manual trigger for scheduled VM image builds",
		EventType:   "MANUAL",
		Build: &cloudbuild.Build{
			ServiceAccount: sa,
			// AutomapSubstitutions exposes these substitutions to every step as
			// environment variables. See
			// https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#mapping_substitutions_to_environment_variables
			Substitutions: map[string]string{
				"_GCS_WORKDIR":               gcsWorkdir,
				"_SERVICE_ACCOUNT":           sa,
				"_IMAGE_OUTPUT_PATH":         "image-builder/binaryOut",
				"_IMAGE_BUILDER_CONFIG_PATH": configPath,
				"_ARTIFACT_REGISTRY_RESOURCE_URI": fmt.Sprintf(
					"projects/%s/locations/%s/repositories/%s/packages/%s/versions/v${BUILD_ID}",
					projectID, region, repository, packageName,
				),
			},
			Steps: []*cloudbuild.BuildStep{
				{
					Id:     "imagebuilder-customize",
					Name:   "us-docker.pkg.dev/image-builder-official/release/builder:stable",
					Script: "#!/usr/bin/env bash\n/build",
					Results: []*cloudbuild.StepResult{
						{
							Name:            "base_image",
							AttestationType: "https://cloudbuild.googleapis.com/attestations/build_content_restrictions",
						},
						{Name: "image_builder_telemetry_metrics"},
					},
				},
				{
					Id:      "imagebuilder-validate",
					Name:    "us-docker.pkg.dev/image-builder-official/release/validator:stable",
					Script:  "#!/usr/bin/env bash\n/validate",
					Results: []*cloudbuild.StepResult{{Name: "image_builder_telemetry_metrics"}},
				},
				{
					Id:      "imagebuilder-publish",
					Name:    "us-docker.pkg.dev/image-builder-official/release/builder:stable",
					Script:  "#!/usr/bin/env bash\n/publish",
					Results: []*cloudbuild.StepResult{{Name: "image_builder_telemetry_metrics"}},
				},
			},
			Options: &cloudbuild.BuildOptions{
				AutomapSubstitutions:  true,
				DynamicSubstitutions:  true,
				RequestedVerifyOption: "VERIFIED",
				SubstitutionOption:    "ALLOW_LOOSE",
				// Builds that run as a user-specified service account must set a
				// logging option.
				Logging: "CLOUD_LOGGING_ONLY",
			},
			Artifacts: &cloudbuild.Artifacts{
				GenericArtifacts: []*cloudbuild.GenericArtifact{
					{
						Folder:       "${_IMAGE_OUTPUT_PATH}",
						RegistryPath: "${_ARTIFACT_REGISTRY_RESOURCE_URI}",
					},
				},
			},
			Timeout: "3600s",
		},
	}
	createdTrigger, err := cbService.Projects.Locations.Triggers.Create(parent, trigger).
		Context(ctx).Do()
	if err != nil {
		return fmt.Errorf("Triggers.Create: %w", err)
	}
	fmt.Fprintf(w, "Created trigger %s (ID: %s)\n", createdTrigger.Name, createdTrigger.Id)

	schedulerSA := fmt.Sprintf(
		"cloud-build-trigger-scheduler@%s.iam.gserviceaccount.com", projectID,
	)
	job := &schedulerpb.Job{
		Name:        fmt.Sprintf("%s/jobs/%s", parent, jobName),
		Description: "Runs the Image Builder trigger on a schedule",
		Schedule:    schedule,
		Target: &schedulerpb.Job_HttpTarget{
			HttpTarget: &schedulerpb.HttpTarget{
				Uri: fmt.Sprintf(
					"https://cloudbuild.googleapis.com/v1/projects/%s/locations/%s/triggers/%s:run",
					projectID, region, createdTrigger.Id,
				),
				HttpMethod: schedulerpb.HttpMethod_POST,
				AuthorizationHeader: &schedulerpb.HttpTarget_OauthToken{
					OauthToken: &schedulerpb.OAuthToken{
						ServiceAccountEmail: schedulerSA,
					},
				},
			},
		},
	}
	req := &schedulerpb.CreateJobRequest{Parent: parent, Job: job}
	createdJob, err := schedulerClient.CreateJob(ctx, req)
	if err != nil {
		return fmt.Errorf("CreateJob: %w", err)
	}
	fmt.Fprintf(w, "Created job %s with schedule %q\n", createdJob.Name, createdJob.Schedule)
	return nil
}

Nächste Schritte