Terraform vs Ansible : Comprendre les Différences et Complémentarités

Terraform vs Ansible : comprenez les différences entre provisioning et configuration management. Tableau comparatif, cas d'usage et architecture combinée pour tirer le meilleur des deux.

Introduction

Si vous travaillez dans le monde DevOps ou de l'infrastructure, vous avez forcément rencontré cette question : faut-il utiliser Terraform ou Ansible ? La réponse courte est "ça dépend". La réponse longue, c'est cet article. Car en réalité, ces deux outils ne sont pas véritablement concurrents : ils répondent à des besoins différents et sont souvent complémentaires.

Terraform excelle dans le provisioning d'infrastructure : créer des serveurs, des réseaux, des bases de données dans le cloud. Ansible excelle dans la gestion de configuration : installer des logiciels, configurer des services, déployer des applications sur des serveurs existants. Comprendre cette distinction fondamentale est la clé pour faire le bon choix — ou plutôt, pour utiliser les deux intelligemment.

Dans cet article, nous allons disséquer les deux outils en profondeur, les comparer sur tous les critères pertinents, et montrer comment les combiner dans une architecture DevOps moderne. Nous aborderons également les alternatives comme Pulumi et OpenTofu pour vous donner une vision complète du paysage de l'Infrastructure as Code.

Diagramme - Terraform vs Ansible : Comprendre les Différences et Complémentarités

Déclaratif vs Impératif : Deux Philosophies

La différence fondamentale entre Terraform et Ansible réside dans leur approche de la description de l'infrastructure.

Terraform : L'Approche Déclarative

Avec Terraform, vous décrivez l'état final désiré de votre infrastructure. Vous ne dites pas "crée un serveur", vous dites "il doit exister un serveur avec ces caractéristiques". Terraform calcule automatiquement les actions nécessaires pour atteindre cet état.

# Terraform : "Je veux 3 instances EC2 de type t3.medium"
resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0123456789abcdef0"
  instance_type = "t3.medium"

  tags = {
    Name        = "web-server-${count.index + 1}"
    Environment = "production"
  }
}

# Si vous changez count de 3 à 5, Terraform crée 2 instances
# Si vous changez count de 3 à 1, Terraform détruit 2 instances
# Terraform sait toujours où il en est grâce au state file

L'avantage majeur : l'idempotence garantie. Exécuter terraform apply plusieurs fois avec la même configuration ne crée pas de doublons. Terraform compare l'état actuel au state file et n'agit que si nécessaire.

Ansible : L'Approche Impérative (avec du Déclaratif)

Ansible est souvent décrit comme impératif, mais c'est une simplification. En réalité, Ansible utilise des modules déclaratifs organisés dans des playbooks séquentiels. Chaque module peut être idempotent individuellement, mais l'exécution globale suit un ordre précis défini par vous.

# Ansible : "Installe Nginx, configure-le, démarre-le"
---
- name: Configurer les serveurs web
  hosts: webservers
  become: yes
  
  tasks:
    - name: Installer Nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Copier la configuration Nginx
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart Nginx

    - name: Déployer le site web
      copy:
        src: files/index.html
        dest: /var/www/html/index.html

    - name: S'assurer que Nginx est démarré
      service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

Chaque tâche (apt, template, service) est idempotente : relancer le playbook ne réinstalle pas Nginx s'il est déjà là. Mais l'ordre des tâches est important et défini explicitement par le développeur.

Provisioning vs Configuration Management

C'est la distinction la plus importante à comprendre entre les deux outils.

Provisioning d'Infrastructure (Terraform)

Le provisioning consiste à créer et gérer les ressources cloud elles-mêmes :

  • Réseaux virtuels (VPC, subnets, routes)
  • Machines virtuelles (EC2, Compute Engine, Azure VM)
  • Bases de données managées (RDS, Cloud SQL, Azure Database)
  • Load balancers, DNS, certificats SSL
  • Conteneurs et orchestrateurs (ECS, EKS, GKE)
  • Stockage (S3, GCS, Azure Blob)
  • Permissions et politiques IAM

Terraform interagit directement avec les API des fournisseurs cloud via ses providers. Il connaît les dépendances entre ressources et les gère automatiquement (créer le VPC avant le subnet, le subnet avant l'instance, etc.).

Configuration Management (Ansible)

La gestion de configuration consiste à configurer ce qui tourne à l'intérieur des machines :

  • Installer et mettre à jour des packages
  • Configurer des services (Nginx, PostgreSQL, Redis)
  • Gérer des utilisateurs et des permissions système
  • Déployer du code applicatif
  • Appliquer des patches de sécurité
  • Configurer le monitoring et les agents de collecte de logs
  • Gérer les fichiers de configuration et les secrets

Ansible se connecte aux machines via SSH (ou WinRM pour Windows) et exécute des tâches sur elles. Il n'a pas besoin d'agent installé sur les machines cibles, ce qui est l'un de ses avantages majeurs.

Terraform en Profondeur : Forces et Faiblesses

Forces de Terraform

  • State Management : Le fichier de state permet à Terraform de savoir exactement ce qui existe et de calculer les différences. C'est ce qui rend le terraform plan si puissant.
  • Graphe de dépendances : Terraform comprend automatiquement les dépendances entre ressources et les crée/détruit dans le bon ordre.
  • Multi-cloud natif : Le même langage (HCL) et le même workflow pour AWS, Azure, GCP, Kubernetes, et des centaines d'autres providers.
  • Plan before Apply : La capacité de prévisualiser exactement ce qui va changer avant d'appliquer est un avantage énorme en production.
  • Écosystème de modules : Le Terraform Registry contient des milliers de modules réutilisables et maintenus par la communauté.
  • Cycle de vie complet : Terraform gère la création, la modification et la destruction des ressources, ce qu'Ansible fait difficilement.

Faiblesses de Terraform

  • Gestion du state : Le state file est aussi sa plus grande faiblesse. Il doit être stocké de manière sécurisée, partagée, et verrouillée. Une corruption du state peut être catastrophique.
  • Configuration des machines : Terraform peut techniquement configurer des machines via des provisioners, mais c'est fortement déconseillé par HashiCorp. Ce n'est pas son domaine.
  • Logique conditionnelle limitée : HCL n'est pas un langage de programmation complet. Les boucles et conditions complexes peuvent devenir verbeux.
  • Temps d'apprentissage du state : Comprendre le state, les imports, les moves, les data sources demande du temps et de l'expérience.
  • Vendor lock-in sur HCL : Terraform utilise un langage propriétaire (HCL), contrairement à Ansible qui utilise YAML.

Ansible en Profondeur : Forces et Faiblesses

Forces d'Ansible

  • Sans agent : Ansible ne nécessite aucune installation sur les machines cibles. Une connexion SSH suffit.
  • Courbe d'apprentissage douce : Les playbooks YAML sont faciles à lire et à écrire, même pour quelqu'un qui n'est pas développeur.
  • Polyvalence : Ansible peut gérer la configuration, le déploiement d'applications, l'orchestration, et même du provisioning cloud basique.
  • Exécution ad-hoc : Vous pouvez lancer des commandes ponctuelles sur des groupes de machines sans écrire de playbook.
  • Rôles et Galaxy : Ansible Galaxy est un hub de rôles réutilisables pour configurer pratiquement n'importe quel service.
  • Gestion des secrets : Ansible Vault est intégré nativement pour chiffrer les variables sensibles.
  • Large communauté : Maintenu par Red Hat, Ansible bénéficie d'une communauté massive et d'un support entreprise solide.

Faiblesses d'Ansible

  • Pas de state : Ansible n'a pas de fichier de state. Il ne sait pas ce qu'il a fait précédemment. Chaque exécution repart de zéro (vérifie et corrige si nécessaire).
  • Pas de plan : Il n'y a pas d'équivalent au terraform plan. Le mode --check (dry-run) existe, mais il est limité et peu fiable pour les cas complexes.
  • Destruction difficile : Ansible ne sait pas nativement "défaire" ce qu'il a fait. Supprimer une ressource cloud nécessite d'écrire un playbook de suppression séparé.
  • Performance à grande échelle : Pour des centaines de machines, Ansible peut être lent car il se connecte séquentiellement (même avec des forks parallèles).
  • Drift non détecté : Sans state, Ansible ne peut pas détecter les dérives de configuration entre deux exécutions.

Tableau Comparatif Détaillé

Voici un comparatif complet de Terraform et Ansible sur les critères les plus importants :

Critère Terraform Ansible
Type Provisioning d'infrastructure Configuration management
Approche Déclarative Impérative / Déclarative hybride
Langage HCL (HashiCorp Configuration Language) YAML + Jinja2
State Oui (fichier de state centralisé) Non (stateless)
Agent Non requis (API-driven) Non requis (SSH)
Plan / Dry-run terraform plan (fiable et détaillé) --check (limité)
Idempotence Garantie par le state Dépend des modules utilisés
Destruction terraform destroy (natif) Doit être codé manuellement
Multi-cloud Excellent (providers natifs) Possible mais moins intégré
Configuration OS Non recommandé Excellent
Courbe d'apprentissage Moyenne (HCL + concepts de state) Faible (YAML familier)
Communauté Très large (HashiCorp) Très large (Red Hat)
Licence BSL 1.1 (depuis août 2023) GPL v3
Écosystème Terraform Registry (modules + providers) Ansible Galaxy (rôles + collections)
Tests terraform test, Terratest Molecule, ansible-lint
Secret management Intégration externe (Vault, etc.) Ansible Vault (natif)
Rollback Re-apply d'un ancien state/code Re-run avec ancienne config

Quand Utiliser Terraform ?

Terraform est le choix idéal dans les situations suivantes :

1. Provisioning Cloud

C'est le cas d'usage principal. Dès que vous créez des ressources sur AWS, Azure, GCP ou tout autre fournisseur cloud, Terraform est l'outil de référence.

# Exemple : Infrastructure complète pour une application web
module "vpc" {
  source = "./modules/networking"
  
  vpc_cidr    = "10.0.0.0/16"
  environment = "production"
}

module "database" {
  source = "./modules/database"
  
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnet_ids
  
  engine         = "postgres"
  engine_version = "15"
  instance_class = "db.r6g.large"
}

module "application" {
  source = "./modules/ecs"
  
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnet_ids
  
  container_image = "api:latest"
  cpu             = 256
  memory          = 512
  desired_count   = 3
  
  database_url = module.database.connection_string
}

2. Infrastructure Multi-Cloud

Si votre organisation utilise plusieurs fournisseurs cloud, Terraform fournit une expérience unifiée avec un seul langage et un seul workflow.

3. Infrastructure Éphémère

Pour les environnements de test ou de démo qui doivent être créés et détruits régulièrement, terraform destroy est imbattable.

4. Conformité et Audit

Le state file et les plans permettent de savoir exactement ce qui existe et ce qui va changer. Combiné avec Sentinel ou OPA, c'est un outil puissant pour la gouvernance.

Quand Utiliser Ansible ?

Ansible est le choix idéal dans ces situations :

1. Configuration de Serveurs

Installer des packages, configurer des services, gérer des utilisateurs, appliquer des patches de sécurité : c'est le terrain de jeu d'Ansible.

# Exemple : Configurer un serveur PostgreSQL
---
- name: Configurer PostgreSQL
  hosts: database_servers
  become: yes
  vars:
    postgresql_version: "15"
    postgresql_max_connections: 200
    postgresql_shared_buffers: "4GB"
    
  roles:
    - role: geerlingguy.postgresql
      vars:
        postgresql_databases:
          - name: api_production
            encoding: UTF-8
            lc_collate: fr_FR.UTF-8
        postgresql_users:
          - name: api_user
            password: "{{ vault_db_password }}"
            db: api_production
            priv: "ALL"
        postgresql_hba_entries:
          - type: host
            database: api_production
            user: api_user
            address: "10.0.0.0/16"
            method: md5

  tasks:
    - name: Configurer les paramètres de performance
      postgresql_set:
        name: "{{ item.name }}"
        value: "{{ item.value }}"
      loop:
        - { name: "max_connections", value: "{{ postgresql_max_connections }}" }
        - { name: "shared_buffers", value: "{{ postgresql_shared_buffers }}" }
        - { name: "effective_cache_size", value: "12GB" }
        - { name: "work_mem", value: "64MB" }
      notify: Restart PostgreSQL

2. Déploiement d'Applications

Déployer du code, gérer les releases, effectuer des rolling updates sur un parc de serveurs.

3. Opérations Ad-Hoc

Exécuter une commande sur 100 serveurs en une seule commande, sans écrire de playbook complet.

# Redémarrer Nginx sur tous les serveurs web
ansible webservers -m service -a "name=nginx state=restarted" -b

# Vérifier l'espace disque sur tous les serveurs
ansible all -m shell -a "df -h /"

# Appliquer un patch de sécurité urgent
ansible all -m apt -a "name=openssl state=latest" -b

4. Gestion de Parc Existant

Si vous avez un parc de serveurs déjà existants (bare-metal ou VMs), Ansible est parfait pour uniformiser leur configuration.

Utiliser Terraform et Ansible Ensemble

L'approche la plus puissante consiste à utiliser les deux outils ensemble, chacun dans son domaine d'excellence. Terraform provisionne l'infrastructure, Ansible la configure.

Architecture Combinée

# Architecture Terraform + Ansible
#
# ┌─────────────────────────────────────────────────────────┐
# │                    PIPELINE CI/CD                        │
# │                                                          │
# │  ┌─────────────────┐      ┌──────────────────────┐      │
# │  │   TERRAFORM      │      │      ANSIBLE          │      │
# │  │                  │      │                       │      │
# │  │  1. Crée le VPC  │      │  5. Installe Docker   │      │
# │  │  2. Crée les EC2 │─────▶│  6. Configure Nginx   │      │
# │  │  3. Crée le RDS  │      │  7. Déploie l'app     │      │
# │  │  4. Crée le S3   │      │  8. Configure le      │      │
# │  │                  │      │     monitoring         │      │
# │  │  Output: IPs,    │      │                       │      │
# │  │  endpoints,      │      │  Input: Inventaire    │      │
# │  │  identifiants    │      │  dynamique depuis     │      │
# │  │                  │      │  Terraform output     │      │
# │  └─────────────────┘      └──────────────────────┘      │
# │                                                          │
# └─────────────────────────────────────────────────────────┘

Méthode 1 : Inventaire Dynamique

La méthode la plus propre consiste à utiliser un inventaire dynamique Ansible qui interroge l'API cloud (ou le state Terraform) pour découvrir les machines à configurer.

# ansible/inventory/aws_ec2.yml
# Inventaire dynamique AWS pour Ansible
plugin: amazon.aws.aws_ec2
regions:
  - eu-west-3
filters:
  tag:ManagedBy: terraform
  tag:Environment: production
  instance-state-name: running
keyed_groups:
  - key: tags.Role
    prefix: role
  - key: tags.Environment
    prefix: env
hostnames:
  - private-ip-address
compose:
  ansible_host: private_ip_address
  ansible_user: "'ubuntu'"
# Vérifier que l'inventaire dynamique fonctionne
ansible-inventory -i inventory/aws_ec2.yml --graph

# Résultat :
# @all:
#   |--@role_webserver:
#   |  |--10.0.1.15
#   |  |--10.0.1.16
#   |  |--10.0.1.17
#   |--@role_database:
#   |  |--10.0.2.10
#   |--@env_production:
#   |  |--10.0.1.15
#   |  |--10.0.1.16
#   |  |--10.0.1.17
#   |  |--10.0.2.10

Méthode 2 : Terraform Outputs comme Source

Vous pouvez générer un inventaire Ansible statique à partir des outputs Terraform.

# Terraform : Générer l'inventaire Ansible
resource "local_file" "ansible_inventory" {
  content = templatefile("${path.module}/templates/inventory.tpl", {
    web_servers = aws_instance.web[*].private_ip
    db_servers  = [aws_db_instance.main.address]
    lb_dns      = aws_lb.main.dns_name
  })
  filename = "${path.module}/../ansible/inventory/hosts"
}

# templates/inventory.tpl
# [webservers]
# %{ for ip in web_servers ~}
# ${ip} ansible_user=ubuntu
# %{ endfor ~}
#
# [databases]
# %{ for ip in db_servers ~}
# ${ip} ansible_user=ubuntu
# %{ endfor ~}
#
# [all:vars]
# lb_dns_name=${lb_dns}

Méthode 3 : Pipeline Séquentiel

# .github/workflows/deploy.yml
name: "Deploy Infrastructure"

on:
  push:
    branches: [main]

jobs:
  terraform:
    name: "Provision Infrastructure"
    runs-on: ubuntu-latest
    outputs:
      web_ips: ${{ steps.outputs.outputs.web_ips }}
      db_endpoint: ${{ steps.outputs.outputs.db_endpoint }}
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
      
      - name: Terraform Apply
        run: |
          cd terraform/
          terraform init
          terraform apply -auto-approve
      
      - name: Export Outputs
        id: outputs
        run: |
          cd terraform/
          echo "web_ips=$(terraform output -json web_ips)" >> $GITHUB_OUTPUT
          echo "db_endpoint=$(terraform output -raw db_endpoint)" >> $GITHUB_OUTPUT

  ansible:
    name: "Configure Servers"
    needs: terraform
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install Ansible
        run: pip install ansible boto3
      
      - name: Configure SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
      
      - name: Run Ansible Playbook
        run: |
          cd ansible/
          ansible-playbook -i inventory/aws_ec2.yml \
            playbooks/configure-all.yml \
            -e "db_endpoint=${{ needs.terraform.outputs.db_endpoint }}"
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Exemple d'Architecture Combinée Complète

Voici un exemple concret d'une architecture web classique gérée par Terraform et Ansible ensemble.

Terraform : Provisioning

# terraform/main.tf
# Terraform crée toute l'infrastructure cloud

module "vpc" {
  source = "./modules/vpc"
  
  cidr_block  = "10.0.0.0/16"
  environment = var.environment
}

resource "aws_instance" "web" {
  count         = 3
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.medium"
  subnet_id     = module.vpc.private_subnet_ids[count.index % 3]
  key_name      = aws_key_pair.deploy.key_name

  vpc_security_group_ids = [aws_security_group.web.id]

  tags = {
    Name        = "web-${count.index + 1}"
    Role        = "webserver"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_db_instance" "main" {
  identifier     = "${var.environment}-postgres"
  engine         = "postgres"
  engine_version = "15"
  instance_class = "db.r6g.large"
  
  db_name  = "application"
  username = "admin"
  password = var.db_password

  db_subnet_group_name   = module.vpc.db_subnet_group
  vpc_security_group_ids = [aws_security_group.db.id]

  backup_retention_period = 7
  multi_az               = true
  storage_encrypted      = true

  tags = {
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_lb" "main" {
  name               = "${var.environment}-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = module.vpc.public_subnet_ids
}

# Outputs pour Ansible
output "web_server_ips" {
  value = aws_instance.web[*].private_ip
}

output "db_endpoint" {
  value = aws_db_instance.main.endpoint
}

output "lb_dns_name" {
  value = aws_lb.main.dns_name
}

Ansible : Configuration

# ansible/playbooks/configure-web.yml
# Ansible configure les serveurs créés par Terraform
---
- name: Configurer les serveurs web
  hosts: role_webserver
  become: yes
  
  vars:
    app_version: "2.3.1"
    db_endpoint: "{{ lookup('env', 'DB_ENDPOINT') }}"
    
  pre_tasks:
    - name: Mettre à jour les packages
      apt:
        update_cache: yes
        upgrade: dist
      
    - name: Installer les dépendances système
      apt:
        name:
          - docker.io
          - docker-compose-v2
          - python3-docker
          - nginx
          - certbot
          - python3-certbot-nginx
          - htop
          - curl
          - jq
        state: present

  tasks:
    - name: Ajouter l'utilisateur au groupe docker
      user:
        name: ubuntu
        groups: docker
        append: yes

    - name: Créer le répertoire de l'application
      file:
        path: /opt/app
        state: directory
        owner: ubuntu
        group: ubuntu

    - name: Déployer le docker-compose
      template:
        src: templates/docker-compose.yml.j2
        dest: /opt/app/docker-compose.yml
        owner: ubuntu
        group: ubuntu
      notify: Restart Application

    - name: Configurer Nginx comme reverse proxy
      template:
        src: templates/nginx-app.conf.j2
        dest: /etc/nginx/sites-available/app.conf
      notify: Reload Nginx

    - name: Activer la configuration Nginx
      file:
        src: /etc/nginx/sites-available/app.conf
        dest: /etc/nginx/sites-enabled/app.conf
        state: link
      notify: Reload Nginx

    - name: Installer et configurer Datadog agent
      include_role:
        name: datadog.datadog
      vars:
        datadog_api_key: "{{ vault_datadog_api_key }}"
        datadog_checks:
          nginx:
            instances:
              - nginx_status_url: http://localhost/nginx_status

    - name: Démarrer l'application
      community.docker.docker_compose_v2:
        project_src: /opt/app
        state: present
        pull: always

  handlers:
    - name: Restart Application
      community.docker.docker_compose_v2:
        project_src: /opt/app
        state: present
        restarted: true

    - name: Reload Nginx
      service:
        name: nginx
        state: reloaded

Alternatives : Pulumi et OpenTofu

Le paysage de l'IaC évolue constamment. Deux alternatives méritent d'être mentionnées.

OpenTofu : Le Fork Open Source de Terraform

Depuis le changement de licence de Terraform (BSL 1.1 en août 2023), la communauté a créé OpenTofu, un fork open source maintenu par la Linux Foundation. OpenTofu est compatible à 100% avec Terraform (même syntaxe HCL, mêmes providers) et s'engage à rester open source (licence MPL 2.0).

# OpenTofu utilise les mêmes commandes que Terraform
tofu init
tofu plan
tofu apply
tofu destroy

# La migration depuis Terraform est triviale
# Remplacez simplement "terraform" par "tofu" dans vos scripts

OpenTofu ajoute progressivement des fonctionnalités absentes de Terraform, comme le chiffrement natif du state file et les provider-defined functions. C'est une alternative sérieuse à considérer si la licence open source est importante pour votre organisation.

Pulumi : L'IaC avec de Vrais Langages

Pulumi permet de définir l'infrastructure avec des langages de programmation classiques : Python, TypeScript, Go, C#, Java. C'est une approche radicalement différente de Terraform/HCL.

# Exemple Pulumi en Python
import pulumi
import pulumi_aws as aws

# Créer un VPC
vpc = aws.ec2.Vpc("main-vpc",
    cidr_block="10.0.0.0/16",
    enable_dns_hostnames=True,
    tags={"Name": "production-vpc"}
)

# Créer des subnets avec une boucle Python classique
azs = ["eu-west-3a", "eu-west-3b", "eu-west-3c"]
subnets = []
for i, az in enumerate(azs):
    subnet = aws.ec2.Subnet(f"subnet-{i}",
        vpc_id=vpc.id,
        cidr_block=f"10.0.{i}.0/24",
        availability_zone=az,
        tags={"Name": f"subnet-{az}"}
    )
    subnets.append(subnet)

# Créer une instance EC2
instance = aws.ec2.Instance("web-server",
    ami="ami-0123456789abcdef0",
    instance_type="t3.medium",
    subnet_id=subnets[0].id,
    tags={"Name": "web-server-1"}
)

# Exporter les outputs
pulumi.export("vpc_id", vpc.id)
pulumi.export("instance_ip", instance.private_ip)

Les avantages de Pulumi incluent l'utilisation de langages familiers avec IDE support complet, des tests unitaires avec les frameworks standard (pytest, Jest, etc.), et une logique conditionnelle native du langage. Ses inconvénients sont une communauté plus petite, un écosystème de modules moins riche que Terraform, et le fait que la puissance du langage peut mener à une complexité excessive.

Comment Choisir ? Guide de Décision

Voici un guide simplifié pour vous aider à choisir :

  • Vous créez des ressources cloud (VMs, réseaux, bases de données managées) : utilisez Terraform.
  • Vous configurez ce qui tourne sur les serveurs (packages, services, fichiers de config) : utilisez Ansible.
  • Vous faites les deux : utilisez les deux ensemble.
  • Vous voulez un seul outil et vous gérez principalement du cloud : Terraform peut gérer la majorité avec cloud-init pour la configuration basique des machines.
  • Vous voulez un seul outil et vous avez beaucoup de serveurs existants : Ansible peut faire du provisioning cloud avec ses modules AWS/Azure/GCP, même si ce n'est pas son point fort.
  • La licence open source est primordiale : utilisez OpenTofu au lieu de Terraform.
  • Votre équipe est composée de développeurs qui préfèrent coder en Python/TypeScript : évaluez Pulumi.

Bonnes Pratiques pour une Architecture Combinée

Séparation Claire des Responsabilités

Définissez clairement la frontière entre Terraform et Ansible :

  • Terraform gère : tout ce qui touche à l'API du fournisseur cloud (création de ressources, permissions IAM, réseaux, DNS, certificats).
  • Ansible gère : tout ce qui se passe à l'intérieur d'une machine après sa création (configuration OS, installation de logiciels, déploiement d'applications).

Communication entre les Outils

Utilisez les outputs Terraform comme variables Ansible. L'inventaire dynamique est la méthode la plus propre, mais les tags sur les ressources cloud fonctionnent aussi très bien pour le filtrage.

Versionning et Structure de Dépôt

# Structure de dépôt recommandée
infrastructure/
├── terraform/
│   ├── environments/
│   │   ├── production/
│   │   └── staging/
│   ├── modules/
│   │   ├── vpc/
│   │   ├── compute/
│   │   └── database/
│   └── README.md
├── ansible/
│   ├── inventory/
│   │   ├── aws_ec2.yml     # Inventaire dynamique
│   │   └── group_vars/
│   ├── playbooks/
│   │   ├── configure-web.yml
│   │   ├── configure-db.yml
│   │   └── deploy-app.yml
│   ├── roles/
│   │   ├── common/
│   │   ├── webserver/
│   │   └── monitoring/
│   └── ansible.cfg
├── .github/
│   └── workflows/
│       ├── terraform.yml
│       └── ansible.yml
└── Makefile

Pipeline Intégré

Votre pipeline CI/CD devrait orchestrer les deux outils de manière séquentielle : Terraform en premier pour provisionner, puis Ansible pour configurer. Assurez-vous que le pipeline attend que les machines soient réellement accessibles (SSH) avant de lancer Ansible.

Conclusion

Terraform et Ansible ne sont pas des concurrents, ce sont des partenaires. Terraform est le maître du provisioning cloud avec son approche déclarative, son state file et son terraform plan. Ansible est le maître de la configuration avec son approche sans agent, ses playbooks lisibles et sa polyvalence.

La clé du succès est de comprendre les forces de chaque outil et de les utiliser dans leur domaine d'excellence. Terraform crée l'infrastructure, Ansible la configure. Le résultat est une chaîne d'automatisation complète, de la création du VPC jusqu'à la configuration du dernier fichier sur le serveur.

Si vous débutez, commencez par Terraform pour votre infrastructure cloud — c'est le fondement. Ajoutez Ansible quand vous avez besoin de configurer vos machines de manière reproductible. Et gardez un oeil sur OpenTofu et Pulumi qui enrichissent le paysage de l'IaC avec des approches innovantes.

Vous avez des questions sur Terraform ou Ansible ? Rejoignez la communauté CodeClan pour échanger avec d'autres passionnés d'infrastructure !

Vous vous êtes abonné avec succès à CodeClan
Parfait ! Ensuite, complétez le paiement pour obtenir un accès complet à tout le contenu premium.
Erreur ! Impossible de s'inscrire. Lien invalide.
Bienvenue ! Vous vous êtes connecté avec succès.
Erreur ! Impossible de se connecter. Veuillez réessayer.
Succès ! Votre compte est entièrement activé, vous avez maintenant accès à tout le contenu.
Erreur ! Le paiement Stripe a échoué.
Succès ! Vos informations de facturation sont mises à jour.
Erreur ! La mise à jour des informations de facturation a échoué.