痛点
2023 年 HashiCorp 将 Terraform 许可证从 MPL 2.0 切换为 BSL 1.1,对商业用途施加限制。对于中大型团队,这意味着:
- 合规风险:如果你的产品或服务与 HashiCorp 构成竞争关系,继续使用 Terraform 可能违反许可证
- 供应商锁定:BSL 限制了社区分发和二次开发的自由度
- 长期成本不确定性:未来可能进一步收紧许可或推商业版
OpenTofu 是 Linux Foundation 托管的 Terraform 开源分支(fork),保持 MPL 2.0 许可,API 兼容 Terraform 1.6+,并持续迭代新特性(如 state encryption、provider-defined functions)。如果你的团队正在评估迁移,这篇文章给出一套经过生产验证的迁移方案。
方案概览
┌──────────────────────────────────────────────┐
│ 迁移路径(零停机,渐进式) │
├──────────────────────────────────────────────┤
│ 1. 环境评估 → 2. 安装 OpenTofu │
│ 3. State 兼容性验证 → 4. CI/CD 管道切换 │
│ 5. 灰度推广 → 6. 全量替换 │
└──────────────────────────────────────────────┘
核心原则:OpenTofu 与 Terraform 1.6.x state 文件完全兼容,迁移本质上是替换二进制,而非重写代码。
实操步骤
Step 1:安装 OpenTofu
# Linux (amd64) — 推荐用官方安装脚本
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh -s -- --install-method standalone
# 验证版本
tofu --version
# OpenTofu v1.8.x
也可通过 brew install opentofu(macOS)或容器镜像 ghcr.io/opentofu/opentofu:latest 使用。
Step 2:现有项目兼容性检查
cd /path/to/your-terraform-project
# 直接用 tofu 执行 init(使用已有 .terraform.lock.hcl)
tofu init
# 生成 plan,对比 terraform plan 的输出
tofu plan -out=tofu.tfplan
# 关键:确认 plan 中无差异(No changes)
# 如果资源数量与 terraform plan 一致,说明完全兼容
注意事项:
- 如果使用了 terraform block 中的 required_version 约束,需改为兼容 OpenTofu 的写法:
terraform {
# 兼容写法:同时适配 Terraform 和 OpenTofu
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
- OpenTofu 沿用 Terraform Registry 的 provider,无需更换 provider source
Step 3:State 文件验证与备份
# 备份当前 state(无论用本地还是远端 backend)
tofu state pull > state_backup_$(date +%Y%m%d).json
# 验证 state 中的资源数量
tofu state list | wc -l
# 对比 terraform state list 的输出
diff <(terraform state list | sort) <(tofu state list | sort)
# 预期输出为空(无差异)
对于使用 S3 + DynamoDB 作为远端 backend 的团队,OpenTofu 完全兼容,无需任何 backend 配置修改:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/infra.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Step 4:CI/CD 管道切换
以 GitHub Actions 为例,替换 hashicorp/setup-terraform 为 opentofu/setup-opentofu:
# .github/workflows/infra.yml
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: "1.8.0"
- name: Init
run: tofu init -no-color
- name: Plan
run: tofu plan -no-color -out=plan.tfplan
- name: Apply (main branch only)
if: github.ref == 'refs/heads/main'
run: tofu apply -no-color -auto-approve plan.tfplan
对于 GitLab CI,将 image: hashicorp/terraform:latest 改为 image: ghcr.io/opentofu/opentofu:latest,命令从 terraform 改为 tofu。
Step 5:利用 OpenTofu 独有特性
迁移完成后,可以启用 OpenTofu 的差异化功能:
State Encryption(生产强烈推荐):
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_encryption_passphrase
}
method "aes_gcm" "default" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.default
}
plan {
method = method.aes_gcm.default
}
}
}
这解决了 Terraform 长期被诟病的 state 文件明文存储敏感信息 问题。即使 S3 bucket 泄露,攻击者也无法读取 state 中的密码、密钥等。
避坑指南
1. Provider 版本锁定问题
现象:tofu init 报错 provider not found in registry
原因:某些企业私有 Registry 的 provider 签名验证机制不兼容
解决:
# 临时跳过签名验证(仅用于迁移验证,生产环境应修复 Registry 配置)
tofu init -upgrade -verify-plugins=false
2. Wrapper 脚本兼容
现象:团队内部封装的 Makefile 或脚本硬编码了 terraform 命令
解决:设置 alias 做平滑过渡
# /etc/profile.d/tofu.sh — 全局 alias
alias terraform='tofu'
# 或在 Makefile 中使用变量
TF_BIN ?= tofu
plan:
$(TF_BIN) plan
3. Terraform Cloud/Enterprise 用户
现象:使用 cloud {} block 作为 backend 的项目无法直接迁移
解决:OpenTofu 不支持 Terraform Cloud backend,需先将 state 迁移到 S3/GCS/Consul 等开放 backend:
# 先从 Terraform Cloud 拉取 state
terraform state pull > local.tfstate
# 修改 backend 配置为 S3
# 然后用 OpenTofu 初始化并推送
tofu init -migrate-state
总结
| 维度 | Terraform | OpenTofu |
|---|---|---|
| 许可证 | BSL 1.1(限制商业) | MPL 2.0(完全开源) |
| State 加密 | ❌ 不支持 | ✅ 内置 AES-GCM |
| Provider 兼容 | — | 100% 兼容 |
| 社区治理 | HashiCorp 主导 | Linux Foundation 托管 |
| 迁移成本 | — | 极低(替换二进制) |
核心结论:OpenTofu 迁移的技术门槛极低(本质是 s/terraform/tofu/g),真正的挑战在于团队流程切换和 CI/CD 管道更新。建议采用灰度策略——先在非生产环境验证,再逐步推广到生产 module。如果你还在用 Terraform Cloud,需额外规划 backend 迁移,这是唯一有实质工作量的环节。