lesson ── terraform-advanced ── ~12 мин ── 6 шагов
OpenTofu is a fork of Terraform under MPL-2.0. The tofu binary already sits
in the image next to terraform. You run one HCL through both, compare the
result, and build a matrix pipeline for CI. This is your insurance against
lock-in to the HashiCorp license.
интерактивный sandbox
Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
which terraform
terraform --version
echo ---
which tofu
tofu --version
Both binaries live in /usr/local/bin. The versions may not match,
and that is normal: the fork branches develop in parallel.
✓ Tofu and terraform live in one sandbox.
cd /home/student/parity
cat > main.tf <<'EOF'
resource "aws_s3_bucket" "parity_demo" {bucket = "linuxlab-parity-demo"
tags = {ManagedBy = "either"
}
}
output "name" {value = aws_s3_bucket.parity_demo.bucket
}
EOF
First Terraform:
terraform init -no-color > /dev/null
terraform plan -no-color -out=plan.terraform > /dev/null
terraform show -no-color plan.terraform > plan-terraform.txt
head -20 plan-terraform.txt
Now OpenTofu (in a new directory so the state does not get mixed up):
mkdir -p tofu-test
cp main.tf provider.tf tofu-test/
cd tofu-test
tofu init -no-color > /dev/null
tofu plan -no-color -out=plan.tofu > /dev/null
tofu show -no-color plan.tofu > ../plan-tofu.txt
cd ..
head -20 plan-tofu.txt
Both showed the same resource to create.
✓ Both tools see the same thing. Parity confirmed.
diff plan-terraform.txt plan-tofu.txt | head -20 || echo "outputs identical (or minor diff)"
You should get either no output (identical) or a minor stylistic diff (for example, the header "Terraform used the selected providers" vs "OpenTofu used..."). Semantically, the same thing.
In CI this diff (minus the headers) is checked regularly. If a large diff suddenly appears, a feature has diverged, and it is time to decide which one you pick.
✓ The plans are compared. Divergence shows up clearly.
mkdir -p .github/workflows
cat > .github/workflows/parity.yml <<'EOF'
name: Parity CI
on:
push:
branches: [main]
pull_request:
jobs:
terraform-plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.9.8
- run: terraform init -input=false
- run: terraform plan -input=false -no-color
opentofu-plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.5
- run: tofu init -input=false
- run: tofu plan -input=false -no-color
EOF
cat .github/workflows/parity.yml
Two independent jobs. If one is green and the other is red, the divergence shows up at once. On a critical divergence the PR is blocked.
✓ The matrix workflow is written. On real GitHub both jobs run in parallel.
The most important property, state is compatible.
# apply through Terraform
cd /home/student/parity
terraform apply -auto-approve plan.terraform > /dev/null
ls terraform.tfstate
# OpenTofu can now work with this state
tofu show terraform.tfstate 2>&1 | head -15
OpenTofu read the state created by Terraform correctly. This is the
basis of the painless migration: you switch CI from terraform to
tofu and change nothing else.
The reverse works too: state from tofu apply is read by
terraform.
✓ State is fully compatible. Migration in both directions without conversion.
The decision:
cat > /tmp/decision.md <<'EOF'
| Signal | Choice |
|---|---|
| Team already on HashiCorp Terraform / HCP | Terraform |
| New project, no lock-in | OpenTofu (MPL-license) |
| You need Stacks (HCP) | Terraform |
| You need state encryption at rest | OpenTofu (native) |
| You need exclude in for_each | OpenTofu 1.8+ |
| Team on Atlantis / Spacelift | Check support for both in your tool |
| Air-gapped / regulated | OpenTofu (Linux Foundation, MPL) |
For most teams: matrix CI is the insurance, and the default choice
is set by your current infrastructure and risk tolerance.
EOF
cat /tmp/decision.md
In a real team this is part of an architectural decision; an ADR records it.
✓ You know when to use which. Next, the capstone project.
A real Terraform to OpenTofu migration for a team:
Pin the current Terraform (1.5.7, the last MPL one). You can keep working without any tricks.
Install OpenTofu in parallel on dev machines. Run
tofu plan on the current stacks, there should be no divergence.
Add matrix CI, tofu plan next to terraform plan.
Green, fine, carry on.
Switch in CI. In a single feature branch, swap
setup-terraform for setup-opentofu. Test it for a week.
Switch main. Once you have confidence, switch everyone over. State is not touched.
Remove the terraform job a month or two after the state
is stable.
If something breaks, the terraform job is still there, your
fallback is ready.
More on this in tf-opentofu-parity.
OpenTofu (tofu) is a drop-in replacement for Terraform. The image already
ships it next to terraform. tofu init/plan/apply works with the same HCL
and the same state. CI with two jobs (terraform + tofu) catches divergence
right away.
команды
tofu --versionOpenTofu is preinstalled in the sandbox image.tofu init && tofu planthe usual commands, run through tofu.diff plan.terraform plan.tofucompare the plan output for divergence.концепции