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

Configura e invia una pipeline Image Builder in modo programmatico utilizzando Google Cloud CLI o Terraform. La configurazione programmatica della pipeline consente di definire le impostazioni dell'infrastruttura, le immagini del sistema operativo di base, le azioni di personalizzazione e i test di convalida in 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, inclusi l'immagine del sistema operativo di base, le impostazioni dell'infrastruttura 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.

Crea 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 specifiche 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 posizione 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 VM worker ZONE deve trovarsi all'interno di REGION specificato.
    • Per ridurre al minimo la latenza di rete ed evitare addebiti per il traffico in uscita tra regioni diverse, assicurati che la zona della VM worker, il bucket di staging Cloud Storage, il repository Artifact Registry e la posizione di archiviazione delle immagini di destinazione si trovino nella stessa regione.
  • ZONE: una zona che si trova all'interno di REGION specificato, ad esempio us-east1-b o europe-west1-b.

Crea 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 staging 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, questo bucket viene creato automaticamente.
  • PROJECT_ID: il tuo ID progetto Cloud de Confiance .
  • REGION: la regione Cloud de Confiance per il repository Artifact Registry, ad esempio us-east1 o europe-west1.
  • SERVICE_ACCOUNT_EMAIL: l'email del service account che hai configurato con le autorizzazioni IAM richieste.
  • REPOSITORY e PACKAGE: il repository di destinazione e il nome del pacchetto creati in Artifact Registry. Per configurare il registro Artifact Registry, consulta Configurare Artifact Registry.

Crea e invia 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, dalla directory del terminale locale contenente entrambi i file di configurazione, esegui il comando gcloud builds submit:

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 ID progetto Cloud de Confiance .
  • REGION: la regione Cloud de Confiance 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 Cloud de Confiance richieste.
  • Crea un bucket Cloud Storage dedicato (workdir_bucket) per archiviare i log temporanei e gli artefatti di build.
  • Configura un trigger di build Cloud Build (image_builder_trigger) collegato alla connessione al repository GitHub di Developer Connect.

Crea 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 tua 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 progetto Cloud de Confiance , tra cui l'attivazione delle API richieste, la creazione del bucket di staging 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, ad esempio l'ID trigger e il nome del bucket di staging.
    • providers.tf: specifica la versione di Terraform richiesta (>= 1.3) e configura il provider Cloud de Confiance by S3NS (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 ID progetto Cloud de Confiance by S3NS esistente.
    • SERVICE_ACCOUNT_EMAIL: l'indirizzo email delaccount di serviziot di build configurato in Configura il service account di Image Builder.
    • LOCATION, CONNECTION e REPO_NAME: la regione host, il nome della connessione e il link al repository di Developer Connect configurati in Connettere un repository.
    • CLOUDBUILD_YAML_PATH: il percorso relativo del file cloudbuild.yaml nella directory locale. Non devi archiviare cloudbuild.yaml nel tuo repository Git.
    • RECIPE_PATH: il percorso relativo del file di ricetta di personalizzazione imagebuilder.yaml archiviato nel repository Git.
    • REPOSITORY_NAME: il repository Artifact Registry generico esistente creato in Configura Artifact Registry.

    Sostituisci i seguenti segnaposto per le risorse create da Terraform:

    • REGION: la regione di destinazione Cloud de Confiance in cui Terraform esegue il provisioning del bucket di staging 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 che gli artefatti intermedi nel bucket di staging Cloud Storage creato da Terraform vengano eliminati automaticamente, ad esempio 30.
    • PACKAGE_NAME: il nome che vuoi che Terraform utilizzi per il pacchetto creato all'interno del repository Artifact Registry. Questo pacchetto memorizza le versioni dell'immagine sistema operativo pubblicate, ad esempio ubuntu-custom.

    main.tf

    Questo file dichiara le risorse di infrastruttura e le origini dati principali 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 e le impostazioni della regione Terraform 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 obbligatorie e facoltative e le regole di convalida:

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

Verifica e monitora la build

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

  1. Nella Cloud de Confiance 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, ad esempio 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