Aller au contenu

Intégration

Pipeline IaC combinant OpenTofu, Packer et Ansible pour un workflow complet.


Le triptyque IaC

Chaque outil a un rôle précis dans la chaîne d'automatisation :

Outil Rôle Quand
Packer Créer des images machine Build-time
Ansible Configurer les machines Build-time (dans Packer) ou deploy-time
OpenTofu Provisionner l'infrastructure Deploy-time
┌────────────┐     ┌──────────┐     ┌──────────┐
│   Packer   │  →  │ OpenTofu │  →  │ Ansible  │
│ + Ansible  │     │          │     │ (day-2)  │
│  (image)   │     │  (infra) │     │ (config) │
└────────────┘     └──────────┘     └──────────┘
   Build-time        Deploy-time      Post-deploy

Packer → OpenTofu

Packer produit une image, OpenTofu l'utilisé pour créer des instances.

1. Packer construit l'image

cd packer/
packer build .
# Produit : docker-server-1712345678 (famille docker-server)

2. OpenTofu référence l'image

# Recuperer la derniere image de la famille
data "google_compute_image" "docker_server" {
  family  = "docker-server"
  project = var.project_id
}

resource "google_compute_instance" "app" {
  name         = "app-server"
  machine_type = "e2-medium"
  zone         = "europe-west1-b"

  boot_disk {
    initialize_params {
      image = data.google_compute_image.docker_server.self_link
    }
  }

  network_interface {
    network = "default"
    access_config {}
  }
}

OpenTofu → Ansible (day-2 config)

OpenTofu provisionne l'infrastructure, puis Ansible configure les machines déployées.

1. OpenTofu généré l'inventaire dynamique

resource "local_file" "ansible_inventory" {
  content = templatefile("inventory.tftpl", {
    webservers = [for i in google_compute_instance.web : {
      name = i.name
      ip   = i.network_interface[0].access_config[0].nat_ip
    }]
  })
  filename = "${path.module}/inventory.yml"
}
# inventory.tftpl
all:
  children:
    webservers:
      hosts:
%{ for server in webservers ~}
        ${server.name}:
          ansible_host: ${server.ip}
%{ endfor ~}

2. Ansible configure les machines

# Apres tofu apply
ansible-playbook -i inventory.yml playbook.yml

Pipeline CI/CD complet

# .github/workflows/infra.yml
name: Infrastructure Pipeline

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

jobs:
  packer:
    runs-on: ubuntu-latest
    if: contains(github.event.head_commit.modified, 'packer/')
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-packer@main
      - run: packer init packer/ && packer build packer/

  tofu-plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: opentofu/setup-opentofu@v1
      - run: |
          cd infra/
          tofu init
          tofu plan -out=tfplan
      - uses: actions/upload-artifact@v4
        with:
          name: tfplan
          path: infra/tfplan

  tofu-apply:
    needs: [tofu-plan]
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: opentofu/setup-opentofu@v1
      - uses: actions/download-artifact@v4
        with:
          name: tfplan
          path: infra/
      - run: |
          cd infra/
          tofu init
          tofu apply tfplan

  configure:
    needs: [tofu-apply]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          pip install ansible
          ansible-playbook -i infra/inventory.yml ansible/playbook.yml

Bonnes pratiques

Séparation des responsabilités

Ne melangez pas les rôles : Packer crée les images, OpenTofu provisionne l'infra, Ansible configuré. Si vous vous retrouvez a exécuter des scripts dans OpenTofu (remote-exec), c'est un signe que la tâche devrait être dans Packer ou Ansible.

Immutabilite

Privilegiez le modèle immutable : plutôt que de modifier une VM en place avec Ansible, reconstruisez l'image avec Packer et remplacez l'instance via OpenTofu. Cela garantit la reproductibilite.

State et inventaire

Ne commitez ni le state OpenTofu ni l'inventaire généré. Le state est dans un backend remote, l'inventaire est régénéré à chaque tofu apply.