Crea una pipeline di immagini sistema operativo personalizzate utilizzando gcloud o Terraform

Configura e invia un programma della pipeline di Image Builder a livello di programmazione utilizzando Google Cloud CLI o Terraform. La configurazione della pipeline a livello di programmazione ti consente di definire le impostazioni dell'infrastruttura, le immagini del sistema operativo di base, le azioni di personalizzazione e i test di convalida nei file di configurazione dichiarativi.

Prima di iniziare

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per creare e inviare pipeline di personalizzazione delle immagini utilizzando Google Cloud CLI o Terraform, chiedi all'amministratore di concederti i seguenti ruoli IAM nel progetto:

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.

Creare i file di configurazione

Per configurare la pipeline utilizzando gcloud CLI o Terraform, crea due file di configurazione:

  • imagebuilder.yaml: definisce la ricetta di personalizzazione per l'immagine, inclusa l'immagine del sistema operativo di base, le impostazioni dell'infrastruttura della VM worker, i dettagli dell'output dell'immagine di destinazione e i passaggi di personalizzazione sequenziali, come l'esecuzione di script shell, il trasferimento di file o l'esecuzione di riavvii.
  • cloudbuild.yaml: orchestra i passaggi del processo di compilazione in Cloud Build, inclusi l'analisi, la convalida, la creazione, il test e la pubblicazione dell'immagine del sistema operativo personalizzata.

Creare il file di configurazione dell'immagine

Per specificare la configurazione dell'immagine, crea un file denominato imagebuilder.yaml nella directory locale. Per un elenco completo di tutti i campi dello schema e le azioni di personalizzazione supportati, consulta Schema della ricetta di personalizzazione e Azioni di personalizzazione supportate.

Il seguente file imagebuilder.yaml di esempio configura una pipeline che crea un'immagine Ubuntu 22.04 LTS personalizzata utilizzando una VM worker e2-standard-4 nella regione e nella zona specificate ed esegue un aggiornamento del pacchetto di sistema.

apiVersion: imagebuilder.gcp.com/v1
kind: OSImageCustomization
metadata:
  name: customized-ubuntu-baseline
  description: "Ubuntu 22.04 LTS custom OS baseline image"
infrastructureConfig:
  machineType: e2-standard-4
  zone: ZONE
  debug: false
source:
  imageFamily: projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts
destinations:
  - diskImage:
      name: custom-ubuntu-v1
      family: custom-ubuntu-family
      project: PROJECT_ID
      storageLocations:
        - REGION
spec:
  config:
    skipSystemTests: false
  steps:
    -   name: "System Package Update"
      action: Shell
      inputs:
        command: "apt-get update -y && apt-get upgrade -y"

Sostituisci i seguenti valori segnaposto:

  • PROJECT_ID: il tuo ID progetto.
  • REGION: la località di archiviazione dell'immagine di destinazione, ad esempio us-east1 o europe-west1. Assicurati di soddisfare i seguenti requisiti regionali e di zona:
    • Image Builder è supportato solo nelle regioni in cui è disponibile Cloud Build.
    • La ZONE della VM worker deve trovarsi all'interno della REGION specificata.
    • Per ridurre al minimo la latenza di rete ed evitare addebiti per l'uscita tra regioni, assicurati che la zona della VM worker, il bucket di gestione temporanea Cloud Storage, il repository Artifact Registry e la località di archiviazione dell'immagine di destinazione si trovino nella stessa regione.
  • ZONE: una zona che si trova all'interno della REGION specificata, ad esempio us-east1-b o europe-west1-b.

Creare il file di build dell'orchestratore

Crea un file denominato cloudbuild.yaml nella stessa directory. Questo file chiama i passaggi del container Image Builder per creare, convalidare e pubblicare l'immagine del sistema operativo personalizzata.

substitutions:
  _GCS_WORKDIR: 'gs://STAGING_BUCKET_NAME/workdir/'
  _IMAGE_BUILDER_CONFIG_PATH: 'imagebuilder.yaml'
  _SERVICE_ACCOUNT: 'projects/PROJECT_ID/serviceAccounts/SERVICE_ACCOUNT_EMAIL'
  _IMAGE_OUTPUT_PATH: 'image-builder/binaryOut'
  _ARTIFACT_REGISTRY_RESOURCE_URI: 'projects/PROJECT_ID/locations/REGION/repositories/REPOSITORY_NAME/packages/PACKAGE_NAME/versions/v${BUILD_ID}'

steps:
  #  Step 1: Parse configs and run OS customization on worker VM
  - name: 'REGION-docker.pkg.dev/image-builder-official/release/builder:stable'
    script: |
      #!/usr/bin/env bash
      /build
    id: 'imagebuilder-customize'
    results:
      - name: image_builder_telemetry_metrics
      - name: base_image
        attestationType: "https://cloudbuild.googleapis.com/attestations/build_content_restrictions"
        attestationContent: base_image

  # Step 2: Validate by running system boot checks on a test VM
  - name: 'REGION-docker.pkg.dev/image-builder-official/release/validator:stable'
    script: |
      #!/usr/bin/env bash
      /validate
    id: 'imagebuilder-validate'
    results:
      - name: image_builder_telemetry_metrics

  # Step 3: Register image in Compute Engine and upload tar files to Artifact Registry
  - name: 'REGION-docker.pkg.dev/image-builder-official/release/builder:stable'
    script: |
      #!/usr/bin/env bash
      /publish
    id: 'imagebuilder-publish'
    results:
      - name: image_builder_telemetry_metrics

options:
  automapSubstitutions: true
  requestedVerifyOption: VERIFIED
  substitutionOption: ALLOW_LOOSE
  dynamicSubstitutions: true
  logging: CLOUD_LOGGING_ONLY

artifacts:
  generic_artifacts:
    - folder: '${_IMAGE_OUTPUT_PATH}'
      registry_path: '${_ARTIFACT_REGISTRY_RESOURCE_URI}'

timeout: '3600s'

Sostituisci i seguenti valori segnaposto:

  • STAGING_BUCKET_NAME: un bucket Cloud Storage esistente nel tuo progetto da utilizzare come spazio di lavoro di gestione temporanea. Se non hai un bucket, puoi crearne uno eseguendo gcloud storage buckets create gs://STAGING_BUCKET_NAME. Se esegui il deployment della pipeline utilizzando Terraform, Terraform crea automaticamente questo bucket.
  • PROJECT_ID: il tuo Google Cloud ID progetto.
  • REGION: la Google Cloud regione del repository Artifact Registry, ad esempio us-east1 o europe-west1.
  • SERVICE_ACCOUNT_EMAIL: l'indirizzo email del service account configurato con le autorizzazioni IAM richieste.
  • REPOSITORY e PACKAGE: il repository e il nome del pacchetto di destinazione creati in Artifact Registry. Per configurare il registro Artifact Registry, consulta Configurare Artifact Registry.

Creare e inviare la pipeline di build

Per eseguire la pipeline di personalizzazione delle immagini, invia una build utilizzando gcloud CLI o esegui il deployment della pipeline utilizzando Terraform. Seleziona una delle seguenti schede:

gcloud

Per eseguire il deployment e l'esecuzione della pipeline di personalizzazione delle immagini, esegui il comando gcloud builds submit dalla directory del terminale locale contenente entrambi i file di configurazione:

gcloud builds submit . \
    --config=cloudbuild.yaml \
    --project=PROJECT_ID \
    --service-account="projects/PROJECT_ID/serviceAccounts/SERVICE_ACCOUNT_EMAIL" \
    --region=REGION

Sostituisci quanto segue:

  • PROJECT_ID: il tuo Google Cloud ID progetto.
  • REGION: la Google Cloud regione in cui eseguire il job della pipeline di personalizzazione delle immagini.
  • SERVICE_ACCOUNT_EMAIL: l'indirizzo email del account di servizio configurato con le autorizzazioni IAM richieste.

Questo comando carica lo spazio di lavoro di personalizzazione, registra l'esecuzione di Cloud Build e avvia i container di orchestrazione.

Terraform

Per eseguire il provisioning dell'infrastruttura necessaria per creare e convalidare automaticamente le immagini del sistema operativo personalizzate, puoi utilizzare Terraform. Questa configurazione Terraform completa le seguenti attività:

  • Abilita le API richieste Google Cloud .
  • Crea un bucket Cloud Storage dedicato (workdir_bucket) per archiviare i log temporanei e gli artefatti di build.
  • Configura un trigger Cloud Build (image_builder_trigger) collegato alla connessione del repository GitHub di Developer Connect.

Creare i file di configurazione Terraform

Per organizzare ed eseguire il deployment dell'infrastruttura della pipeline utilizzando Terraform, completa i seguenti passaggi:

  1. Crea una directory dedicata sulla workstation locale o nell'ambiente CI/CD, separata dal repository dell'applicazione, e passa a questa directory:

    mkdir terraform-image-builder && cd terraform-image-builder
    
  2. In questa directory, crea i seguenti cinque file di configurazione Terraform:

    • terraform.tfvars: imposta i valori per le variabili specifiche del progetto.
    • main.tf: esegue il provisioning delle risorse nel tuo Google Cloud progetto, inclusa l'abilitazione delle API richieste, la creazione del bucket di gestione temporanea Cloud Storage (workdir_bucket) e il deployment del trigger di build Cloud Build (image_builder_trigger).
    • outputs.tf: definisce i valori di output visualizzati nel terminale dopo il deployment, come l'ID trigger e il nome del bucket di gestione temporanea.
    • providers.tf: specifica la versione di Terraform richiesta (>= 1.3) e configura il Google Cloud provider (hashicorp/google).
    • variables.tf: definisce le variabili di input, i valori predefiniti e le regole di convalida per il deployment.

    Seleziona una delle seguenti schede per visualizzare e copiare la configurazione di ogni file nella directory locale:

    terraform.tfvars

    Questo file specifica i valori dei parametri per l'ambiente per le variabili dichiarate:

    project_id                = "PROJECT_ID"
    builder_service_account   = "SERVICE_ACCOUNT_EMAIL"
    github_repo_name          = "projects/PROJECT_ID/locations/LOCATION/connections/CONNECTION/repositories/REPO_NAME"
    region                    = "REGION"
    trigger_name              = "TRIGGER_NAME"
    cloudbuild_yaml_path      = "CLOUDBUILD_YAML_PATH"
    image_builder_config_path = "RECIPE_PATH"
    gcs_lifecycle_age_days    = LIFECYCLE_DAYS
    ar_repository_id          = "REPOSITORY_NAME"
    ar_package_name           = "PACKAGE_NAME"
    

    Sostituisci i seguenti segnaposto per le risorse preesistenti:

    • PROJECT_ID: il tuo esistente Google Cloud ID progetto.
    • SERVICE_ACCOUNT_EMAIL: l'indirizzo email del tuo account di servizio di build configurato in Configurare il service account di Image Builder.
    • LOCATION, CONNECTION, e REPO_NAME: la regione host, il nome della connessione e il link del repository di Developer Connect configurati in Connettere un repository.
    • CLOUDBUILD_YAML_PATH: il percorso relativo al file cloudbuild.yaml nella directory locale. Non devi archiviare cloudbuild.yaml nel repository Git.
    • RECIPE_PATH: il percorso relativo al file della ricetta di personalizzazione imagebuilder.yaml archiviato nel repository Git.
    • REPOSITORY_NAME: il repository Artifact Registry generico esistente creato in Configurare Artifact Registry.

    Sostituisci i seguenti segnaposto per le risorse create da Terraform:

    • REGION: la Google Cloudregione di destinazione in cui Terraform esegue il provisioning del bucket di gestione temporanea Cloud Storage e del trigger di build Cloud Build, ad esempio us-central1.
    • TRIGGER_NAME: il nome del nuovo trigger del repository Cloud Build creato da Terraform, ad esempio git-push-os-builder.
    • LIFECYCLE_DAYS: il periodo di conservazione in giorni prima dell'eliminazione automatica degli artefatti intermedi nel bucket di gestione temporanea Cloud Storage creato da Terraform, ad esempio 30.
    • PACKAGE_NAME: il nome che vuoi che Terraform utilizzi per il pacchetto creato all'interno del repository Artifact Registry. Questo pacchetto archivia le versioni delle immagini del sistema operativo pubblicate, ad esempio ubuntu-custom.

    main.tf

    Questo file dichiara le risorse dell'infrastruttura di base e le origini dati per il deployment:

    # Main resource configurations for Image Builder.
    # 1. Enable Required APIs
    resource "google_project_service" "apis" {
      for_each = toset([
        "compute.googleapis.com",
        "cloudbuild.googleapis.com",
        "artifactregistry.googleapis.com",
        "serviceusage.googleapis.com",
        "cloudresourcemanager.googleapis.com",
        "iam.googleapis.com",
        "storage.googleapis.com"
      ])
      project = var.project_id
      service = each.key
      disable_on_destroy = false
    }
    
    # 2. Project data source to retrieve Project Number
    data "google_project" "project" {
      project_id = var.project_id
      depends_on = [google_project_service.apis]
    }
    
    locals {
      builder_sa = var.builder_service_account
    }
    
    # 3. Storage Bucket for Image Builder Workdir
    resource "google_storage_bucket" "workdir_bucket" {
      name                        = var.gcs_bucket_name != "" ? var.gcs_bucket_name : "${var.project_id}-vm-builder-workdir"
      project                     = var.project_id
      location                    = var.region
      force_destroy               = true
      uniform_bucket_level_access = true
      lifecycle_rule {
        action {
          type = "Delete"
        }
        condition {
          age = var.gcs_lifecycle_age_days
        }
      }
      depends_on = [google_project_service.apis]
    }
    
    # 4. Cloud Build Trigger
    resource "google_cloudbuild_trigger" "image_builder_trigger" {
      name        = var.trigger_name
      location    = var.region
      project     = var.project_id
      description = "Trigger that runs Image Builder customization"
    
      service_account = var.builder_service_account != "" ? "projects/${var.project_id}/serviceAccounts/${var.builder_service_account}" : null
    
      repository_event_config {
        repository = replace(var.github_repo_name, "gitRepositoryLinks", "repositories")
        push {
          branch = "^main$"
        }
      }
      filename = var.cloudbuild_yaml_path
    
      substitutions = {
        _GCS_WORKDIR                    = "gs://${google_storage_bucket.workdir_bucket.name}/workdir/"
        _SERVICE_ACCOUNT                = "projects/${var.project_id}/serviceAccounts/${local.builder_sa}"
        _IMAGE_OUTPUT_PATH              = "image-builder/binaryOut"
        _PROJECT_ID                     = var.project_id
        _LOCATION                       = var.region
        _REPOSITORY_NAME                = var.ar_repository_id
        _PACKAGE_NAME                   = var.ar_package_name
        _IMAGE_BUILDER_CONFIG_PATH      = var.image_builder_config_path
        _ARTIFACT_REGISTRY_RESOURCE_URI = "projects/${var.project_id}/locations/${var.region}/repositories/${var.ar_repository_id}/packages/${var.ar_package_name}/versions/v$${BUILD_ID}"
      }
      depends_on = [
        google_project_service.apis
      ]
    }
    

    outputs.tf

    Questo file definisce gli attributi di output restituiti al terminale dopo il deployment:

    output "builder_service_account" {
      value       = local.builder_sa
      description = "The email representation of the resolved Image Builder service account."
    }
    
    output "workdir_bucket" {
      value       = google_storage_bucket.workdir_bucket.name
      description = "The name of the storage workdir bucket."
    }
    
    output "artifact_registry_repository" {
      value       = "projects/${var.project_id}/locations/${var.region}/repositories/${var.ar_repository_id}"
      description = "The fully qualified resource path of the Artifact Registry repository."
    }
    
    output "cloud_build_trigger_id" {
      value       = google_cloudbuild_trigger.image_builder_trigger.trigger_id
      description = "The unique ID for the created Cloud Build Trigger."
    }
    

    providers.tf

    Questo file configura la versione di Terraform e le impostazioni della regione richieste:

    terraform {
      required_version = ">= 1.3"
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = ">= 5.0, < 7.0"
        }
      }
    }
    
    provider "google" {
      project = var.project_id
      region  = var.region
    }
    

    variables.tf

    Questo file dichiara tutte le variabili di input e le regole di convalida obbligatorie e facoltative:

    variable "project_id" {
      type        = string
      description = "The target Project ID where resources will be created."
      validation {
        condition     = can(regex("^[a-z0-9-]{6,30}$", var.project_id))
        error_message = "The project_id must consist of lowercase letters, numbers, and hyphens, and be between 6 and 30 characters."
      }
    }
    
    variable "region" {
      type        = string
      default     = "us-central1"
      description = "Location used for cloud build triggers, storage buckets, and artifact registry."
    }
    
    variable "github_repo_name" {
      type        = string
      default     = ""
      description = "Developer Connect github repository details, format: projects/PROJECT_ID/locations/LOCATION/connections/CONNECTION/repositories/REPO_LINK"
      validation {
        condition     = can(regex("^projects/[^/]+/locations/[^/]+/connections/[^/]+/(gitRepositoryLinks|repositories)/[^/]+$", var.github_repo_name))
        error_message = "The github_repo_name must follow either the Cloud Build v2 repository link format (using '/repositories/') or the Developer Connect resource format (using '/gitRepositoryLinks/')."
      }
    }
    
    variable "builder_service_account" {
      type        = string
      default     = ""
      description = "The email representation of the pre-existing Image Builder service account. If omitted, the default Cloud Build service account will be used."
    }
    
    variable "gcs_bucket_name" {
      type        = string
      default     = ""
      description = "Custom name for the workdir storage bucket. If left empty, a default name using the project ID will be constructed."
    }
    
    variable "gcs_lifecycle_age_days" {
      type        = number
      default     = 30
      description = "The number of days after which temporary logs and artifacts in the storage workdir bucket are deleted."
    }
    
    variable "ar_repository_id" {
      type        = string
      default     = "vm-images"
      description = "The repository ID for the generic Artifact Registry hosting the final OS image tarballs."
    }
    
    variable "ar_package_name" {
      type        = string
      default     = "image-builder"
      description = "The package name under which the generic OS image artifact will be registered in Artifact Registry."
    }
    
    variable "trigger_name" {
      type        = string
      default     = "custom-os-image-builder"
      description = "The name of the Cloud Build trigger."
    }
    
    variable "cloudbuild_yaml_path" {
      type        = string
      default     = "cloudbuild.yaml"
      description = "The path to the cloudbuild.yaml configuration file relative to the repository root."
    }
    
    variable "image_builder_config_path" {
      type        = string
      default     = "imagebuilder.yaml"
      description = "The path to the imagebuilder.yaml configuration file relative to the repository root."
    }
    
  3. Per eseguire il deployment delle configurazioni, esegui i seguenti comandi nella directory contenente i file Terraform:

    1. Inizializza la directory:
      terraform init
    2. Convalida la sintassi:
      terraform validate
    3. Visualizza l'anteprima del deployment:
      terraform plan
    4. Applica la configurazione:
      terraform apply

Verificare e monitorare la build

Per monitorare l'avanzamento della pipeline di build, completa i seguenti passaggi:

  1. Nella Google Cloud console, vai alla pagina Cloud Build.

    Vai a Cloud Build

  2. Nel menu di navigazione, fai clic su Cronologia per visualizzare i job attivi o completati.

  3. Nell'elenco Build, fai clic sull'ID build della build per esaminare i log di esecuzione del container. I log mostrano i passaggi eseguiti all'interno della VM worker, come gli aggiornamenti dei pacchetti di sistema o i comandi shell personalizzati, seguiti dai risultati dei test di convalida della VM di test e dalla registrazione dell'output finale.

Passaggi successivi