Múlt hónapban végre belehúztam. Hónapokig figyeltem, ahogy az OpenTofu projekt érik, és a HashiCorp licenszelési helyzete egyre kényelmetlenebbé válik az ügyfélmunkákhoz. Végül 47 Terraform modult migráltam három éles környezetben OpenTofu-ra. Nagyjából két hét tényleges munka volt, egy hónapra széthúzva, és a legtöbb simán ment. A legtöbb.

Miért váltottam

A BSL licencváltás volt a kiváltó ok, de nem az egyetlen. Pár ügyfelem kényes kérdéseket kezdett feltenni a Terraform Enterprise szerződésükről. Egyikük kapott egy levelet a HashiCorp sales csapattól, amiből elég egyértelművé vált a költségek iránya. Az OpenTofu eljutott arra a pontra, ahol a maradás kockázata nagyobbnak tűnt, mint a váltásé.

Szeretném tisztázni: a Terraform továbbra is jó eszköz. Ez nem egy gyűlöletkeltő poszt. Ez egy “íme mi történik ténylegesen, amikor migráltok” poszt.

Az egyszerű rész: alap modulok

Az egyértelmű moduloknál (VPC-k, security group-ok, S3 bucket-ek, IAM) a migráció szó szerint ennyi volt:

# OpenTofu telepítése
brew install opentofu

# A modul könyvtárában
tofu init
tofu plan

Ennyi. Nem kellett state-et migrálni. Az OpenTofu natívan olvassa a Terraform state fájlokat. A 47 modulból nagyjából 30-nál ez volt az egész folyamat. Futtattam a tofu init-et, láttam a tiszta plan-t, mentem tovább.

Az egyetlen változtatás a CI pipeline-ok frissítése volt, az opentofu/setup-opentofu GitHub Action-re cseréltem a hashicorp/setup-terraform-ot:

- name: Setup OpenTofu
  uses: opentofu/setup-opentofu@v1
  with:
    tofu_version: "1.9.0"

- name: Init
  run: tofu init

- name: Plan
  run: tofu plan -no-color

A közepes rész: provider verziók rögzítése

Nagyjából 10 modulnál kellett a provider verzió-megkötésekkel foglalkozni. Nem azért, mert az OpenTofu nem tudja használni ugyanazokat a providereket (tudja, és használja is), hanem mert pár .terraform.lock.hcl fájlban platform-specifikus hash-ek voltak, amiket újra kellett generálni.

# Régi lock fájl törlése és újragenerálás
rm .terraform.lock.hcl
tofu init
tofu providers lock \
  -platform=linux_amd64 \
  -platform=darwin_arm64

Egy buktató: ha a required_providers blokkokban source attribútummal registry.terraform.io-ra mutatsz, az továbbra is működik. Az OpenTofu registry-je tükrözi a hivatalosat. De azért frissítettem őket az egyértelműség kedvéért:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.80"
    }
  }
}

Ez a blokk mindkét eszközben azonosan működik. Nem kell változtatni rajta.

A nehéz rész: state titkosítás

Itt lesz az OpenTofu igazán érdekes, és itt futottam az első komolyabb problémába. Az OpenTofu natívan támogatja a state titkosítást, amit a Terraform soha nem kínált Enterprise nélkül. Be akartam kapcsolni.

A konfiguráció így néz ki:

terraform {
  encryption {
    method "aes_gcm" "main" {
      keys = key_provider.aws_kms.main
    }

    key_provider "aws_kms" "main" {
      kms_key_id = "arn:aws:kms:eu-central-1:123456789:key/abc-def-123"
      region     = "eu-central-1"
    }

    state {
      method = method.aes_gcm.main
    }
  }
}

A probléma: ha egyszer titkosítod a state-et, nem tudsz visszatérni Terraform-ra. Ez egyirányú ajtó. Ezt a nehezebb úton tanultam meg staging-ben, amikor titkosítottam a state-et, aztán kiderült, hogy az egyik kollégám még mindig terraform-ot aliasolt a shelljében. A következő terraform plan-je elszállt egy state parsing hibával, ami úgy nézett ki, mint korrupció.

A tanácsom: ne kapcsold be a state titkosítást, amíg minden egyes ember és pipeline, aki ahhoz a state-hez nyúl, át nem állt tofu-ra. Adj hozzá egy wrapper scriptet vagy Makefile-t, ami kikényszeríti:

#!/bin/bash
# tf-wrapper.sh
if command -v tofu &> /dev/null; then
  tofu "$@"
else
  echo "HIBA: Először telepítsd az OpenTofu-t. Lásd: https://opentofu.org/docs/intro/install/"
  exit 1
fi

A csúnya rész: egyedi providerek

Két belső providert tartok karban ügyfél-specifikus API-khoz. Ezek a Terraform Plugin SDK-val készültek, és tökéletesen működnek OpenTofu-val. Viszont a build és release pipeline a provider címben registry.terraform.io-ra hivatkozott, és a belső registry-nk (egy egyszerű S3 bucket meghatározott könyvtárstruktúrával) metaadat fájljait frissíteni kellett.

A javítás a terraform-registry-manifest.json frissítése volt:

{
  "version": 1,
  "metadata": {
    "protocol_versions": ["6.0"]
  }
}

És a network mirror konfiguráció a .terraformrc-ben (igen, az OpenTofu továbbra is olvassa ezt a fájlt, vagy használhatod a .tofurc-t) a megfelelő helyre kellett mutasson:

provider_installation {
  network_mirror {
    url = "https://our-internal-registry.example.com/providers/"
  }
  direct {
    exclude = ["example.com/*/*"]
  }
}

Tesztelési stratégia

Nem csak úgy bedobtam ezt élesbe. Minden modulnál ezt a folyamatot követtem:

  1. terraform plan futtatása és kimenet mentése
  2. tofu plan futtatása és kimenet mentése
  3. A két kimenet összehasonlítása
  4. Ha azonos, mehet tovább. Ha nem, kivizsgálás.
terraform plan -no-color > /tmp/tf-plan.txt 2>&1
tofu plan -no-color > /tmp/tofu-plan.txt 2>&1

# Verzió fejlécek levágása és diff
diff <(tail -n +5 /tmp/tf-plan.txt) <(tail -n +5 /tmp/tofu-plan.txt)

47 modulból 44-nél a diff üres volt. A három eltérő esetben apró formázási különbségek voltak a plan kimenetben, nem tényleges erőforrás-változások.

CI/CD migrációs checklist

Ezeket frissítettem a pipeline-okban:

  • GitHub Actions: hashicorp/setup-terraform cseréje opentofu/setup-opentofu-ra
  • Pre-commit hook-ok: terraform_fmt frissítése tofu fmt-re (a pre-commit-terraform hook-ok már mindkettőt támogatják)
  • Atlantis: átállás az OpenTofu-kompatibilis fork-ra. Ez volt a legidegesítőbb rész, mert az Atlantis konfigurációja szét van szórva az atlantis.yaml, a szerver oldali konfig és a repo szintű override-ok között
  • Dokumentáció: keresés-csere terraform-ról tofu-ra minden README-ben (de megtartottam a “Terraform”-ra való hivatkozásokat, ahol a koncepcióra/nyelvre utaltak)

Mit csinálnék másképp

Nem éles modulokkal kezdeni. Ezt tettem is, de hosszabb ideig kellett volna mindkét eszközt párhuzamosan futtatni. Két hét nem volt elég, hogy a state titkosítási buktatót időben elkapjam.

Többet kommunikálni. Küldtem egy Slack üzenetet és frissítettem a wikit. Kellett volna egy 15 perces walkthrough a csapatnak. Az a kolléga, aki terraform plan-t futtatott titkosított state-en, elkerülhető lett volna egy gyors demóval.

Ne titkosítsd rögtön a state-et. Először legyen mindenki migrálva. A state titkosítás remek funkció, de ez az egyetlen dolog, ami visszafordíthatatlanná teszi a migrációt. Hagyd nyitva ezt az ajtót legalább egy hónapig.

Teljesítmény

Egy dolgot észrevettem: a tofu init észrevehetően gyorsabb, mint a terraform init sok providerrel rendelkező moduloknál. Nem mértem tudományos pontossággal, de a 6 provideres modulnál kb. 12 másodpercről kb. 7 másodpercre csökkent az idő. Nem életbevágó, de jólesik.

A tofu plan és tofu apply sebessége a Terraform megfelelőivel azonosnak tűnt.

Megéri migrálni?

Ha Terraform Community Edition-t használsz és zavar a licenszelési helyzet, vagy ha az ügyfeleid kérdeznek róla, igen. A migráció az esetek többségében tényleg alacsony kockázatú.

Ha Terraform Enterprise-on vagy Cloud-on vagy, más a számítás. Azt a funkcionalitást (távoli state kezelés, policy as code, drift detection) más eszközökkel kellene kiváltanod. Az már egy nagyobb projekt.

Ha minden működik és senkit nem érdekel a licenszelés, nincs sürgősség. Mindkét eszköz ugyanazt a state formátumot olvassa, ugyanazokat a providereket használja, és ugyanazt a HCL-t fogadja el. Bármikor átállhatsz később.

A lényeg, hogy a lehetőség létezik, működik, és production-ready. Éles infrastruktúrán futtatom, valós forgalmat szolgál ki, és nyugodtan alszom.