Crea una canalización de imagen de SO personalizadas con gcloud o Terraform

Configura y envía una canalización de Image Builder de forma programática con Google Cloud CLI o Terraform. Configurar tu canalización de forma programática te permite definir parámetros de configuración de infraestructura, imágenes de SO base, acciones de personalización y pruebas de validación en archivos de configuración declarativos.

Antes de comenzar

Roles obligatorios

Para obtener los permisos que necesitas para crear y enviar canalizaciones de personalización de imágenes con Google Cloud CLI o Terraform, pídele a tu administrador que te otorgue los siguientes roles de IAM en tu proyecto:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

También puedes obtener los permisos necesarios mediante roles personalizados o cualquier otro rol predefinido.

Crea los archivos de configuración.

Para configurar tu canalización con gcloud CLI o Terraform, crea dos archivos de configuración:

  • imagebuilder.yaml: Define la receta de personalización de la imagen, incluida la imagen de SO base, la configuración de la infraestructura de la VM de trabajador, los detalles de salida de la imagen de destino y los pasos de personalización secuenciales, como ejecutar secuencias de comandos de shell, transferir archivos o realizar reinicios.
  • cloudbuild.yaml: Organiza los pasos del proceso de compilación en Cloud Build, incluido el análisis, la validación, la compilación, la prueba y la publicación de la imagen de SO personalizada.

Crea el archivo de configuración de la imagen

Para especificar la configuración de la imagen, crea un archivo llamado imagebuilder.yaml en tu directorio local. Para obtener una lista completa de todos los campos de esquema y las acciones de personalización compatibles, consulta Esquema de recetas de personalización y Acciones de personalización compatibles.

En el siguiente archivo imagebuilder.yaml de muestra, se configura una canalización que compila una imagen personalizada de Ubuntu 22.04 LTS con una VM de trabajador e2-standard-4 en la región y la zona especificadas, y realiza una actualización del paquete del 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"

Reemplaza los siguientes valores de marcador de posición:

  • PROJECT_ID: ID del proyecto
  • REGION: la ubicación de almacenamiento de la imagen de destino, por ejemplo, us-east1 o europe-west1. Asegúrate de cumplir con los siguientes requisitos regionales y zonales:
    • Image Builder solo es compatible con las regiones en las que está disponible Cloud Build.
    • La VM de trabajador ZONE debe ubicarse dentro de la REGION especificada.
    • Para minimizar la latencia de la red y evitar los cargos de salida entre regiones, asegúrate de que la zona de la VM de trabajador, el bucket de preparación de Cloud Storage, el repositorio de Artifact Registry y la ubicación de almacenamiento de la imagen de destino estén ubicados en la misma región.
  • ZONE: una zona ubicada dentro de la REGION especificada, por ejemplo, us-east1-b o europe-west1-b.

Crea el archivo de compilación del organizador

Crea un archivo llamado cloudbuild.yaml en el mismo directorio. Este archivo llama a los pasos del contenedor de Image Builder para compilar, validar y publicar la imagen de SO personalizada.

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'

Reemplaza los siguientes valores de marcador de posición:

  • STAGING_BUCKET_NAME: un bucket de Cloud Storage existente en tu proyecto para usar como un espacio de trabajo de preparación temporal. Si no tienes un bucket, puedes crear uno ejecutando gcloud storage buckets create gs://STAGING_BUCKET_NAME. Si implementas tu canalización con Terraform, Terraform crea este bucket automáticamente.
  • PROJECT_ID: Es el ID del Google Cloud proyecto de.
  • REGION: Es la Google Cloud región de tu repositorio de Artifact Registry, por ejemplo, us-east1 o europe-west1.
  • SERVICE_ACCOUNT_EMAIL: Es el correo electrónico de la cuenta de servicio que configuraste con los permisos de IAM obligatorios.
  • REPOSITORY y PACKAGE: Son el repositorio de destino y el nombre del paquete creados en Artifact Registry. Para configurar el registro de Artifact Registry, consulta Configura Artifact Registry.

Crea y envía la canalización de compilación

Para ejecutar tu canalización de personalización de imágenes, envía una compilación con gcloud CLI o implementa tu canalización con Terraform. Selecciona una de las siguientes pestañas:

gcloud

Para implementar y ejecutar tu canalización de personalización de imágenes, desde el directorio de la terminal local que contiene ambos archivos de configuración, ejecuta el gcloud builds submit comando:

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

Reemplaza lo siguiente:

  • PROJECT_ID: Es el ID del Google Cloud proyecto de.
  • REGION: Es la Google Cloud región en la que se ejecutará el trabajo de tu canalización de personalización de imágenes.
  • SERVICE_ACCOUNT_EMAIL: Es la dirección de correo electrónico de la cuenta de servicio configurada con los permisos de IAM obligatorios.

Este comando sube tu espacio de trabajo de personalización, registra la ejecución de Cloud Build y lanza los contenedores de organización.

Terraform

Para aprovisionar la infraestructura necesaria para compilar y validar automáticamente imágenes de SO personalizadas, puedes usar Terraform. Esta configuración de Terraform completa las siguientes tareas:

  • Habilita las APIs obligatorias Google Cloud .
  • Crea un bucket de Cloud Storage dedicado (workdir_bucket) para almacenar registros temporales y artefactos de compilación.
  • Configura un activador de compilación de Cloud Build (image_builder_trigger) vinculado a la conexión de tu repositorio de GitHub de Developer Connect.

Crea tus archivos de configuración de Terraform

Para organizar e implementar la infraestructura de tu canalización con Terraform, completa los siguientes pasos:

  1. Crea un directorio dedicado en tu estación de trabajo local o entorno de CI/CD, separado de tu repositorio de aplicaciones, y cámbialo:

    mkdir terraform-image-builder && cd terraform-image-builder
    
  2. En este directorio, crea los siguientes cinco archivos de configuración de Terraform:

    • terraform.tfvars: Establece valores para las variables específicas del proyecto.
    • main.tf: Aprovisiona recursos en tu Google Cloud proyecto, lo que incluye habilitar las APIs obligatorias, crear el bucket de preparación de Cloud Storage (workdir_bucket) y, también, implementar el activador de compilación de Cloud Build (image_builder_trigger).
    • outputs.tf: Define los valores de resultado que se muestran en tu terminal después de la implementación, como el ID del activador y el nombre del bucket de preparación.
    • providers.tf: especifica la versión de Terraform requerida (>= 1.3) y configura el Google Cloud proveedor (hashicorp/google).
    • variables.tf: Define las variables de entrada, los valores predeterminados y las reglas de validación para la implementación.

    Selecciona una de las siguientes pestañas para ver y copiar la configuración de cada archivo en tu directorio local:

    terraform.tfvars

    Este archivo especifica los valores de los parámetros para tu entorno para las variables declaradas:

    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"
    

    Reemplaza los siguientes marcadores de posición para tus recursos preexistentes:

    • PROJECT_ID: Es el ID de tu proyecto existente Google Cloud .
    • SERVICE_ACCOUNT_EMAIL: Es la dirección de correo electrónico de tu cuenta de servicio de compilación configurada en Configura la cuenta de servicio de Image Builder.
    • LOCATION, CONNECTION, y REPO_NAME: Son la región de host, el nombre de la conexión y el vínculo del repositorio de Developer Connect configurados en Conecta un repositorio.
    • CLOUDBUILD_YAML_PATH: Es la ruta de acceso relativa a tu archivo cloudbuild.yaml en tu directorio local. No es necesario que registres cloudbuild.yaml en tu repositorio de Git.
    • RECIPE_PATH: Es la ruta de acceso relativa a tu archivo de receta de personalización imagebuilder.yaml registrado en tu repositorio de Git.
    • REPOSITORY_NAME: Es el repositorio genérico de Artifact Registry existente creado en Configura Artifact Registry.

    Reemplaza los siguientes marcadores de posición para los recursos que crea Terraform:

    • REGION: Es la Google Cloudregión de destino en la que Terraform aprovisiona el bucket de preparación de Cloud Storage y el activador de compilación de Cloud Build, por ejemplo, us-central1.
    • TRIGGER_NAME: Es el nombre del nuevo activador del repositorio de Cloud Build creado por Terraform, por ejemplo, git-push-os-builder.
    • LIFECYCLE_DAYS: Es el período de retención en días antes de que se borren automáticamente los artefactos intermedios en el bucket de preparación de Cloud Storage creado por Terraform, por ejemplo, 30.
    • PACKAGE_NAME: Es el nombre que deseas que Terraform use para el paquete creado dentro de tu repositorio de Artifact Registry. Este paquete almacena versiones publicadas de imagen de SO, por ejemplo, ubuntu-custom.

    main.tf

    Este archivo declara los recursos de infraestructura y las fuentes de datos principales para la implementación:

    # 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

    Este archivo define los atributos de salida que se muestran en tu terminal después de la implementación:

    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

    Este archivo configura la versión de Terraform y la configuración de región requeridas:

    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

    Este archivo declara todas las variables de entrada y las reglas de validación obligatorias y opcionales:

    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. Para implementar las configuraciones, ejecuta los siguientes comandos en el directorio que contiene tus archivos de Terraform:

    1. Inicializa el directorio:
      terraform init
    2. Valida la sintaxis:
      terraform validate
    3. Obtén una vista previa de la implementación:
      terraform plan
    4. Aplica la configuración:
      terraform apply

Verifica y supervisa la compilación

Para hacer un seguimiento del progreso de tu canalización de compilación, completa los siguientes pasos:

  1. En la Google Cloud consola, ve a la página de Cloud Build.

    Ir a Cloud Build

  2. En el menú de navegación, haz clic en Historial para ver los trabajos activos o completados.

  3. En la lista Compilaciones, haz clic en el ID de compilación de tu compilación para inspeccionar los registros de ejecución del contenedor. En los registros, se muestran los pasos que se realizan dentro de la VM de trabajador, como las actualizaciones de paquetes del sistema o los comandos de shell personalizados, seguidos de los resultados de las pruebas de validación de la VM de prueba y el registro de salida final.

¿Qué sigue?