Créer un pipeline d'image d'OS personnalisée à l'aide de gcloud ou de Terraform

Configurez et envoyez un pipeline Image Builder par programmation à l'aide de la Google Cloud CLI ou de Terraform. La configuration programmatique de votre pipeline vous permet de définir les paramètres d'infrastructure, les images de système d'exploitation de base, les actions de personnalisation et les tests de validation dans des fichiers de configuration déclaratifs.

Avant de commencer

  • Suivez les étapes de configuration de l'environnement décrites dans Préparer votre environnement.
  • Si vous prévoyez de déployer votre pipeline à l'aide de Terraform ou d'automatiser les compilations à partir d'un dépôt, connectez votre dépôt GitHub, GitLab ou Bitbucket à l'aide des dépôts Cloud Build (2nd gen) ou des liens de connexion Developer Connect.
  • Si vous prévoyez d'utiliser Terraform, installez la CLI Terraform version 1.3 ou ultérieure.
  • Si ce n'est pas déjà fait, configurez l'authentification. L'authentification permet de valider votre identité pour accéder aux Google Cloud services et aux API. Pour exécuter du code ou des exemples depuis un environnement de développement local, vous pouvez vous authentifier auprès de Compute Engine en sélectionnant l'une des options suivantes :

    Sélectionnez l'onglet correspondant à la façon dont vous prévoyez d'utiliser les exemples de cette page :

    gcloud

    1. Installez la Google Cloud CLI. Une fois que la Google Cloud CLI est installée, initialisezla en exécutant la commande suivante :

      gcloud init

      Si vous utilisez un fournisseur d'identité (IdP) externe, vous devez d'abord vous connecter à la gcloud CLI avec votre identité fédérée.

  • Définissez une région et une zone par défaut.
  • Terraform

    Pour utiliser les exemples Terraform de cette page dans un environnement de développement local, installez et initialisez la gcloud CLI, puis configurez le service Identifiants par défaut de l'application avec vos identifiants utilisateur.

    1. Installez la Google Cloud CLI.

    2. Si vous utilisez un fournisseur d'identité (IdP) externe, vous devez d'abord vous connecter à la gcloud CLI avec votre identité fédérée.

    3. Si vous utilisez un shell local, créez des identifiants d'authentification locaux pour votre compte utilisateur : Créer des identifiants d'authentification locaux pour votre compte utilisateur :

      gcloud auth application-default login

      Vous n'avez pas besoin de le faire si vous utilisez Cloud Shell.

      Si une erreur d'authentification est renvoyée et que vous utilisez un fournisseur d'identité (IdP) externe, vérifiez que vous vous êtes connecté à la gcloud CLI avec votre identité fédérée.

    Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

Rôles requis

Pour obtenir les autorisations nécessaires pour créer et envoyer des pipelines de personnalisation d'images à l'aide de la Google Cloud CLI ou de Terraform, demandez à votre administrateur de vous accorder les rôles IAM suivants sur votre projet :

Pour en savoir plus sur l'attribution de rôles, consultez la page Gérer l'accès aux projets, aux dossiers et aux organisations.

Vous pouvez également obtenir les autorisations requises avec des rôles personnalisés ou d'autres rôles prédéfinis.

Créer des fichiers de configuration

Pour configurer votre pipeline à l'aide de la gcloud CLI ou de Terraform, créez deux fichiers de configuration :

  • imagebuilder.yaml: définit la recette de personnalisation de l'image, y compris l'image de système d'exploitation de base, les paramètres d'infrastructure de la VM de nœud de calcul, les détails de sortie de l'image cible et les étapes de personnalisation séquentielles, telles que l'exécution de scripts shell, le transfert de fichiers ou le redémarrage.
  • cloudbuild.yaml: orchestre les étapes du processus de compilation dans Cloud Build, y compris l'analyse, la validation, la compilation, le test et la publication de l'image de système d'exploitation personnalisée.

Créer le fichier de configuration de l'image

Pour spécifier la configuration de votre image, créez un fichier nommé imagebuilder.yaml dans votre répertoire local. Pour obtenir la liste complète de tous les champs de schéma et actions de personnalisation compatibles, consultez Schéma de la recette de personnalisation et Actions de personnalisation compatibles.

L'exemple de fichier imagebuilder.yaml suivant configure un pipeline qui crée une image Ubuntu 22.04 LTS personnalisée à l'aide d'une VM de nœud de calcul e2-standard-4 dans la région et la zone spécifiées, et effectue une mise à jour du package système.

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"

Remplacez les valeurs d'espace réservé suivantes :

  • PROJECT_ID : ID de votre projet.
  • REGION: emplacement de stockage de l'image cible, par exemple us-east1 ou europe-west1. Assurez-vous de respecter les exigences régionales et zonales suivantes :
    • Image Builder n'est compatible que dans les régions où Cloud Build est disponible.
    • La ZONE de la VM de nœud de calcul doit se trouver dans la REGION spécifiée.
    • Pour minimiser la latence du réseau et éviter les frais de sortie interrégionaux, assurez-vous que la zone de votre VM de nœud de calcul, le bucket de préproduction Cloud Storage, le dépôt Artifact Registry et l'emplacement de stockage de l'image cible sont colocalisés dans la même région.
  • ZONE : zone située dans la REGION spécifiée, par exemple us-east1-b ou europe-west1-b.

Créer le fichier de compilation de l'orchestrateur

Créez un fichier nommé cloudbuild.yaml dans le même répertoire. Ce fichier appelle les étapes du conteneur Image Builder pour créer, valider et publier l'image de système d'exploitation personnalisée.

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'

Remplacez les valeurs d'espace réservé suivantes :

  • STAGING_BUCKET_NAME: bucket Cloud Storage existant dans votre projet à utiliser comme espace de travail de préproduction temporaire. Si vous n'avez pas de bucket, vous pouvez en créer un en exécutant gcloud storage buckets create gs://STAGING_BUCKET_NAME. Si vous déployez votre pipeline à l'aide de Terraform, Terraform crée automatiquement ce bucket.
  • PROJECT_ID: ID de votre Google Cloud projet.
  • REGION : Google Cloud région de votre dépôt Artifact Registry, par exemple us-east1 ou europe-west1.
  • SERVICE_ACCOUNT_EMAIL : adresse e-mail du compte de service que vous avez configuré avec les autorisations IAM requises.
  • REPOSITORY et PACKAGE : dépôt cible et nom du package créés dans Artifact Registry. Pour configurer le registre Artifact Registry, consultez Configurer Artifact Registry.

Créer et envoyer le pipeline de compilation

Pour exécuter votre pipeline de personnalisation d'images, envoyez une compilation à l'aide de la gcloud CLI ou déployez votre pipeline à l'aide de Terraform. Sélectionnez l'un des onglets suivants :

gcloud

Pour déployer et exécuter votre pipeline de personnalisation d'images, exécutez la commande gcloud builds submit à partir du répertoire de votre terminal local contenant les deux fichiers de configuration :

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

Remplacez les éléments suivants :

  • PROJECT_ID: ID de votre Google Cloud projet.
  • REGION : Google Cloud région dans laquelle exécuter le job de votre pipeline de personnalisation d'images.
  • SERVICE_ACCOUNT_EMAIL: adresse e-mail du compte de service configuré avec les autorisations IAM requises.

Cette commande importe votre espace de travail de personnalisation, enregistre l'exécution de Cloud Build et lance les conteneurs d'orchestration.

Terraform

Pour provisionner l'infrastructure requise pour créer et valider automatiquement des images de système d'exploitation personnalisées, vous pouvez utiliser Terraform. Cette configuration Terraform effectue les tâches suivantes :

  • Active les API requises Google Cloud .
  • Crée un bucket Cloud Storage dédié (workdir_bucket) pour stocker les journaux temporaires et les artefacts de compilation.
  • Configure un déclencheur de compilation Cloud Build (image_builder_trigger) associé à votre connexion de dépôt GitHub Developer Connect.

Créer vos fichiers de configuration Terraform

Pour organiser et déployer votre infrastructure de pipeline à l'aide de Terraform, procédez comme suit :

  1. Créez un répertoire dédié sur votre poste de travail local ou dans votre environnement CI/CD, distinct de votre dépôt d'application, puis accédez-y :

    mkdir terraform-image-builder && cd terraform-image-builder
    
  2. Dans ce répertoire, créez les cinq fichiers de configuration Terraform suivants :

    • terraform.tfvars : définit les valeurs des variables spécifiques au projet.
    • main.tf : provisionne les ressources dans votre Google Cloud projet, y compris l'activation des API requises, la création du bucket de préproduction Cloud Storage (workdir_bucket) et le déploiement du déclencheur de compilation Cloud Build (image_builder_trigger).
    • outputs.tf: définit les valeurs de sortie affichées dans votre terminal après le déploiement, telles que l'ID du déclencheur et le nom du bucket de préproduction.
    • providers.tf : spécifie la version Terraform requise (>= 1.3) et configure le Google Cloud fournisseur (hashicorp/google).
    • variables.tf: définit les variables d'entrée, les valeurs par défaut et les règles de validation pour le déploiement.

    Sélectionnez l'un des onglets suivants pour afficher et copier la configuration de chaque fichier dans votre répertoire local :

    terraform.tfvars

    Ce fichier spécifie les valeurs des paramètres de votre environnement pour les variables déclarées :

    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"
    

    Remplacez les espaces réservés suivants pour vos ressources préexistantes :

    • PROJECT_ID : ID de votre projet existant Google Cloud .
    • SERVICE_ACCOUNT_EMAIL : adresse e-mail de votre compte de service de compilation configuré dans Configurer le compte de service Image Builder.
    • LOCATION, CONNECTION, et REPO_NAME : région hôte, nom de la connexion et lien du dépôt Developer Connect configurés dans Connecter un dépôt.
    • CLOUDBUILD_YAML_PATH: chemin d'accès relatif à votre fichier cloudbuild.yaml dans votre répertoire local. Vous n'avez pas besoin d'archiver cloudbuild.yaml dans votre dépôt Git.
    • RECIPE_PATH: chemin d'accès relatif à votre fichier de recette de personnalisation imagebuilder.yaml archivé dans votre dépôt Git.
    • REPOSITORY_NAME : dépôt Artifact Registry générique existant créé dans Configurer Artifact Registry.

    Remplacez les espaces réservés suivants pour les ressources créées par Terraform :

    • REGION : région cible dans laquelle Terraform provisionne le bucket de préproduction Cloud Storage et le déclencheur de compilation Cloud Build, par exemple us-central1. Google Cloud
    • TRIGGER_NAME: nom du nouveau déclencheur de dépôt Cloud Build créé par Terraform, par exemple git-push-os-builder.
    • LIFECYCLE_DAYS: période de conservation en jours avant la suppression automatique des artefacts intermédiaires dans le bucket de préproduction Cloud Storage créé par Terraform, par exemple 30.
    • PACKAGE_NAME : nom que vous souhaitez que Terraform utilise pour le package créé dans votre dépôt Artifact Registry. Ce package stocke les versions d'image de système d'exploitation publiées, par exemple ubuntu-custom.

    main.tf

    Ce fichier déclare les ressources d'infrastructure et les sources de données principales pour le déploiement :

    # 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

    Ce fichier définit les attributs de sortie renvoyés à votre terminal après le déploiement :

    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

    Ce fichier configure les paramètres de version et de région Terraform requis :

    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

    Ce fichier déclare toutes les variables d'entrée et règles de validation obligatoires et facultatives :

    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. Pour déployer les configurations, exécutez les commandes suivantes dans le répertoire contenant vos fichiers Terraform :

    1. Initialisez le répertoire :
      terraform init
    2. Validez la syntaxe :
      terraform validate
    3. Prévisualisez le déploiement :
      terraform plan
    4. Appliquez la configuration :
      terraform apply

Vérifier et surveiller la compilation

Pour suivre la progression de votre pipeline de compilation, procédez comme suit :

  1. Dans la Google Cloud console, accédez à la page Cloud Build.

    Accéder à Cloud Build

  2. Dans le menu de navigation, cliquez sur Historique pour afficher les tâches actives ou terminées.

  3. Dans la liste Compilations, cliquez sur l'ID de compilation de votre compilation pour inspecter les journaux d'exécution du conteneur. Les journaux affichent les étapes effectuées dans la VM de nœud de calcul, telles que les mises à jour du package système ou les commandes shell personnalisées, suivies des résultats des tests de validation de la VM de test et de l'enregistrement de la sortie finale.

Étape suivante