Menjadwalkan build image OS kustom

Anda dapat menjadwalkan eksekusi Image Builder berulang menggunakan pemicu Cloud Scheduler dan Cloud Build. Saat Anda menjadwalkan build image OS kustom, Cloud Build akan otomatis mengupdate image dasar Anda dengan patch sistem operasi dan kebijakan keamanan organisasi tanpa memerlukan intervensi manual.

Sebelum memulai

  • Selesaikan langkah-langkah penyiapan lingkungan di Menyiapkan lingkungan Anda.
  • Siapkan autentikasi jika Anda belum melakukannya. Autentikasi memverifikasi identitas Anda untuk mengakses layanan Google Cloud dan API. Untuk menjalankan kode atau sampel dari lingkungan pengembangan lokal, Anda dapat melakukan autentikasi ke Compute Engine dengan memilih salah satu opsi berikut:

    Pilih tab untuk melihat bagaimana Anda berencana menggunakan contoh di halaman ini:

    gcloud

    1. Instal Google Cloud CLI. Setelah penginstalan, inisialisasi Google Cloud CLI dengan menjalankan perintah berikut:

      gcloud init

      Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

  • Tetapkan region dan zona default.
  • Go

    Untuk menggunakan contoh Go di halaman ini dalam lingkungan pengembangan lokal, instal dan lakukan inisialisasi gcloud CLI, lalu siapkan Kredensial Default Aplikasi dengan kredensial pengguna Anda.

    1. Instal Google Cloud CLI.

    2. Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

    3. Jika Anda menggunakan shell lokal, buat kredensial autentikasi lokal untuk akun pengguna Anda:

      gcloud auth application-default login

      Anda tidak perlu melakukan langkah ini jika menggunakan Cloud Shell.

      Jika error autentikasi ditampilkan, dan Anda menggunakan penyedia identitas (IdP) eksternal, konfirmasi bahwa Anda telah login ke gcloud CLI dengan identitas gabungan Anda.

    Untuk mengetahui informasi selengkapnya, lihat Menyiapkan autentikasi untuk lingkungan pengembangan lokal.

Peran yang diperlukan

Untuk mendapatkan izin yang Anda perlukan untuk membuat pemicu dan menjadwalkan build, minta administrator untuk memberi Anda peran IAM berikut di project Anda:

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

Untuk mengetahui informasi selengkapnya tentang pemberian peran, lihat Mengelola akses ke project, folder, dan organisasi.

Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

Membuat pipeline build terjadwal

Anda dapat mengonfigurasi build image berulang menggunakan gcloud CLI atau SDK klien Go:

gcloud

Untuk menjadwalkan build image OS berulang menggunakan gcloud CLI, selesaikan langkah-langkah berikut:

  1. Buat pemicu Cloud Build manual yang menentukan file cloudbuild.yaml target dengan menjalankan perintah gcloud builds triggers create manual. Karena Cloud Scheduler memanggil pemicu ini secara manual bukan pada peristiwa repositori, jangan tentukan filter permintaan pull atau push:

    gcloud builds triggers create manual \
        --name="TRIGGER_NAME" \
        --region=REGION \
        --build-config=CLOUDBUILD_YAML_PATH \
        --project=PROJECT_ID
    
  2. Ambil ID unik (trigger_id) yang dibuat untuk pemicu baru Anda dengan menjalankan perintah gcloud builds triggers describe:

    gcloud builds triggers describe TRIGGER_NAME \
        --region=REGION \
        --format="value(id)" \
        --project=PROJECT_ID
    
  3. Untuk membuat tugas Cloud Scheduler yang mengirim permintaan HTTP POST ke Cloud Build API (projects.locations.triggers.run) sesuai dengan jadwal cron Unix yang diperlukan, misalnya, mingguan pada hari Senin pukul 06.00 menggunakan '0 6 * * 1', jalankan perintah 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
    

Ganti kode berikut:

  • TRIGGER_NAME: nama untuk pemicu Cloud Build manual Anda, misalnya, weekly-ubuntu-builder.
  • REGION: region untuk membuat pemicu, misalnya, us-central1.
  • CLOUDBUILD_YAML_PATH: jalur ke file cloudbuild.yaml di direktori lokal Anda, misalnya, cloudbuild.yaml.
  • PROJECT_ID: project ID Anda.
  • JOB_NAME: nama untuk cron job Cloud Scheduler Anda, misalnya, weekly-custom-os-patching.
  • CRON_SCHEDULE: ekspresi jadwal cron unix, misalnya, '0 6 * * 1'.
  • TRIGGER_ID: ID unik (trigger_id) yang dibuat untuk pemicu Anda.
  • SERVICE_ACCOUNT_EMAIL: email akun layanan yang mengizinkan Cloud Scheduler untuk memanggil pemicu. Akun layanan ini memerlukan izin roles/cloudbuild.builds.editor.

Go

Anda dapat menjadwalkan pipeline secara terprogram di dalam aplikasi perusahaan menggunakan Google Cloud library klien Go API (cloudbuild/v1 dan cloudscheduler/v1).

Contoh Go lengkap berikut menunjukkan cara mengurai flag command line dan membuat permintaan Build dari definisi imagebuilder.yaml Anda. Kemudian, program akan mendaftarkan pemicu Cloud Build manual dan menyediakan tugas Cloud Scheduler saat Anda memberikan tanda --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
}

Menjalankan aplikasi Go terjadwal

Untuk menjalankan program biner Go yang dikompilasi dan menjadwalkan eksekusi berulang setiap hari Senin pukul 06.00, jalankan perintah berikut:

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'

Langkah berikutnya