Criar um pipeline de imagem do SO personalizada usando gcloud ou Terraform

Configure e envie um programa de pipeline do Image Builder de maneira programática usando a Google Cloud CLI ou o Terraform. A configuração programática do pipeline permite definir as configurações de infraestrutura, imagens de SO de base, ações de personalização e testes de validação em arquivos de configuração declarativos.

Antes de começar

Funções exigidas

Para ter as permissões necessárias para criar e enviar pipelines de personalização de imagens usando a Google Cloud CLI ou o Terraform, peça ao administrador para conceder a você os seguintes papéis do IAM no seu projeto:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Também é possível conseguir as permissões necessárias com papéis personalizados ou outros papéis predefinidos.

Crie os arquivos de configuração.

Para configurar o pipeline usando a CLI gcloud ou o Terraform, crie dois arquivos de configuração:

  • imagebuilder.yaml: define a receita de personalização da imagem, incluindo a imagem do SO de base, as configurações de infraestrutura da VM de worker, os detalhes de saída da imagem de destino e as etapas de personalização sequenciais, como a execução de scripts de shell, a transferência de arquivos ou a realização de reinicializações.
  • cloudbuild.yaml: orquestra as etapas do processo de build no Cloud Build, incluindo a análise, validação, criação, teste e publicação da imagem do SO personalizada.

Criar o arquivo de configuração da imagem

Para especificar a configuração da imagem, crie um arquivo chamado imagebuilder.yaml no diretório local. Para uma lista completa de todos os campos de esquema e ações de personalização compatíveis, consulte Esquema de receita de personalização e Ações de personalização compatíveis.

O exemplo de arquivo imagebuilder.yaml a seguir configura um pipeline que cria uma imagem personalizada do Ubuntu 22.04 LTS usando uma VM de worker e2-standard-4 na região e zona especificadas e executa uma atualização do pacote do 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"

Substitua os seguintes valores de marcador de posição:

  • PROJECT_ID: o ID do projeto.
  • REGION: o local de armazenamento da imagem de destino, por exemplo, us-east1 ou europe-west1. Verifique se você atende aos seguintes requisitos regionais e zonais:
    • O Image Builder só é compatível com regiões em que o Cloud Build está disponível.
    • A VM de worker ZONE precisa estar localizada na REGION especificada.
    • Para minimizar a latência da rede e evitar cobranças de saída entre regiões, verifique se a zona da VM de worker, o bucket de preparo do Cloud Storage, o repositório do Artifact Registry e o local de armazenamento da imagem de destino estão localizados na mesma região.
  • ZONE: uma zona localizada na REGION especificada, por exemplo, us-east1-b ou europe-west1-b.

Criar o arquivo de build do orquestrador

Crie um arquivo chamado cloudbuild.yaml no mesmo diretório. Esse arquivo chama as etapas do contêiner do Image Builder para criar, validar e publicar a imagem do 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'

Substitua os seguintes valores de marcador de posição:

  • STAGING_BUCKET_NAME: um bucket do Cloud Storage no seu projeto para usar como um espaço de trabalho de preparo temporário. Se você não tiver um bucket, crie um executando gcloud storage buckets create gs://STAGING_BUCKET_NAME. Se você implantar o pipeline usando o Terraform, ele vai criar esse bucket automaticamente.
  • PROJECT_ID: o ID do Google Cloud projeto.
  • REGION: Google Cloud a região do repositório do Artifact Registry, por exemplo, us-east1 ou europe-west1.
  • SERVICE_ACCOUNT_EMAIL: o e-mail da conta de serviço que você configurou com as permissões necessárias do IAM.
  • REPOSITORY e PACKAGE: o repositório de destino e o nome do pacote criados no Artifact Registry. Para configurar o registro do Artifact Registry, consulte Configurar o Artifact Registry.

Criar e enviar o pipeline de build

Para executar o pipeline de personalização de imagens, envie um build usando a CLI gcloud ou implante o pipeline usando o Terraform. Selecione uma das seguintes guias:

gcloud

Para implantar e executar o pipeline de personalização de imagens, no diretório do terminal local que contém os dois arquivos de configuração, execute o gcloud builds submit comando:

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

Substitua:

  • PROJECT_ID: o ID do Google Cloud projeto.
  • REGION: a Google Cloud região em que você quer executar o job do pipeline de personalização de imagens.
  • SERVICE_ACCOUNT_EMAIL: o endereço de e-mail da conta de serviço configurada com as permissões necessárias do IAM.

Esse comando faz o upload do espaço de trabalho de personalização, registra a execução do Cloud Build e inicia os contêineres de orquestração.

Terraform

Para provisionar a infraestrutura necessária para criar e validar automaticamente imagens de SO personalizadas, use o Terraform. Essa configuração do Terraform conclui as seguintes tarefas:

  • Ativa as APIs necessárias Google Cloud .
  • Cria um bucket do Cloud Storage dedicado (workdir_bucket) para armazenar registros temporários e artefatos de build.
  • Configura um gatilho de build do Cloud Build (image_builder_trigger) vinculado à conexão do repositório do GitHub do Developer Connect.

Criar os arquivos de configuração do Terraform

Para organizar e implantar a infraestrutura do pipeline usando o Terraform, siga estas etapas:

  1. Crie um diretório dedicado na estação de trabalho local ou no ambiente de CI/CD, separado do repositório do aplicativo, e acesse-o:

    mkdir terraform-image-builder && cd terraform-image-builder
    
  2. Nesse diretório, crie os cinco arquivos de configuração do Terraform a seguir:

    • terraform.tfvars: define valores para variáveis específicas do projeto.
    • main.tf: provisiona recursos no seu Google Cloud projeto, incluindo a ativação das APIs necessárias, a criação do bucket de preparo do Cloud Storage (workdir_bucket) e a implantação do gatilho de build do Cloud Build (image_builder_trigger).
    • outputs.tf: define os valores de saída exibidos no terminal após a implantação, como o ID do acionador e o nome do bucket de preparo.
    • providers.tf: especifica a versão necessária do Terraform (>= 1.3) e configura o Google Cloud provedor (hashicorp/google).
    • variables.tf: define variáveis de entrada, valores padrão e regras de validação para a implantação.

    Selecione uma das seguintes guias para visualizar e copiar a configuração de cada arquivo para o diretório local:

    terraform.tfvars

    Esse arquivo especifica valores de parâmetros para o ambiente das variáveis 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"
    

    Substitua os seguintes marcadores de posição pelos recursos preexistentes:

    • PROJECT_ID: o ID do projeto existente Google Cloud .
    • SERVICE_ACCOUNT_EMAIL: o endereço de e-mail da sua conta de serviço de build configurada em Configurar a conta de serviço do Image Builder.
    • LOCATION, CONNECTION, e REPO_NAME: a região do host, o nome da conexão e o link do repositório do Developer Connect configurados em Conectar um repositório.
    • CLOUDBUILD_YAML_PATH: o caminho relativo para o arquivo cloudbuild.yaml no diretório local. Não é necessário fazer check-in de cloudbuild.yaml no repositório Git.
    • RECIPE_PATH: o caminho relativo para o arquivo de receita de personalização imagebuilder.yaml que foi feito check-in no repositório Git.
    • REPOSITORY_NAME: o repositório genérico do Artifact Registry criado em Configurar o Artifact Registry.

    Substitua os seguintes marcadores de posição pelos recursos que o Terraform cria:

    • REGION: a região de destino Google Cloudem que o Terraform provisiona o bucket de preparo do Cloud Storage e o gatilho de build do Cloud Build, por exemplo, us-central1.
    • TRIGGER_NAME: o nome do novo acionador do repositório do Cloud Build criado pelo Terraform, por exemplo, git-push-os-builder.
    • LIFECYCLE_DAYS: o período de armazenamento em dias antes que os artefatos intermediários no bucket de preparo do Cloud Storage criado pelo Terraform sejam excluídos automaticamente, por exemplo, 30.
    • PACKAGE_NAME: o nome que você quer que o Terraform use para o pacote criado no repositório do Artifact Registry. Esse pacote armazena versões publicadas da imagem do SO, por exemplo, ubuntu-custom.

    main.tf

    Esse arquivo declara os recursos de infraestrutura e as fontes de dados principais para a implantação:

    # 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

    Esse arquivo define os atributos de saída retornados ao terminal após a implantação:

    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

    Esse arquivo configura a versão necessária do Terraform e as configurações de região:

    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

    Esse arquivo declara todas as variáveis de entrada e regras de validação obrigatórias e opcionais:

    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 implantar as configurações, execute os seguintes comandos no diretório que contém os arquivos do Terraform:

    1. Inicialize o diretório:
      terraform init
    2. Valide a sintaxe:
      terraform validate
    3. Visualize a implantação:
      terraform plan
    4. Aplique a configuração:
      terraform apply

Verificar e monitorar o build

Para acompanhar o progresso do pipeline de build, siga estas etapas:

  1. No Google Cloud console, acesse a página Cloud Build.

    Acessar o Cloud Build

  2. No menu de navegação, clique em Histórico para visualizar jobs ativos ou concluídos.

  3. Na lista Builds, clique no ID do build para inspecionar os registros de execução do contêiner. Os registros mostram as etapas que estão sendo realizadas na VM de worker, como atualizações de pacotes do sistema ou comandos de shell personalizados, seguidas pelos resultados do teste de validação da VM de teste e pelo registro de saída final.

A seguir