opentofu-coder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenTofu 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
StructureFlat .tf files in one directoryNested modules/ + environments/ directories
ModulesNone or only remote registry modulesCustom local modules for simple resources
EnvironmentsWorkspaces OR single tfvarsDuplicate directory per environment
VariablesInline defaults, minimal tfvarsComplex variable hierarchies
File count3-5 .tf files total15+ 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 ] } }
undefined
resource "aws_instance" "immutable" { ami = var.ami_id instance_type = var.instance_type
lifecycle { replace_triggered_by = [ null_resource.ami_trigger ] } }
undefined

Module Design

模块设计

Module Structure

模块结构

modules/
└── vpc/
    ├── main.tf          # Primary resources
    ├── variables.tf     # Input variables
    ├── outputs.tf       # Output values
    ├── versions.tf      # Required providers
    └── README.md        # Documentation
modules/
└── 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 }
undefined
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 }
undefined

Module 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
undefined
bash
undefined

List 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
undefined
tofu import aws_instance.web i-1234567890abcdef0
undefined

Provider 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

...

}
undefined
provider "aws" { alias = "us_west" region = "us-west-2" }
resource "aws_instance" "west" { provider = aws.us_west

...

}
undefined

Provider Authentication

提供商认证

hcl
undefined
hcl
undefined

Environment 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" } }
undefined
provider "aws" { region = var.aws_region
assume_role { role_arn = "arn:aws:iam::123456789012:role/DeployRole" session_name = "TofuDeployment" } }
undefined

Environment Strategies

环境策略

Workspaces

工作区

bash
undefined
bash
undefined

Create 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

```hcl
tofu workspace list

```hcl

Use workspace in configuration

在配置中使用工作区

locals { environment = terraform.workspace
instance_type = { dev = "t3.micro" staging = "t3.small" prod = "t3.medium" }[terraform.workspace] }
undefined
locals { environment = terraform.workspace
instance_type = { dev = "t3.micro" staging = "t3.small" prod = "t3.medium" }[terraform.workspace] }
undefined

Directory-Based Environments (Alternative)

基于目录的环境(替代方案)

infrastructure/
├── modules/           # Shared modules
│   ├── vpc/
│   └── eks/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   │   ├── main.tf
│   │   └── terraform.tfvars
│   └── prod/
│       ├── main.tf
│       └── terraform.tfvars
infrastructure/
├── modules/           # 共享模块
│   ├── vpc/
│   └── eks/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   │   ├── main.tf
│   │   └── terraform.tfvars
│   └── prod/
│       ├── main.tf
│       └── terraform.tfvars

CLI Workflow

CLI 工作流

bash
undefined
bash
undefined

Initialize 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
undefined
tofu refresh
undefined

Best Practices Checklist

最佳实践检查清单

When writing OpenTofu/Terraform code:
  • Use remote backend with locking for team use
  • Enable state encryption (OpenTofu feature)
  • Never commit
    .tfstate
    or
    .tfvars
    with secrets to VCS
  • Pin provider and module versions
  • Use
    tofu plan
    before every
    apply
  • Use
    lifecycle.prevent_destroy
    for critical resources
  • Document all variables and outputs
  • Use
    locals
    for computed values and tags
  • Prefer
    for_each
    over
    count
    for named resources
  • 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工作流