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 Basis-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-Jobinitiator (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 den Go-Client-SDKs konfigurieren:

gcloud

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

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

    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 Ihren neuen Trigger generiert wurde, indem Sie den Befehl gcloud builds triggers describe ausführen:

    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-Cron-Job, 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, mit der Cloud Scheduler autorisiert wird, den Trigger aufzurufen. Für dieses Dienstkonto sind roles/cloudbuild.builds.editor-Berechtigungen erforderlich.

Go

Sie können Pipelines programmatisch in Ihren Unternehmensanwendungen planen, indem Sie die Cloud de Confiance Go API-Clientbibliothekencloudbuild/v1 und cloudscheduler/v1 verwenden.

Das folgende vollständige Go-Beispiel zeigt, wie Befehlszeilen-Flags geparst und die Build-Anfrage aus Ihrer imagebuilder.yaml-Definition erstellt wird. Das Programm registriert dann einen manuellen Cloud Build-Trigger und stellt einen Cloud Scheduler-Job bereit, wenn Sie das Flag --cron_schedule angeben.

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

Geplante Go-Anwendung ausführen

Führen Sie den folgenden Befehl aus, um die kompilierte Go-Binärdatei auszuführen und die wiederkehrende Ausführung für jeden Montag um 6:00 Uhr zu planen:

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'

Nächste Schritte