lesson ── terraform-advanced ── ~12 мин ── 6 шагов
OpenTofu, fork Terraform под MPL-2.0. Бинарь tofu уже лежит в образе
рядом с terraform. На уроке прогоним один HCL обоими, сравним результат
и соберём matrix-pipeline для CI. Это страховка от lock-in HashiCorp-лицензии.
интерактивный 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
Оба бинаря лежат в /usr/local/bin. Версии могут не совпадать
это норма, fork ветки развиваются параллельно.
✓ Tofu и terraform в одном 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
Сначала 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
Теперь OpenTofu (в новом каталоге чтобы не путать state):
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
Оба показали тот же ресурс к созданию.
✓ Оба инструмента видят одно и то же. Parity подтверждена.
diff plan-terraform.txt plan-tofu.txt | head -20 || echo "outputs identical (or minor diff)"
Должно быть либо нет вывода (identical), либо minor stylistic diff (например, заголовок «Terraform used the selected providers» vs «OpenTofu used...»). Семантически, то же самое.
В CI этот diff (минус headers) проверяется регулярно. Если внезапно large diff, фича расходится, время решить какой выбираем.
✓ Plan'ы сравнены. Расхождения видны явно.
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
Два независимых job'а. Если один зелёный, другой красный сразу видно расхождение. На critical-расхождения PR блокируется.
✓ Matrix-workflow написан. В реальном GitHub оба job'а гоняются параллельно.
Самое важное свойство, state совместим.
# apply через Terraform
cd /home/student/parity
terraform apply -auto-approve plan.terraform > /dev/null
ls terraform.tfstate
# OpenTofu теперь сможет работать с этим state'ом
tofu show terraform.tfstate 2>&1 | head -15
OpenTofu корректно прочитал state, созданный Terraform'ом. Это
и есть основа miracle-миграции: переключаешь CI с terraform на
tofu, ничего больше не меняешь.
Обратное тоже работает: state от tofu apply читается
terraform.
✓ State полностью совместим. Миграция в обе стороны без conversion.
Решение:
cat > /tmp/decision.md <<'EOF'
| Сигнал | Выбор |
|---|---|
| Текущая команда на HashiCorp Terraform / HCP | Terraform |
| Новый проект, нет lock-in'а | OpenTofu (MPL-license) |
| Нужны Stacks (HCP) | Terraform |
| Нужно state encryption at rest | OpenTofu (нативно) |
| Нужен exclude в for_each | OpenTofu 1.8+ |
| Команда на Atlantis / Spacelift | Проверь поддержку обоих в твоём tool'е |
| Air-gapped / regulated | OpenTofu (Linux Foundation, MPL) |
Для большинства команд: matrix-CI = страховка, выбор default'а
определяется текущей инфраструктурой и risk-tolerance.
EOF
cat /tmp/decision.md
В реальной команде это часть архитектурного решения; ADR это фиксирует.
✓ Знаешь когда что. Дальше, capstone-проект.
Реальная миграция Terraform → OpenTofu для команды:
Pin'нуть текущий Terraform (1.5.7, последний MPL). Можно работать дальше без хитростей.
Параллельно ставить OpenTofu на dev-machines. Прогнать
tofu plan на текущих stack'ах, расхождений быть не должно.
Matrix-CI добавить, tofu plan рядом с terraform plan.
Зелёный, ок продолжаем.
Переключение в CI. В одном feature-branch меняем
setup-terraform → setup-opentofu. Тестируем неделю.
Свич main'а. После confidence, переключаем всех. State не трогается.
Удаляем terraform job'у через месяц-два после
stable-state'а.
Что-то ломается, terraform job всё ещё там, fallback готов.
Подробнее, tf-opentofu-parity.
OpenTofu (tofu), drop-in replacement Terraform. В образе уже стоит
рядом с terraform. tofu init/plan/apply работает с тем же HCL и тем
же state'ом. CI с двумя jobs (terraform + tofu) ловит расхождения сразу.
команды
tofu --versionOpenTofu предустановлен в sandbox-образе.tofu init && tofu planобычные команды, но через tofu.diff plan.terraform plan.tofuсравнить вывод plan'ов на расхождения.концепции