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¶
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¶
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.