前言
在 Infrastructure as Code(IaC)領域中,Terraform 長期以來一直是業界標準工具。然而,2023 年 HashiCorp 宣布將 Terraform 的授權從開源的 Mozilla Public License 2.0(MPL 2.0)變更為 Business Source License 1.1(BSL 1.1),這項決定在開源社群引發了巨大的迴響。作為回應,OpenTofu 應運而生,成為 Terraform 的真正開源替代方案。
本文將深入探討 OpenTofu 的背景、與 Terraform 的差異、安裝遷移方式,以及企業採用時的各種考量。
1. OpenTofu 背景與緣起
HashiCorp 授權變更事件
2023 年 8 月,HashiCorp 宣布將旗下產品(包括 Terraform、Vault、Consul 等)的授權從 MPL 2.0 變更為 BSL 1.1。這項變更意味著:
- 商業使用限制:競爭對手無法直接使用這些工具提供類似的託管服務
- 開源精神受損:BSL 不符合 Open Source Initiative(OSI)的開源定義
- 社群貢獻疑慮:許多貢獻者擔心其貢獻被商業化利用
OpenTofu 的誕生
為了維護 Terraform 的開源精神,Linux Foundation 在 2023 年 9 月宣布成立 OpenTofu 專案:
- Fork 自 Terraform:基於 Terraform v1.5.x 的最後一個 MPL 2.0 版本
- 真正的開源:採用 MPL 2.0 授權,永久保持開源
- 社群驅動:由 Linux Foundation 管理,確保中立治理
- 企業支持:獲得 Spacelift、env0、Scalr 等多家公司支持
1
2
3
4
5
6
| Timeline:
2023-08 HashiCorp 宣布授權變更
2023-09 OpenTofu 專案成立
2023-12 OpenTofu 1.6.0 正式發布
2024-03 OpenTofu 1.7.0 發布,新增獨特功能
2025-xx 持續發展,功能逐漸分化
|
授權差異
| 項目 | Terraform | OpenTofu |
|---|
| 授權 | BSL 1.1 | MPL 2.0 |
| 開源認證 | 否 | 是(OSI 認證) |
| 商業使用 | 有限制 | 無限制 |
| 社群治理 | HashiCorp 主導 | Linux Foundation 治理 |
功能差異
從 OpenTofu 1.7 開始,兩者的功能開始出現分化:
OpenTofu 獨有功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| # 1. State Encryption - 狀態檔案加密
terraform {
encryption {
key_provider "pbkdf2" "my_passphrase" {
passphrase = var.state_passphrase
}
method "aes_gcm" "my_method" {
keys = key_provider.pbkdf2.my_passphrase
}
state {
method = method.aes_gcm.my_method
}
}
}
# 2. Early Variable/Local Evaluation
# 可在 module source 和 backend configuration 中使用變數
locals {
environment = "production"
}
module "vpc" {
source = "git::https://github.com/org/modules.git//vpc?ref=${local.environment}"
}
# 3. Provider-defined Functions
# Provider 可以定義自己的函數
output "parsed_arn" {
value = provider::aws::arn_parse("arn:aws:s3:::my-bucket")
}
|
1
2
3
4
5
6
7
8
9
10
11
12
| # 1. Stacks (Terraform Cloud 功能)
# 用於管理多個相關的 Terraform 配置
# 2. Ephemeral Values (1.10+)
# 臨時值,不會儲存在 state 中
variable "temporary_token" {
type = string
ephemeral = true
}
# 3. terraform test 功能增強
# 原生測試框架
|
CLI 差異
1
2
3
4
5
6
7
8
9
10
11
12
| # Terraform
terraform init
terraform plan
terraform apply
# OpenTofu - 完全相容的 CLI
tofu init
tofu plan
tofu apply
# OpenTofu 特有命令
tofu state encryption # 管理狀態加密
|
3. 安裝與遷移
安裝 OpenTofu
macOS
1
2
3
4
5
6
| # 使用 Homebrew
brew update
brew install opentofu
# 驗證安裝
tofu version
|
Linux (Debian/Ubuntu)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # 安裝 GPG key 和 repository
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sudo bash -s -- --install-method deb
# 或手動安裝
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/opentofu-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/opentofu-archive-keyring.gpg] \
https://packages.opentofu.org/opentofu/tofu/any/ any main" | \
sudo tee /etc/apt/sources.list.d/opentofu.list > /dev/null
sudo apt-get update
sudo apt-get install tofu
|
Linux (RHEL/CentOS/Fedora)
1
2
3
4
5
| # 使用安裝腳本
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sudo bash -s -- --install-method rpm
# 驗證
tofu version
|
Windows
1
2
3
4
5
6
| # 使用 Chocolatey
choco install opentofu
# 或使用 Scoop
scoop bucket add opentofu https://github.com/opentofu/scoop-bucket
scoop install opentofu
|
Docker
1
2
3
4
5
6
| # 使用官方 Docker image
docker pull ghcr.io/opentofu/opentofu:latest
# 執行
docker run --rm -v $(pwd):/workspace -w /workspace \
ghcr.io/opentofu/opentofu:latest init
|
基本遷移步驟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 1. 備份現有狀態
cp terraform.tfstate terraform.tfstate.backup
cp -r .terraform .terraform.backup
# 2. 清理 Terraform 快取
rm -rf .terraform
rm -f .terraform.lock.hcl
# 3. 初始化 OpenTofu
tofu init
# 4. 驗證狀態
tofu plan
# 應該顯示 "No changes" 如果遷移成功
|
處理 Provider Lock 檔案
1
2
3
4
5
6
7
8
| # 重新產生 lock 檔案
tofu providers lock \
-platform=linux_amd64 \
-platform=darwin_amd64 \
-platform=darwin_arm64
# 檢查 lock 檔案
cat .terraform.lock.hcl
|
CI/CD Pipeline 遷移
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # GitHub Actions 範例
name: OpenTofu CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
tofu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.0
- name: OpenTofu Init
run: tofu init
- name: OpenTofu Format Check
run: tofu fmt -check -recursive
- name: OpenTofu Validate
run: tofu validate
- name: OpenTofu Plan
run: tofu plan -out=tfplan
- name: OpenTofu Apply
if: github.ref == 'refs/heads/main'
run: tofu apply -auto-approve tfplan
|
4. 相容性與功能
| Terraform 版本 | OpenTofu 版本 | 相容性說明 |
|---|
| 1.5.x | 1.6.x | 完全相容 |
| 1.6.x | 1.6.x | 大部分相容 |
| 1.7.x | 1.7.x | 核心相容,部分功能分化 |
| 1.8.x+ | 1.8.x+ | 功能開始顯著分化 |
State 檔案相容性
1
2
3
4
5
6
| # 檢查 state 版本
cat terraform.tfstate | jq '.version, .terraform_version'
# OpenTofu 支援的 state 版本
# version: 4 (完全支援)
# terraform_version: 1.5.x 或更早 (完全支援)
|
Provider 相容性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 大多數 Provider 完全相容
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.0"
}
}
}
|
模組相容性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Terraform Registry 模組繼續可用
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
}
# OpenTofu Registry 模組
module "eks" {
source = "registry.opentofu.org/terraform-aws-modules/eks/aws"
version = "20.0.0"
cluster_name = "my-cluster"
}
|
5. 社群與發展路線
社群治理結構
OpenTofu 採用開放的社群治理模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Linux Foundation
│
▼
┌─────────────────┐
│ Technical │
│ Steering │
│ Committee (TSC) │
└────────┬────────┘
│
┌────┴────┐
▼ ▼
┌───────┐ ┌───────┐
│ Core │ │ Eco- │
│ Team │ │ system│
└───────┘ └───────┘
|
貢獻方式
1
2
3
4
5
6
7
8
9
10
11
12
| # Fork 並 clone repository
git clone https://github.com/opentofu/opentofu.git
cd opentofu
# 建立開發環境
go mod download
# 執行測試
go test ./...
# 建置
go build -o tofu ./cmd/tofu
|
發展路線圖
已完成功能(2024-2025)
- State Encryption(狀態加密)
- Early Variable Evaluation(早期變數評估)
- Provider-defined Functions(Provider 自定義函數)
- Registry Mirror 支援
- 改進的錯誤訊息
計畫中功能(2025-2026)
- Enhanced Module Testing
- Improved Import Workflow
- Better IDE Integration
- Performance Optimizations
- Extended Provider Protocol
參與社群
1
2
3
4
5
6
7
8
| # 官方資源
# GitHub: https://github.com/opentofu/opentofu
# Slack: https://opentofu.org/slack
# Forum: https://github.com/opentofu/opentofu/discussions
# 追蹤更新
# RSS: https://opentofu.org/blog/rss.xml
# Newsletter: https://opentofu.org/newsletter
|
6. Provider 生態系統
OpenTofu Registry
OpenTofu 建立了自己的 Registry 系統,同時保持與 Terraform Registry 的相容性:
1
2
3
4
5
6
7
8
9
10
| terraform {
required_providers {
# 預設使用 OpenTofu Registry (優先)
# 回退到 Terraform Registry
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
|
Registry 配置
1
2
3
4
5
6
7
8
9
10
| # ~/.tofurc 或專案內 .tofurc
provider_installation {
network_mirror {
url = "https://registry.opentofu.org/v1/mirror/"
}
direct {
exclude = ["registry.terraform.io/*/*"]
}
}
|
常用 Provider 一覽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| # 雲端平台
terraform {
required_providers {
# AWS
aws = {
source = "hashicorp/aws"
version = "~> 5.30"
}
# Google Cloud
google = {
source = "hashicorp/google"
version = "~> 5.10"
}
# Azure
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.85"
}
# Alibaba Cloud
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.215"
}
}
}
# 容器與 Kubernetes
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.25"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.12"
}
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
}
}
# 監控與維運
terraform {
required_providers {
datadog = {
source = "DataDog/datadog"
version = "~> 3.35"
}
grafana = {
source = "grafana/grafana"
version = "~> 2.10"
}
pagerduty = {
source = "PagerDuty/pagerduty"
version = "~> 3.6"
}
}
}
|
自建 Provider Registry
1
2
3
4
5
6
7
8
9
10
11
| # 使用 OpenTofu Registry Protocol
# 目錄結構
registry/
├── v1/
│ └── providers/
│ └── myorg/
│ └── myprovider/
│ ├── versions
│ └── 1.0.0/
│ └── download/
│ └── linux_amd64
|
1
2
3
4
5
6
7
8
9
| # 配置使用自建 Registry
terraform {
required_providers {
myprovider = {
source = "registry.mycompany.com/myorg/myprovider"
version = "~> 1.0"
}
}
}
|
7. 企業使用考量
法務與合規評估
授權比較
1
2
3
4
5
6
7
8
9
10
11
| MPL 2.0 (OpenTofu):
✓ 可自由使用、修改、分發
✓ 可用於商業目的
✓ 可整合到專有軟體中
✓ 無需公開衍生作品(除非修改 MPL 授權的檔案)
BSL 1.1 (Terraform):
✓ 可用於內部使用
✗ 競爭用途受限
✗ 提供類似託管服務受限
○ 4 年後轉為開源授權
|
技術評估矩陣
| 評估項目 | Terraform | OpenTofu | 備註 |
|---|
| 穩定性 | 高 | 高 | 兩者都成熟穩定 |
| 企業支援 | HashiCorp | 社群 + 第三方 | HashiCorp 提供付費支援 |
| 雲端整合 | Terraform Cloud | 第三方方案 | Spacelift, env0, Scalr |
| 長期維護 | 商業公司 | Linux Foundation | 兩者都可靠 |
| 功能更新 | 快速 | 穩健 | 各有特色功能 |
遷移風險評估
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| #!/bin/bash
# migration-assessment.sh - 遷移評估腳本
echo "=== OpenTofu 遷移評估報告 ==="
# 檢查 Terraform 版本
echo -e "\n[1] Terraform 版本檢查"
terraform version
# 檢查 state 版本
echo -e "\n[2] State 版本檢查"
if [ -f "terraform.tfstate" ]; then
jq '.version, .terraform_version' terraform.tfstate
else
echo "使用遠端 state"
fi
# 檢查 provider 版本
echo -e "\n[3] Provider 版本檢查"
cat .terraform.lock.hcl 2>/dev/null | grep -A2 'provider'
# 檢查模組來源
echo -e "\n[4] 模組來源檢查"
grep -r "source\s*=" *.tf 2>/dev/null | head -20
# 檢查是否使用 Terraform Cloud 功能
echo -e "\n[5] Terraform Cloud 功能檢查"
grep -r "cloud\s*{" *.tf 2>/dev/null
echo -e "\n=== 評估完成 ==="
|
企業級架構範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| # 企業級 OpenTofu 配置範例
terraform {
required_version = ">= 1.7.0"
# 使用加密的 S3 後端
backend "s3" {
bucket = "company-tofu-state"
key = "production/infrastructure.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "tofu-state-lock"
kms_key_id = "arn:aws:kms:ap-northeast-1:123456789:key/xxx"
}
# 狀態加密 (OpenTofu 獨有)
encryption {
key_provider "aws_kms" "main" {
kms_key_id = "arn:aws:kms:ap-northeast-1:123456789:key/xxx"
region = "ap-northeast-1"
}
method "aes_gcm" "default" {
keys = key_provider.aws_kms.main
}
state {
method = method.aes_gcm.default
enforced = true
}
plan {
method = method.aes_gcm.default
enforced = true
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.30"
}
}
}
# 標準化標籤
locals {
common_tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "OpenTofu"
CostCenter = var.cost_center
Owner = var.team_email
}
}
|
成本考量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| Terraform 生態系統成本:
├── Terraform Cloud (Team & Governance)
│ └── $20/user/month 起
├── Terraform Enterprise
│ └── 需要聯繫銷售
└── HashiCorp 支援合約
└── 依規模定價
OpenTofu 生態系統成本:
├── OpenTofu Core
│ └── 免費 (MPL 2.0)
├── 第三方託管方案
│ ├── Spacelift: $20/user/month 起
│ ├── env0: 依使用量計價
│ └── Scalr: $25/user/month 起
└── 自建方案
└── 運維成本
|
8. 遷移最佳實務
遷移前準備
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 1. 完整備份
#!/bin/bash
BACKUP_DIR="terraform-backup-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 備份所有 .tf 檔案
cp -r *.tf "$BACKUP_DIR/"
# 備份 state
if [ -f "terraform.tfstate" ]; then
cp terraform.tfstate "$BACKUP_DIR/"
fi
# 備份 lock 檔案
cp .terraform.lock.hcl "$BACKUP_DIR/" 2>/dev/null
# 備份 .terraform 目錄
cp -r .terraform "$BACKUP_DIR/" 2>/dev/null
echo "備份完成: $BACKUP_DIR"
|
分階段遷移策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| Phase 1: 評估與準備 (1-2 週)
├── 盤點所有 Terraform 專案
├── 評估各專案複雜度
├── 建立測試環境
└── 培訓團隊成員
Phase 2: 試點專案 (2-4 週)
├── 選擇低風險專案
├── 執行遷移
├── 驗證功能
└── 記錄問題與解決方案
Phase 3: 漸進式遷移 (依規模)
├── 依優先序遷移專案
├── 更新 CI/CD pipeline
├── 同步文件
└── 持續監控
Phase 4: 完成與優化 (2 週)
├── 確認所有專案遷移完成
├── 移除 Terraform 相依
├── 探索 OpenTofu 新功能
└── 建立長期維護流程
|
遷移驗證清單
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| #!/bin/bash
# migration-validation.sh
echo "=== OpenTofu 遷移驗證清單 ==="
# 1. 初始化檢查
echo -e "\n[1] 初始化驗證"
tofu init -upgrade
if [ $? -eq 0 ]; then
echo "✓ 初始化成功"
else
echo "✗ 初始化失敗"
exit 1
fi
# 2. 格式檢查
echo -e "\n[2] 格式驗證"
tofu fmt -check -recursive
if [ $? -eq 0 ]; then
echo "✓ 格式正確"
else
echo "⚠ 格式需要調整"
fi
# 3. 驗證配置
echo -e "\n[3] 配置驗證"
tofu validate
if [ $? -eq 0 ]; then
echo "✓ 配置有效"
else
echo "✗ 配置無效"
exit 1
fi
# 4. Plan 檢查
echo -e "\n[4] Plan 驗證 (應無變更)"
tofu plan -detailed-exitcode
PLAN_EXIT=$?
if [ $PLAN_EXIT -eq 0 ]; then
echo "✓ 無變更 - 遷移成功"
elif [ $PLAN_EXIT -eq 2 ]; then
echo "⚠ 偵測到變更 - 請檢查"
else
echo "✗ Plan 失敗"
exit 1
fi
# 5. State 檢查
echo -e "\n[5] State 驗證"
tofu state list | head -10
echo "..."
RESOURCE_COUNT=$(tofu state list | wc -l)
echo "總資源數: $RESOURCE_COUNT"
echo -e "\n=== 驗證完成 ==="
|
常見問題處理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # 問題 1: Provider 版本衝突
# 解決方案: 重新產生 lock 檔案
# tofu providers lock -platform=linux_amd64
# 問題 2: State 版本不相容
# 解決方案: 確認使用相容的 OpenTofu 版本
terraform {
required_version = ">= 1.6.0, < 2.0.0"
}
# 問題 3: 模組來源問題
# 解決方案: 使用明確的 registry 來源
module "example" {
source = "registry.terraform.io/terraform-aws-modules/vpc/aws"
version = "5.0.0"
# 或使用 OpenTofu registry
# source = "registry.opentofu.org/terraform-aws-modules/vpc/aws"
}
# 問題 4: Backend 遷移
# 解決方案: 使用 state migration
# tofu init -migrate-state
|
Alias 設定建議
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # ~/.bashrc 或 ~/.zshrc
# 方案 1: 完全取代
alias terraform="tofu"
alias tf="tofu"
# 方案 2: 共存
alias tofu="tofu"
alias tf="tofu"
# 保留 terraform 指向原始命令
# 方案 3: 環境切換
function use-tofu() {
alias terraform="tofu"
echo "Now using OpenTofu"
}
function use-terraform() {
unalias terraform 2>/dev/null
echo "Now using Terraform"
}
|
總結
OpenTofu 作為 Terraform 的開源替代方案,提供了:
- 真正的開源授權:MPL 2.0 確保永久開源
- 完整的相容性:與 Terraform 生態系統高度相容
- 創新功能:State Encryption、Early Variable Evaluation 等獨特功能
- 穩健的治理:Linux Foundation 確保中立與透明
- 活躍的社群:持續成長的貢獻者與使用者社群
對於重視開源精神、需要避免授權風險,或希望使用 OpenTofu 獨有功能的團隊,遷移到 OpenTofu 是值得考慮的選擇。透過本文介紹的遷移策略與最佳實務,相信能夠順利完成轉換,享受開源 IaC 工具帶來的自由與彈性。
參考資源