opentofu-coder
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenTofu Coder
OpenTofu 编码指南
⚠️ SIMPLICITY FIRST - Default to Flat Files
⚠️ 优先简洁 - 默认使用扁平文件结构
ALWAYS start with the simplest approach. Only add complexity when explicitly requested.
始终从最简单的方案入手。仅在明确要求时才增加复杂度。
Simple (DEFAULT) vs Overengineered
简洁(默认)vs 过度设计
| Aspect | ✅ Simple (Default) | ❌ Overengineered |
|---|---|---|
| Structure | Flat .tf files in one directory | Nested modules/ + environments/ directories |
| Modules | None or only remote registry modules | Custom local modules for simple resources |
| Environments | Workspaces OR single tfvars | Duplicate directory per environment |
| Variables | Inline defaults, minimal tfvars | Complex variable hierarchies |
| File count | 3-5 .tf files total | 15+ files across nested directories |
| 维度 | ✅ 简洁(默认) | ❌ 过度设计 |
|---|---|---|
| 结构 | 单目录下的扁平.tf文件 | 嵌套modules/ + environments/目录 |
| 模块 | 无或仅使用远程注册表模块 | 为简单资源创建自定义本地模块 |
| 环境 | 工作区或单个tfvars文件 | 每个环境对应重复目录 |
| 变量 | 内联默认值,最小化tfvars | 复杂的变量层级结构 |
| 文件数量 | 总计3-5个.tf文件 | 嵌套目录下共15+个文件 |
When to Use Simple Approach (90% of cases)
何时使用简洁方案(90%场景)
- Managing 1-5 resources of each type
- Single provider, single region
- Small team or solo developer
- Standard infrastructure patterns
- 管理每种类型1-5个资源
- 单一提供商、单一区域
- 小团队或独立开发者
- 标准基础设施模式
When Complexity is Justified (10% of cases)
何时可增加复杂度(10%场景)
- Enterprise multi-region, multi-account
- Reusable modules shared across teams
- Complex dependency chains
- User explicitly requests modular structure
Rule: If you can define everything in 5 flat .tf files, DO IT.
- 企业级多区域、多账户
- 团队间共享的可复用模块
- 复杂依赖链
- 用户明确要求模块化结构
规则:如果可以用5个扁平.tf文件定义所有内容,就这么做。
Simple Project Structure (DEFAULT)
简洁项目结构(默认)
infra/
├── main.tf # All resources
├── variables.tf # Input variables
├── outputs.tf # Outputs
├── versions.tf # Provider versions
└── terraform.tfvars # Variable values (gitignored)infra/
├── main.tf # 所有资源
├── variables.tf # 输入变量
├── outputs.tf # 输出
├── versions.tf # 提供商版本
└── terraform.tfvars # 变量值(已加入git忽略)Overview
概述
OpenTofu is a community-driven, open-source fork of Terraform under MPL-2.0 license, maintained by the Linux Foundation. It uses HashiCorp Configuration Language (HCL) for declarative infrastructure management across cloud providers.
OpenTofu是由Linux基金会维护的、社区驱动的开源Terraform分支,采用MPL-2.0许可证。它使用HashiCorp配置语言(HCL)实现跨云提供商的声明式基础设施管理。
Core Philosophy
核心理念
Prioritize:
- Declarative over imperative: Describe desired state, not steps
- Idempotency: Apply safely multiple times with same result
- Modularity: Compose infrastructure from reusable modules
- State as truth: State file is the source of truth for managed resources
- Immutable infrastructure: Replace resources rather than mutate in place
优先遵循:
- 声明式而非命令式:描述期望状态,而非步骤
- 幂等性:多次执行应用操作可得到相同结果
- 模块化:通过可复用模块组合基础设施
- 状态作为事实来源:状态文件是托管资源的事实来源
- 不可变基础设施:替换资源而非原地修改
HCL Syntax Essentials
HCL语法要点
Resource Blocks
资源块
hcl
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "${var.project}-web"
Environment = var.environment
}
}hcl
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "${var.project}-web"
Environment = var.environment
}
}Data Sources
数据源
hcl
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
owners = ["099720109477"] # Canonical
}hcl
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
owners = ["099720109477"] # Canonical
}Variables
变量
hcl
variable "environment" {
description = "Deployment environment (dev, staging, prod)"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_types" {
description = "Map of environment to instance type"
type = map(string)
default = {
dev = "t3.micro"
staging = "t3.small"
prod = "t3.medium"
}
}hcl
variable "environment" {
description = "部署环境(dev, staging, prod)"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "环境必须是dev、staging或prod。"
}
}
variable "instance_types" {
description = "环境到实例类型的映射"
type = map(string)
default = {
dev = "t3.micro"
staging = "t3.small"
prod = "t3.medium"
}
}Outputs
输出
hcl
output "instance_ip" {
description = "Public IP of the web instance"
value = aws_instance.web.public_ip
sensitive = false
}
output "database_password" {
description = "Generated database password"
value = random_password.db.result
sensitive = true
}hcl
output "instance_ip" {
description = "Web实例的公网IP"
value = aws_instance.web.public_ip
sensitive = false
}
output "database_password" {
description = "生成的数据库密码"
value = random_password.db.result
sensitive = true
}Locals
本地值
hcl
locals {
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "OpenTofu"
}
name_prefix = "${var.project}-${var.environment}"
}hcl
locals {
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "OpenTofu"
}
name_prefix = "${var.project}-${var.environment}"
}Meta-Arguments
元参数
count - Create Multiple Instances
count - 创建多个实例
hcl
resource "aws_instance" "server" {
count = var.server_count
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "${local.name_prefix}-server-${count.index}"
}
}hcl
resource "aws_instance" "server" {
count = var.server_count
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "${local.name_prefix}-server-${count.index}"
}
}for_each - Create from Map/Set
for_each - 从映射/集合创建
hcl
resource "aws_iam_user" "users" {
for_each = toset(var.user_names)
name = each.value
path = "/users/"
}
resource "aws_security_group_rule" "ingress" {
for_each = var.ingress_rules
type = "ingress"
from_port = each.value.port
to_port = each.value.port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
security_group_id = aws_security_group.main.id
}hcl
resource "aws_iam_user" "users" {
for_each = toset(var.user_names)
name = each.value
path = "/users/"
}
resource "aws_security_group_rule" "ingress" {
for_each = var.ingress_rules
type = "ingress"
from_port = each.value.port
to_port = each.value.port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
security_group_id = aws_security_group.main.id
}depends_on - Explicit Dependencies
depends_on - 显式依赖
hcl
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
depends_on = [
aws_db_instance.database,
aws_elasticache_cluster.cache
]
}hcl
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
depends_on = [
aws_db_instance.database,
aws_elasticache_cluster.cache
]
}lifecycle - Control Resource Behavior
lifecycle - 控制资源行为
hcl
resource "aws_instance" "critical" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
prevent_destroy = true
create_before_destroy = true
ignore_changes = [
tags["LastUpdated"],
user_data
]
}
}hcl
resource "aws_instance" "critical" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
prevent_destroy = true
create_before_destroy = true
ignore_changes = [
tags["LastUpdated"],
user_data
]
}
}Replace when AMI changes
AMI变更时替换资源
resource "aws_instance" "immutable" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
replace_triggered_by = [
null_resource.ami_trigger
]
}
}
undefinedresource "aws_instance" "immutable" {
ami = var.ami_id
instance_type = var.instance_type
lifecycle {
replace_triggered_by = [
null_resource.ami_trigger
]
}
}
undefinedModule Design
模块设计
Module Structure
模块结构
modules/
└── vpc/
├── main.tf # Primary resources
├── variables.tf # Input variables
├── outputs.tf # Output values
├── versions.tf # Required providers
└── README.md # Documentationmodules/
└── vpc/
├── main.tf # 核心资源
├── variables.tf # 输入变量
├── outputs.tf # 输出值
├── versions.tf # 所需提供商
└── README.md # 文档Calling Modules
调用模块
hcl
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
environment = var.environment
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}hcl
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
environment = var.environment
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}Remote module with version
指定版本的远程模块
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = local.cluster_name
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
undefinedmodule "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = local.cluster_name
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
undefinedModule Best Practices
模块最佳实践
- Expose minimal, clear interface of variables
- Use sensible defaults where possible
- Document all variables and outputs
- Avoid over-generic "god" modules
- Prefer composition over configuration flags
- Version pin remote modules
- 暴露最小、清晰的变量接口
- 尽可能使用合理的默认值
- 为所有变量和输出编写文档
- 避免过度通用的“上帝模块”
- 优先组合而非配置标志
- 固定远程模块的版本
State Management
状态管理
Remote Backend (S3)
远程后端(S3)
hcl
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}hcl
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}OpenTofu State Encryption (Unique Feature)
OpenTofu 状态加密(独有功能)
hcl
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_encryption_passphrase
}
method "aes_gcm" "encrypt" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.encrypt
enforced = true
}
plan {
method = method.aes_gcm.encrypt
enforced = true
}
}
}hcl
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_encryption_passphrase
}
method "aes_gcm" "encrypt" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.encrypt
enforced = true
}
plan {
method = method.aes_gcm.encrypt
enforced = true
}
}
}State Commands
状态命令
bash
undefinedbash
undefinedList resources in state
列出状态中的资源
tofu state list
tofu state list
Show specific resource
查看特定资源
tofu state show aws_instance.web
tofu state show aws_instance.web
Move resource (refactoring)
移动资源(重构)
tofu state mv aws_instance.old aws_instance.new
tofu state mv aws_instance.old aws_instance.new
Remove from state (without destroying)
从状态中移除(不销毁资源)
tofu state rm aws_instance.imported
tofu state rm aws_instance.imported
Import existing resource
导入现有资源
tofu import aws_instance.web i-1234567890abcdef0
undefinedtofu import aws_instance.web i-1234567890abcdef0
undefinedProvider Configuration
提供商配置
AWS Provider
AWS提供商
hcl
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = local.common_tags
}
}hcl
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = local.common_tags
}
}Multiple provider configurations
多提供商配置
provider "aws" {
alias = "us_west"
region = "us-west-2"
}
resource "aws_instance" "west" {
provider = aws.us_west
...
}
undefinedprovider "aws" {
alias = "us_west"
region = "us-west-2"
}
resource "aws_instance" "west" {
provider = aws.us_west
...
}
undefinedProvider Authentication
提供商认证
hcl
undefinedhcl
undefinedEnvironment variables (preferred)
环境变量(推荐)
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
AWS_PROFILE for named profiles
AWS_PROFILE 用于命名配置文件
Named profile from ~/.aws/credentials (recommended)
~/.aws/credentials中的命名配置文件(推荐)
provider "aws" {
region = var.aws_region
profile = "suppli" # Uses [suppli] section from ~/.aws/credentials
}
provider "aws" {
region = var.aws_region
profile = "suppli" # 使用~/.aws/credentials中的[suppli]段
}
Or explicit (NOT recommended for secrets)
显式配置(不推荐用于密钥)
provider "aws" {
region = var.aws_region
access_key = var.aws_access_key # Use env vars instead
secret_key = var.aws_secret_key
}
provider "aws" {
region = var.aws_region
access_key = var.aws_access_key # 建议使用环境变量替代
secret_key = var.aws_secret_key
}
Assume role
角色假设
provider "aws" {
region = var.aws_region
assume_role {
role_arn = "arn:aws:iam::123456789012:role/DeployRole"
session_name = "TofuDeployment"
}
}
undefinedprovider "aws" {
region = var.aws_region
assume_role {
role_arn = "arn:aws:iam::123456789012:role/DeployRole"
session_name = "TofuDeployment"
}
}
undefinedEnvironment Strategies
环境策略
Workspaces
工作区
bash
undefinedbash
undefinedCreate and switch workspaces
创建并切换工作区
tofu workspace new dev
tofu workspace new staging
tofu workspace new prod
tofu workspace new dev
tofu workspace new staging
tofu workspace new prod
Switch workspace
切换工作区
tofu workspace select prod
tofu workspace select prod
List workspaces
列出工作区
tofu workspace list
```hcltofu workspace list
```hclUse workspace in configuration
在配置中使用工作区
locals {
environment = terraform.workspace
instance_type = {
dev = "t3.micro"
staging = "t3.small"
prod = "t3.medium"
}[terraform.workspace]
}
undefinedlocals {
environment = terraform.workspace
instance_type = {
dev = "t3.micro"
staging = "t3.small"
prod = "t3.medium"
}[terraform.workspace]
}
undefinedDirectory-Based Environments (Alternative)
基于目录的环境(替代方案)
infrastructure/
├── modules/ # Shared modules
│ ├── vpc/
│ └── eks/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ └── terraform.tfvarsinfrastructure/
├── modules/ # 共享模块
│ ├── vpc/
│ └── eks/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ └── terraform.tfvarsCLI Workflow
CLI 工作流
bash
undefinedbash
undefinedInitialize working directory
初始化工作目录
tofu init
tofu init
Validate configuration
验证配置
tofu validate
tofu validate
Format code
格式化代码
tofu fmt -recursive
tofu fmt -recursive
Preview changes
预览变更
tofu plan -out=plan.tfplan
tofu plan -out=plan.tfplan
Apply changes
应用变更
tofu apply plan.tfplan
tofu apply plan.tfplan
Destroy infrastructure
销毁基础设施
tofu destroy
tofu destroy
Show current state
查看当前状态
tofu show
tofu show
Refresh state from actual infrastructure
从实际基础设施刷新状态
tofu refresh
undefinedtofu refresh
undefinedBest Practices Checklist
最佳实践检查清单
When writing OpenTofu/Terraform code:
- Use remote backend with locking for team use
- Enable state encryption (OpenTofu feature)
- Never commit or
.tfstatewith secrets to VCS.tfvars - Pin provider and module versions
- Use before every
tofu planapply - Use for critical resources
lifecycle.prevent_destroy - Document all variables and outputs
- Use for computed values and tags
locals - Prefer over
for_eachfor named resourcescount - Use validation blocks for variable constraints
- Store secrets in secret managers, not in code
编写OpenTofu/Terraform代码时:
- 团队使用时,启用带锁定功能的远程后端
- 启用状态加密(OpenTofu独有功能)
- 切勿将.tfstate或包含密钥的.tfvars提交到版本控制系统
- 固定提供商和模块版本
- 每次apply前先执行tofu plan
- 为关键资源设置lifecycle.prevent_destroy
- 为所有变量和输出编写文档
- 使用locals存储计算值和标签
- 对于命名资源,优先使用for_each而非count
- 为变量添加验证块
- 将密钥存储在密钥管理器中,而非代码中
Common Patterns
常见模式
Conditional Resources
条件资源
hcl
resource "aws_eip" "static" {
count = var.create_elastic_ip ? 1 : 0
instance = aws_instance.web.id
}hcl
resource "aws_eip" "static" {
count = var.create_elastic_ip ? 1 : 0
instance = aws_instance.web.id
}Dynamic Blocks
动态块
hcl
resource "aws_security_group" "main" {
name = "${local.name_prefix}-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}hcl
resource "aws_security_group" "main" {
name = "${local.name_prefix}-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}References
参考资料
For detailed patterns and examples:
- resources/hcl-patterns.md - Advanced HCL patterns
- resources/project-scaffolding.md - Directory structure, .gitignore, next_steps output, security-first variables
- resources/post-provisioning.md - bin/setup-server scripts for post-infra, pre-deployment setup
- resources/state-management.md - State operations and encryption
- resources/provider-examples.md - Multi-cloud provider configs
- resources/makefile-automation.md - Makefile workflows for plan/apply/destroy
如需详细模式和示例:
- resources/hcl-patterns.md - 高级HCL模式
- resources/project-scaffolding.md - 目录结构、.gitignore、下一步输出、安全优先的变量
- resources/post-provisioning.md - 用于基础设施部署后、应用部署前设置的bin/setup-server脚本
- resources/state-management.md - 状态操作与加密
- resources/provider-examples.md - 多云提供商配置
- resources/makefile-automation.md - 用于plan/apply/destroy的Makefile工作流