搜索

PythonReactSEOPDF
GitHub Skill

opentofu-coder

This skill guides writing Infrastructure as Code using OpenTofu (open-source Terraform fork). Use when creating .tf files, managing cloud infrastructure, configuring providers, or designing reusable modules.

majesticlabs-dev☆ 20 仓库 Stars3 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

OpenTofu Coder

⚠️ SIMPLICITY FIRST - Default to Flat Files

ALWAYS start with the simplest approach. Only add complexity when explicitly requested.

Simple (DEFAULT) vs Overengineered
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
When to Use Simple Approach (90% of cases)
  • Managing 1-5 resources of each type
  • Single provider, single region
  • Small team or solo developer
  • Standard infrastructure patterns
When Complexity is Justified (10% of cases)
  • 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.

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)

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.

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

Resource Blocks
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  tags = {
    Name        = "${var.project}-web"
    Environment = var.environment
  }
}
Data Sources
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
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"
  }
}
Outputs
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
}
Locals
locals {
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "OpenTofu"
  }

  name_prefix = "${var.project}-${var.environment}"
}

Meta-Arguments

count - Create Multiple Instances
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
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
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
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
resource "aws_instance" "immutable" {
  ami           = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    replace_triggered_by = [
      null_resource.ami_trigger
    ]
  }
}

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
Calling Modules
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
}
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)
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)
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
# List resources in state
tofu state list

# Show specific resource
tofu state show aws_instance.web

# Move resource (refactoring)
tofu state mv aws_instance.old aws_instance.new

# Remove from state (without destroying)
tofu state rm aws_instance.imported

# Import existing resource
tofu import aws_instance.web i-1234567890abcdef0

Provider Configuration

AWS Provider
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
  # ...
}
Provider Authentication
# Environment variables (preferred)
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
# AWS_PROFILE for named profiles

# Named profile from ~/.aws/credentials (recommended)
provider "aws" {
  region  = var.aws_region
  profile = "suppli"  # Uses [suppli] section from ~/.aws/credentials
}

# 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
}

# Assume role
provider "aws" {
  region = var.aws_region

  assume_role {
    role_arn     = "arn:aws:iam::123456789012:role/DeployRole"
    session_name = "TofuDeployment"
  }
}

Environment Strategies

Workspaces
# Create and switch workspaces
tofu workspace new dev
tofu workspace new staging
tofu workspace new prod

# Switch workspace
tofu workspace select prod

# List workspaces
tofu workspace list
# Use workspace in configuration
locals {
  environment = terraform.workspace

  instance_type = {
    dev     = "t3.micro"
    staging = "t3.small"
    prod    = "t3.medium"
  }[terraform.workspace]
}
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

CLI Workflow

# Initialize working directory
tofu init

# Validate configuration
tofu validate

# Format code
tofu fmt -recursive

# Preview changes
tofu plan -out=plan.tfplan

# Apply changes
tofu apply plan.tfplan

# Destroy infrastructure
tofu destroy

# Show current state
tofu show

# Refresh state from actual infrastructure
tofu refresh

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

Common Patterns

Conditional Resources
resource "aws_eip" "static" {
  count = var.create_elastic_ip ? 1 : 0

  instance = aws_instance.web.id
}
Dynamic Blocks
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:

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-02-04
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!