Aller au contenu

Pipeline CI/CD avec Packer

Intégrer Packer dans un pipeline CI/CD garantit que chaque image est construite, testée et publiee de manière reproductible sans intervention manuelle.


Principe du pipeline

validate
   |
   v
build (packer build)
   |
   v
test (Goss / Inspec)
   |
   v
publish (manifest, tag, registre)

Chaque étape dépend du succès de la précédente. En cas d'échec, le pipeline s'arrêté et aucun artefact n'est publie.


GitHub Actions

Exemple de workflow avec deux jobs : validation du template puis build et push.

# .github/workflows/packer.yml
name: Packer Build

on:
  push:
    branches: [main]
    paths:
      - "packer/**"
  pull_request:
    paths:
      - "packer/**"

env:
  PACKER_VERSION: "1.10.0"

jobs:
  validate:
    name: Validate template
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Packer
        uses: hashicorp/setup-packer@main
        with:
          version: ${{ env.PACKER_VERSION }}

      - name: Init plugins
        run: packer init packer/

      - name: Format check
        run: packer fmt -check packer/

      - name: Validate
        run: packer validate packer/
        env:
          PKR_VAR_project_id: ${{ vars.GCP_PROJECT_ID }}

  build:
    name: Build image
    needs: validate
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Authenticate to GCP
        uses: google-github-actions/auth@v2
        with:
          credentials_json: ${{ secrets.GCP_SA_KEY }}

      - name: Setup Packer
        uses: hashicorp/setup-packer@main
        with:
          version: ${{ env.PACKER_VERSION }}

      - name: Init plugins
        run: packer init packer/

      - name: Build
        run: packer build packer/
        env:
          PKR_VAR_project_id: ${{ vars.GCP_PROJECT_ID }}
          PKR_VAR_region: ${{ vars.GCP_REGION }}

      - name: Upload manifest
        uses: actions/upload-artifact@v4
        with:
          name: packer-manifest
          path: packer/manifest.json

Le job build ne s'exécuté que sur la branche main pour éviter de consommer des ressources cloud sur chaque pull request.


GitLab CI

Exemple équivalent pour GitLab CI avec deux stages.

# .gitlab-ci.yml
variables:
  PACKER_VERSION: "1.10.0"
  PACKER_DIR: "packer"

stages:
  - validate
  - build

.packer-base:
  image: hashicorp/packer:${PACKER_VERSION}
  before_script:
    - packer init ${PACKER_DIR}/

validate:
  extends: .packer-base
  stage: validate
  script:
    - packer fmt -check ${PACKER_DIR}/
    - packer validate ${PACKER_DIR}/
  variables:
    PKR_VAR_project_id: ${GCP_PROJECT_ID}

build:
  extends: .packer-base
  stage: build
  script:
    - packer build ${PACKER_DIR}/
  variables:
    PKR_VAR_project_id: ${GCP_PROJECT_ID}
    PKR_VAR_region: ${GCP_REGION}
  artifacts:
    paths:
      - packer/manifest.json
    expire_in: 7 days
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Les variables GCP_PROJECT_ID et GCP_REGION sont définies dans Settings > CI/CD > Variables de GitLab. Les secrets (compte de service) sont marques comme proteges et masques.


GCP Cloud Build

Cloud Build est le service CI/CD natif de GCP. Il s'intégré nativement avec les comptes de service et les rôles IAM.

# cloudbuild.yaml
steps:
  - name: "hashicorp/packer:1.10.0"
    id: packer-init
    args: ["init", "packer/"]

  - name: "hashicorp/packer:1.10.0"
    id: packer-validate
    args: ["validate", "packer/"]
    env:
      - "PKR_VAR_project_id=$PROJECT_ID"

  - name: "hashicorp/packer:1.10.0"
    id: packer-build
    args: ["build", "packer/"]
    env:
      - "PKR_VAR_project_id=$PROJECT_ID"
      - "PKR_VAR_region=europe-west1"

artifacts:
  objects:
    location: "gs://${_ARTIFACTS_BUCKET}/packer/"
    paths:
      - "packer/manifest.json"

Le compte de service Cloud Build doit avoir les rôles roles/compute.instanceAdmin.v1 et roles/iam.serviceAccountUser pour créer des instances et capturer des images.

Pour la configuration complète de Cloud Build avec GCP, voir la page DevOps GCP.


Bonnes pratiques

Variables d'environnement PKR_VAR_

Toutes les variables Packer peuvent être passees via des variables d'environnement prefixees PKR_VAR_. Cela evite de passer des valeurs sensibles en clair dans les commandes.

export PKR_VAR_project_id="mon-projet"
export PKR_VAR_sa_key_path="/run/secrets/sa.json"
packer build packer/

Post-processor manifest

Activer le post-processor manifest pour tracer les artefacts produits par chaque build. Le fichier JSON peut être archivé comme artefact CI ou pousse dans un bucket.

build {
  sources = ["source.googlecompute.base"]

  # ... provisioners ...

  post-processor "manifest" {
    output     = "manifest.json"
    strip_path = true
    custom_data = {
      git_commit = "${env("CI_COMMIT_SHA")}"
      pipeline   = "${env("CI_PIPELINE_ID")}"
    }
  }
}

Builds parallèles

Packer peut construire plusieurs sources en parallèle dans un même bloc build. Cela réduit significativement la durée totale pour des images multi-regions ou multi-providers.

build {
  sources = [
    "source.googlecompute.europe",
    "source.googlecompute.us",
    "source.amazon-ebs.eu-west",
  ]

  provisioner "shell" {
    script = "scripts/base.sh"
  }
}

Les trois images sont construites simultanément. Les provisioners s'appliquent à chaque source independamment.