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 le build di immagini sistema operativo personalizzate, Cloud Build aggiorna automaticamente le immagini di base con le patch del sistema operativo e le norme 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 relativa alla modalità di utilizzo degli 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 locali per il tuo account utente:

      gcloud auth application-default login

      Non devi eseguire questa operazione se utilizzi Cloud Shell.

      Se viene restituito un errore di autenticazione e utilizzi un provider di identità (IdP) esterno, verifica di aver acceduto 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 le build, chiedi all'amministratore di concederti i seguenti ruoli IAM nel progetto:

  • Editor di Cloud Build (roles/cloudbuild.builds.editor)
  • Esecutore job Cloud Scheduler (roles/cloudscheduler.jobRunner) o Amministratore Cloud Scheduler (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 gli SDK client Go:

gcloud

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

  1. Crea un trigger di build manuale di Cloud Build che specifichi il file di destinazione cloudbuild.yaml 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 di push o richieste di pull filtri:

    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 gcloud builds triggers describe comando:

    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 6:00 utilizzando '0 6 * * 1', esegui il gcloud scheduler jobs create http comando:

    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 di 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

Puoi pianificare le pipeline in modo programmatico all'interno delle applicazioni aziendali utilizzando le librerie client dell'API Google Cloud Go (cloudbuild/v1 e cloudscheduler/v1).

Il seguente esempio completo di Go mostra come analizzare i flag della riga di comando e costruire la richiesta Build dalla definizione imagebuilder.yaml. Il programma registra quindi un trigger manuale di Cloud Build e esegue il provisioning di un job Cloud Scheduler quando fornisci il flag --cron_schedule.

// 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
}

Esegui l'applicazione Go pianificata

Per eseguire il file binario Go compilato e pianificare l'esecuzione ricorrente ogni lunedì alle 6:00, esegui il comando seguente:

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'

Passaggi successivi