DEV Community

Cover image for Introduction à OpenTofu pour les utilisateurs Terraform
Benoît Garçon for La Formule Nuagique

Posted on • Originally published at formulenuagique.com

Introduction à OpenTofu pour les utilisateurs Terraform

OpenTofu est un fork communautaire de Terraform, compatible en grande partie avec ce dernier, mais qui prend une orientation technique différente sur certains points clés. Pour les utilisateurs expérimentés de Terraform, la transition vers OpenTofu est quasi transparente tout en offrant des fonctionnalités avancées comme le chiffrement natif de l'état ou une évaluation anticipée des expressions.

Ce tutoriel illustre l'utilisation d'OpenTofu pour déployer une architecture répartie sur deux régions GCP avec deux machines virtuelles GCE faisant tourner NGINX, exposées via un Global Load Balancer. Le backend de stockage d'état utilisera GitLab comme source de vérité.

Installation d'OpenTofu

Installation Debian/Ubuntu :

curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh | bash -s -- --install-method deb
Enter fullscreen mode Exit fullscreen mode

Pour vérifier la bonne installation de OpenTofu :

tofu version
Enter fullscreen mode Exit fullscreen mode

Configuration du backend GitLab

GitLab permet de stocker l'état via un repository en tant que backend "HTTP" compatible.

Exemple terragrunt.hcl :

locals {
  config            = yamldecode(file("config.yaml"))
  gitlab_project_id = local.config.backend.gitlab.project_id
  gitlab_username   = local.config.backend.gitlab.username
  gitlab_token      = get_env("GITLAB_TOKEN", "")
  gitlab_path       = "blog"
  gitlab_url        = "https://gitlab.com/api/v4/projects/${local.gitlab_project_id}/terraform/state/${local.gitlab_path}"
}

generate "backend" {
  path      = "backend.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  backend "http" {
    address        = "${local.gitlab_url}"
    lock_address   = "${local.gitlab_url}/lock"
    unlock_address = "${local.gitlab_url}/lock"
    username       = "${local.gitlab_username}"
    password       = "${local.gitlab_token}"
    lock_method    = "POST"
    unlock_method  = "DELETE"
    retry_wait_min = 5
  }
}
EOF
}

generate "providers" {
  path      = "providers.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "google" {
  project = "${local.config.cloud.project_id}"
  region  = "${local.config.cloud.region}"
}
EOF
}

inputs = {
  config = local.config
}
Enter fullscreen mode Exit fullscreen mode

Ce module Terragrunt va charger un fichier config.yaml de ce type :

backend:
  gitlab:
    project_id: "<project_id>"
    username: "<username>"

cloud:
  project_id: <gcp_project_id>
  region: europe-west9
  workload:
    france:
      color: "#0000BB"
      machine: e2-micro
      region: europe-west9
      traffic: 0.80
    belgium:
      color: "#BB0000"
      machine: e2-micro
      region: europe-west1
      traffic: 0.20
Enter fullscreen mode Exit fullscreen mode

Remplacez <project_id>, <username>, <gcp_project_id>, et les identifiants par les vôtres. Le projet doit être configuré pour permettre le remote backend via HTTP.

Pour pouvoir utiliser OpenTofu et le backend GitLab, il faut aussi exporter une variable d'environnement :

export GITLAB_TOKEN=<key>
Enter fullscreen mode Exit fullscreen mode

Infrastructure cible

  • Deux instances GCE (dans europe-west9 et europe-west1) avec NGINX
  • Global Load Balancer HTTP(S)
  • Priorité pondérée sur les backends (ex : 80/20)

Exemple d’infrastructure (fichiers principaux)

workload.tf

resource "google_compute_instance" "nginx" {
  for_each = var.config.cloud.workload

  machine_type = each.value.machine
  name         = "nginx-${each.key}"
  zone         = "${each.value.region}-b"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
    }
  }

  network_interface {
    network = "default"
    access_config {}
  }

  tags = [ "public" ]

  metadata_startup_script = <<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    echo " <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${upper(each.key)}</title> <style> body { background-color: ${each.value.color}; color: white; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; font-family: Arial, sans-serif; } h1 { font-size: 5rem; } </style> </head> <body> <h1>${upper(each.key)}</h1> </body> </html>" > /var/www/html/index.nginx-debian.html
    systemctl restart nginx
  EOF

  depends_on = [ google_project_service.apis ]
}
Enter fullscreen mode Exit fullscreen mode

load_balancing.tf

resource "google_compute_instance_group" "group" {
  for_each = var.config.cloud.workload

  name        = "group-${each.key}"
  zone        = "${each.value.region}-b"
  instances   = [google_compute_instance.nginx[each.key].self_link]

  named_port {
    name = "http"
    port = 80
  }
}

resource "google_compute_health_check" "default" {
  name               = "http-health-check"
  check_interval_sec = 5
  timeout_sec        = 5

  http_health_check {
    port = 80
  }
}

resource "google_compute_backend_service" "default" {
  name                  = "nginx-backend"
  load_balancing_scheme = "EXTERNAL"
  port_name             = "http"
  protocol              = "HTTP"
  timeout_sec           = 10
  health_checks         = [google_compute_health_check.default.self_link]

  dynamic "backend" {
    for_each = var.config.cloud.workload
    content {
      group           = google_compute_instance_group.group[backend.key].self_link
      balancing_mode  = "UTILIZATION"
      capacity_scaler = backend.value.traffic
    }
  }
}

resource "google_compute_url_map" "default" {
  name            = "url-map"
  default_service = google_compute_backend_service.default.self_link
}

resource "google_compute_target_http_proxy" "default" {
  name        = "http-proxy"
  url_map     = google_compute_url_map.default.self_link
}

resource "google_compute_global_forwarding_rule" "default" {
  name                  = "http-forwarding-rule"
  target                = google_compute_target_http_proxy.default.self_link
  port_range            = "80"
  load_balancing_scheme = "EXTERNAL"
}
Enter fullscreen mode Exit fullscreen mode

network.tf

resource "google_compute_firewall" "allow_http" {
  name    = "allow-http"
  network = "default"

  allow {
    protocol = "tcp"
    ports    = ["80"]
  }

  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["public"]
}
Enter fullscreen mode Exit fullscreen mode

api.tf

resource "google_project_service" "apis" {
  project = var.config.cloud.project_id
  service = "compute.googleapis.com"
}
Enter fullscreen mode Exit fullscreen mode

variables.tf

variable "config" {
  type = any
}
Enter fullscreen mode Exit fullscreen mode

Utilisation de Terragrunt avec OpenTofu

Terragrunt est pleinement compatible avec OpenTofu. Il suffit de remplacer la commande terraform par tofu dans votre via votre variable TERRAGRUNT_TFPATH :

export TERRAGRUNT_TFPATH=tofu
Enter fullscreen mode Exit fullscreen mode

Conclusion

Ce projet démontre la maturité d'OpenTofu pour gérer des infrastructures complexes tout en restant compatible avec l'écosystème Terraform. Couplé à Terragrunt, il devient un outil de choix pour l'automatisation multi-environnement. L'intégration avec GitLab pour la gestion d'état et les pipelines CI renforce encore sa pertinence pour des workflows GitOps en production : il est tout aussi cpable que Terraform.

Grâce à une configuration modulaire, un backend distant sécurisé, et une exposition via un load balancer global, ce cas d’usage illustre comment industrialiser un déploiement cloud fiable avec des outils modernes, ouverts et maintenus par la communauté.

Références

Top comments (2)

Collapse
 
nevodavid profile image
Nevo David

Really like seeing projects that push for more open-source options. Makes me think- once you get deep into these setups, you ever actually want to go back to closed systems?

Collapse
 
begarco profile image
Benoît Garçon La Formule Nuagique

Hello and thank you for this very insightful comment. You've hit on a key point that many developers and DevOps engineers feel.

Once you've fully embraced open-source tools for tasks as critical as infrastructure management (IaC), the idea of going back to closed systems often becomes unthinkable. Several reasons explain this feeling:

  • With open source, there's no "black box." You can read the code, understand exactly how the tool works, and even fix it yourself in case of an urgent bug. This transparency builds a level of trust that a proprietary system can hardly match.

  • The Terraform/OpenTofu situation is a perfect example of freedom from vendor lock-in. Tying yourself to a closed system means accepting dependency on a single company's strategic, pricing, and licensing decisions. Open source, especially when governed by a neutral foundation like the Linux Foundation, guarantees the tool's longevity and freedom. You invest your time and skills in a standard that won't be privatized overnight.

  • Open-source projects benefit from collective intelligence. Features are often developed in response to the community's real needs, not solely for commercial reasons. You shift from being a simple "customer" to a potential "contributor" to a project you're passionate about.

That said, closed systems still have their advantages for certain organizations (dedicated support, highly integrated ecosystems, etc.). But for the engineer "on the ground," the freedom, flexibility, and collaborative philosophy of open source often create a one-way street.

Your comment perfectly summarizes why projects like OpenTofu aren't just technical alternatives, but fundamental movements driven by a community that values openness.