Pianificare le build di immagini del sistema operativo personalizzate

Puoi pianificare esecuzioni ricorrenti di Image Builder utilizzando i trigger di Cloud Scheduler e Cloud Build. Quando pianifichi build di immagini sistema operativo personalizzate, Cloud Build aggiorna automaticamente le immagini di base con patch del sistema operativo e policy di sicurezza dell'organizzazione senza richiedere un intervento manuale.

Prima di iniziare

  • Completa i passaggi di configurazione dell'ambiente in Prepara l'ambiente.
  • Se non l'hai ancora fatto, configura l'autenticazione. L'autenticazione verifica la tua identità per l'accesso ad API e servizi Google Cloud . Per eseguire codice o esempi da un ambiente di sviluppo locale, puoi autenticarti su Compute Engine selezionando una delle seguenti opzioni:

    Seleziona la scheda in base a come prevedi di utilizzare gli esempi in questa pagina:

    gcloud

    1. Installa Google Cloud CLI. Dopo l'installazione, inizializza Google Cloud CLI eseguendo il comando seguente:

      gcloud init

      Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  • Imposta una regione e una zona predefinite.
  • Vai

    Per utilizzare gli esempi di Go in questa pagina in un ambiente di sviluppo locale, installa e inizializza gcloud CLI, quindi configura Credenziali predefinite dell'applicazione con le tue credenziali utente.

    1. Installa Google Cloud CLI.

    2. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

    3. Se utilizzi una shell locale, crea le credenziali di autenticazione locale per il tuo account utente:

      gcloud auth application-default login

      Non è necessario farlo se utilizzi Cloud Shell.

      Se viene restituito un errore di autenticazione e utilizzi un provider di identità (IdP) esterno, verifica di aver eseguito l'accesso a gcloud CLI con la tua identità federata.

    Per saperne di più, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per creare trigger e pianificare build, chiedi all'amministratore di concederti i seguenti ruoli IAM nel progetto:

  • Cloud Build Editor (roles/cloudbuild.builds.editor)
  • Cloud Scheduler Job Runner (roles/cloudscheduler.jobRunner) o Cloud Scheduler Admin (roles/cloudscheduler.admin)
  • Utente Service Account (roles/iam.serviceAccountUser)

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Potresti anche riuscire a ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Crea una pipeline di build pianificata

Puoi configurare build di immagini ricorrenti utilizzando gcloud CLI o la libreria client Go:

gcloud

Per pianificare build ricorrenti di immagini sistema operativo utilizzando gcloud CLI, completa i seguenti passaggi:

  1. Crea un trigger di Cloud Build manuale che specifichi il file cloudbuild.yaml di destinazione eseguendo il comando gcloud builds triggers create manual. Poiché Cloud Scheduler richiama questo trigger manualmente anziché in base agli eventi del repository, non specificare filtri per le richieste di push o pull:

    gcloud builds triggers create manual \
        --name="TRIGGER_NAME" \
        --region=REGION \
        --build-config=CLOUDBUILD_YAML_PATH \
        --project=PROJECT_ID
    
  2. Recupera l'ID univoco (trigger_id) generato per il nuovo trigger eseguendo il comando gcloud builds triggers describe:

    gcloud builds triggers describe TRIGGER_NAME \
        --region=REGION \
        --format="value(id)" \
        --project=PROJECT_ID
    
  3. Per creare un job Cloud Scheduler che invii una richiesta HTTP POST all'API Cloud Build (projects.locations.triggers.run) in base alla pianificazione cron unix richiesta, ad esempio settimanalmente il lunedì alle 06:00 utilizzando '0 6 * * 1', esegui il comando 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
    

Sostituisci quanto segue:

  • TRIGGER_NAME: il nome del trigger di build Cloud Build, ad esempio weekly-ubuntu-builder.
  • REGION: la regione in cui creare il trigger, ad esempio us-central1.
  • CLOUDBUILD_YAML_PATH: il percorso del file cloudbuild.yaml nella directory locale, ad esempio cloudbuild.yaml.
  • PROJECT_ID: il tuo ID progetto.
  • JOB_NAME: il nome del job cron di Cloud Scheduler, ad esempio weekly-custom-os-patching.
  • CRON_SCHEDULE: l'espressione di pianificazione cron Unix, ad esempio '0 6 * * 1'.
  • TRIGGER_ID: l'ID univoco (trigger_id) generato per il trigger.
  • SERVICE_ACCOUNT_EMAIL: l'indirizzo email del account di servizio che autorizza Cloud Scheduler a richiamare il trigger. Questo account di servizio richiede le autorizzazioni roles/cloudbuild.builds.editor.

Vai

Per pianificare le pipeline in modo programmatico utilizzando le librerie client Go di Cloud Build e Cloud Scheduler, utilizza la funzione scheduleBuild.

Prima di eseguire questo esempio, completa i seguenti prerequisiti:

  • Carica il file di configurazione imagebuilder.yaml nel bucket Cloud Storage, ad esempio gs://STAGING_BUCKET/imagebuilder.yaml.
  • Concedi al account di servizio di pianificazione cloud-build-trigger-scheduler@PROJECT_ID.iam.gserviceaccount.com il ruolo Cloud Build Editor (roles/cloudbuild.builds.editor) nel tuo progetto e il ruolo Service Account User (roles/iam.serviceAccountUser) nel account di servizio che esegue la build. Per saperne di più, consulta Pianifica le build nella documentazione di Cloud Build.
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
}

Passaggi successivi