terraform-module-writer

安装量: 41
排名: #17738

安装

npx skills add https://github.com/dengineproblem/agents-monorepo --skill terraform-module-writer

Terraform Module Writer Эксперт по созданию высококачественных, переиспользуемых Terraform модулей с соблюдением industry best practices. Module Structure Standard Directory Layout modules/ └── my-module/ ├── main.tf # Primary resource definitions ├── variables.tf # Input variable declarations ├── outputs.tf # Output value definitions ├── versions.tf # Provider version constraints ├── locals.tf # Local values and computations ├── data.tf # Data source definitions ├── README.md # Module documentation ├── CHANGELOG.md # Version history ├── examples/ │ ├── basic/ │ │ ├── main.tf │ │ └── outputs.tf │ └── advanced/ │ ├── main.tf │ └── outputs.tf └── tests/ └── module_test.go versions.tf Template terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0.0, < 6.0.0" } random = { source = "hashicorp/random" version = ">= 3.5.0" } } } Input Variable Design Variable Declaration Best Practices

variables.tf

Required variables (no default)

variable "name" { description = "Name prefix for all resources created by this module" type = string validation { condition = can(regex( "^[a-z][a-z0-9-]*$" , var.name)) error_message = "Name must start with a letter and contain only lowercase letters, numbers, and hyphens." } } variable "environment" { description = "Environment name (e.g., dev, staging, prod)" type = string validation { condition = contains( [ "dev" , "staging" , "prod" ] , var.environment) error_message = "Environment must be one of: dev, staging, prod." } }

Optional variables with sensible defaults

variable "instance_type" { description = "EC2 instance type for the application servers" type = string default = "t3.medium" validation { condition = can(regex( "^[a-z][0-9][.][a-z]+$" , var.instance_type)) error_message = "Instance type must be a valid AWS instance type format." } } variable "enable_monitoring" { description = "Enable detailed monitoring for resources" type = bool default = true } variable "min_instances" { description = "Minimum number of instances in the Auto Scaling Group" type = number default = 2 validation { condition = var.min_instances > = 1 && var.min_instances < = 100 error_message = "Minimum instances must be between 1 and 100." } } variable "max_instances" { description = "Maximum number of instances in the Auto Scaling Group" type = number default = 10 validation { condition = var.max_instances > = 1 && var.max_instances < = 100 error_message = "Maximum instances must be between 1 and 100." } } Complex Variable Types

Object type with optional attributes

variable "vpc_config" { description = "VPC configuration for the module" type = object( { vpc_id = string subnet_ids = list(string) security_group_ids = optional(list(string), [ ] ) assign_public_ip = optional(bool, false ) } ) validation { condition = length(var.vpc_config.subnet_ids) > = 2 error_message = "At least 2 subnet IDs required for high availability." } }

Map with specific value types

variable "tags" { description = "Additional tags to apply to all resources" type = map(string) default = { } validation { condition = alltrue( [ for k, v in var.tags : can(regex( "^[a-zA-Z][a-zA-Z0-9:/_-]*$" , k)) ] ) error_message = "Tag keys must start with a letter and contain only valid characters." } }

List of objects

variable "ingress_rules" { description = "List of ingress rules for the security group" type = list(object( { description = string from_port = number to_port = number protocol = string cidr_blocks = optional(list(string), [ ] ) security_groups = optional(list(string), [ ] ) } )) default = [ ] validation { condition = alltrue( [ for rule in var.ingress_rules : rule.from_port > = 0 && rule.from_port < = 65535 && rule.to_port > = 0 && rule.to_port < = 65535 ] ) error_message = "Port numbers must be between 0 and 65535." } }

Sensitive variables

variable "database_password" { description = "Master password for the RDS instance" type = string sensitive = true validation { condition = length(var.database_password) > = 16 error_message = "Database password must be at least 16 characters." } } Local Values locals.tf Template locals {

Naming convention

name_prefix

" $ { var . name } - $ { var . environment } "

Common tags applied to all resources

common_tags

merge( var.tags, { Name = local.name_prefix Environment = var.environment ManagedBy = "terraform" Module = "my-module" Project = var.name } )

Computed values

is_production

var.environment

= "prod" enable_encryption = local.is_production backup_retention = local.is_production ? 30 : 7 instance_count = local.is_production ? var.max_instances : var.min_instances

Derived configurations

monitoring_config

{ enabled = var.enable_monitoring || local.is_production detailed = local.is_production retention_days = local.is_production ? 90 : 30 alarm_threshold = local.is_production ? 80 : 90 }

Dynamic block helpers

ingress_rules_map

{ for idx, rule in var.ingress_rules : "${rule.protocol}-${rule.from_port}-${rule.to_port}" =

rule }

Conditional resource naming

bucket_name

var.bucket_name !

null ? var.bucket_name : " $ { local . name_prefix } -storage- $ { random_id . bucket . hex } " } Resource Definitions main.tf Template

main.tf

------------------------------------------------------------------------------

Security Group

------------------------------------------------------------------------------

resource
"aws_security_group"
"this"
{
name_prefix
=
"
$
{
local
.
name_prefix
}
-sg-"
description
=
"Security group for
$
{
var
.
name
}
$
{
var
.
environment
}
"
vpc_id
=
var.vpc_config.vpc_id
tags
=
merge(local.common_tags,
{
Name
=
"
$
{
local
.
name_prefix
}
-sg"
}
)
lifecycle
{
create_before_destroy
=
true
}
}
resource
"aws_security_group_rule"
"ingress"
{
for_each
=
local.ingress_rules_map
type
=
"ingress"
security_group_id
=
aws_security_group.this.id
description
=
each.value.description
from_port
=
each.value.from_port
to_port
=
each.value.to_port
protocol
=
each.value.protocol
cidr_blocks
=
length(each.value.cidr_blocks) >
0
? each.value.cidr_blocks : null
source_security_group_id
=
length(each.value.security_groups) >
0
? each.value.security_groups
[
0
]
null } resource "aws_security_group_rule" "egress" { type = "egress" security_group_id = aws_security_group.this.id description = "Allow all outbound traffic" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = [ "0.0.0.0/0" ] }

------------------------------------------------------------------------------

Launch Template

------------------------------------------------------------------------------

resource "aws_launch_template" "this" { name_prefix = " $ { local . name_prefix } -lt-" description = "Launch template for $ { var . name } $ { var . environment } " image_id = data.aws_ami.amazon_linux.id instance_type = var.instance_type network_interfaces { associate_public_ip_address = var.vpc_config.assign_public_ip security_groups = concat( [ aws_security_group.this.id ] , var.vpc_config.security_group_ids) delete_on_termination = true } iam_instance_profile { arn = aws_iam_instance_profile.this.arn } monitoring { enabled = local.monitoring_config.detailed } metadata_options { http_endpoint = "enabled" http_tokens = "required"

IMDSv2

http_put_response_hop_limit

1 } block_device_mappings { device_name = "/dev/xvda" ebs { volume_size = var.root_volume_size volume_type = "gp3" encrypted = local.enable_encryption kms_key_id = local.enable_encryption ? var.kms_key_id : null delete_on_termination = true } } tag_specifications { resource_type = "instance" tags = local.common_tags } tag_specifications { resource_type = "volume" tags = local.common_tags } tags = local.common_tags lifecycle { create_before_destroy = true } }

------------------------------------------------------------------------------

Auto Scaling Group

------------------------------------------------------------------------------

resource "aws_autoscaling_group" "this" { name_prefix = " $ { local . name_prefix } -asg-" desired_capacity = var.desired_instances min_size = var.min_instances max_size = var.max_instances vpc_zone_identifier = var.vpc_config.subnet_ids health_check_type = "ELB" health_check_grace_period = 300 launch_template { id = aws_launch_template.this.id version = "$Latest" } dynamic "tag" { for_each = local.common_tags content { key = tag.key value = tag.value propagate_at_launch = true } } lifecycle { create_before_destroy = true ignore_changes = [ desired_capacity ] } } Data Sources data.tf Template

data.tf

Get current AWS account info

data "aws_caller_identity" "current" { } data "aws_region" "current" { } data "aws_partition" "current" { }

Get latest Amazon Linux 2023 AMI

data "aws_ami" "amazon_linux" { most_recent = true owners = [ "amazon" ] filter { name = "name" values = [ "al2023-ami-*-x86_64" ] } filter { name = "virtualization-type" values = [ "hvm" ] } filter { name = "architecture" values = [ "x86_64" ] } }

Get VPC info if not provided

data "aws_vpc" "selected" { id = var.vpc_config.vpc_id }

Get subnet info for AZ distribution

data "aws_subnet" "selected" { for_each = toset(var.vpc_config.subnet_ids) id = each.value }

Get available AZs

data "aws_availability_zones" "available" { state = "available" filter { name = "opt-in-status" values = [ "opt-in-not-required" ] } } Output Definitions outputs.tf Template

outputs.tf

------------------------------------------------------------------------------

Primary Outputs

------------------------------------------------------------------------------

output "id" { description = "The unique identifier for this module instance" value = aws_autoscaling_group.this.id } output "name" { description = "The name prefix used for all resources" value = local.name_prefix } output "arn" { description = "ARN of the Auto Scaling Group" value = aws_autoscaling_group.this.arn }

------------------------------------------------------------------------------

Security Group Outputs

------------------------------------------------------------------------------

output "security_group_id" { description = "ID of the security group created for this module" value = aws_security_group.this.id } output "security_group_arn" { description = "ARN of the security group" value = aws_security_group.this.arn } output "security_group_name" { description = "Name of the security group" value = aws_security_group.this.name }

------------------------------------------------------------------------------

Launch Template Outputs

------------------------------------------------------------------------------

output "launch_template_id" { description = "ID of the launch template" value = aws_launch_template.this.id } output "launch_template_arn" { description = "ARN of the launch template" value = aws_launch_template.this.arn } output "launch_template_latest_version" { description = "Latest version of the launch template" value = aws_launch_template.this.latest_version }

------------------------------------------------------------------------------

Computed/Derived Outputs

------------------------------------------------------------------------------

output "ami_id" { description = "ID of the AMI used for instances" value = data.aws_ami.amazon_linux.id } output "availability_zones" { description = "List of availability zones where resources are deployed" value = distinct( [ for s in data.aws_subnet.selected : s.availability_zone ] ) } output "configuration" { description = "Summary of the module configuration" value = { environment = var.environment instance_type = var.instance_type min_instances = var.min_instances max_instances = var.max_instances monitoring_enabled = local.monitoring_config.enabled encryption_enabled = local.enable_encryption } }

------------------------------------------------------------------------------

Sensitive Outputs

------------------------------------------------------------------------------

output "iam_role_arn" { description = "ARN of the IAM role attached to instances" value = aws_iam_role.this.arn sensitive = false } Conditional Resource Creation Using count vs for_each

Use count for simple on/off toggles

resource "aws_cloudwatch_metric_alarm" "high_cpu" { count = var.enable_monitoring ? 1 : 0 alarm_name = " $ { local . name_prefix } -high-cpu" comparison_operator = "GreaterThanThreshold" evaluation_periods = 2 metric_name = "CPUUtilization" namespace = "AWS/EC2" period = 300 statistic = "Average" threshold = local.monitoring_config.alarm_threshold alarm_description = "CPU utilization exceeded threshold" alarm_actions = var.alarm_actions dimensions = { AutoScalingGroupName = aws_autoscaling_group.this.name } tags = local.common_tags }

Use for_each for collections

resource "aws_s3_bucket" "logs" { for_each = var.enable_logging ? toset( [ "access" , "audit" , "error" ] ) : toset( [ ] ) bucket = " $ { local . name_prefix } - $ { each . key } -logs" tags = merge(local.common_tags, { LogType = each.key } ) }

for_each with complex objects

resource "aws_route53_record" "this" { for_each = { for record in var.dns_records : "${record.name}-${record.type}" =

record } zone_id = var.route53_zone_id name = each.value.name type = each.value.type ttl = each.value.ttl records = each.value.records } Module Composition Root Module Example

examples/complete/main.tf

terraform { required_version = ">= 1.5.0" } provider "aws" { region = var.region }

Network module

module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" name = " $ { var . name } -vpc" cidr = "10.0.0.0/16" azs = [ " $ { var . region } a" , " $ { var . region } b" , " $ { var . region } c" ] private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" , "10.0.3.0/24" ] public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" , "10.0.103.0/24" ] enable_nat_gateway = true single_nat_gateway = var.environment ! = "prod" tags = var.tags }

Application module

module "app" { source = "../../" name = var.name environment = var.environment vpc_config = { vpc_id = module.vpc.vpc_id subnet_ids = module.vpc.private_subnets } instance_type = var.instance_type min_instances = var.min_instances max_instances = var.max_instances enable_monitoring = true ingress_rules = [ { description = "HTTP from ALB" from_port = 80 to_port = 80 protocol = "tcp" security_groups = [ module.alb.security_group_id ] } ] tags = var.tags }

ALB module

module "alb" { source = "terraform-aws-modules/alb/aws" version = "~> 8.0" name = " $ { var . name } -alb" load_balancer_type = "application" vpc_id = module.vpc.vpc_id subnets = module.vpc.public_subnets target_groups = [ { name = " $ { var . name } -tg" backend_protocol = "HTTP" backend_port = 80 target_type = "instance" } ] tags = var.tags }

Outputs

output "vpc_id" { value = module.vpc.vpc_id } output "app_security_group_id" { value = module.app.security_group_id } output "alb_dns_name" { value = module.alb.lb_dns_name } Documentation README.md Template

Module Name Brief description of what this module creates.

Features

Feature 1

Feature 2

Feature 3

Usage

Basic ```hcl module "example" { source = "github.com/org/terraform-aws-module?ref=v1.0.0" name = "my-app" environment = "prod" vpc_config = { vpc_id = "vpc-12345678" subnet_ids = ["subnet-1", "subnet-2"] } } Advanced module "example" { source = "github.com/org/terraform-aws-module?ref=v1.0.0" name = "my-app" environment = "prod" vpc_config = { vpc_id = "vpc-12345678" subnet_ids = [ "subnet-1" , "subnet-2" ] security_group_ids = [ "sg-existing" ] assign_public_ip = false } instance_type = "t3.large" min_instances = 3 max_instances = 10 enable_monitoring = true ingress_rules = [ { description = "HTTPS" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = [ "10.0.0.0/8" ] } ] tags = { Team = "platform" CostCenter = "12345" } } Requirements Name Version terraform

= 1.5.0 aws = 5.0.0, < 6.0.0 Providers Name Version aws = 5.0.0 Inputs Name Description Type Default Required name Name prefix for resources string n/a yes environment Environment (dev/staging/prod) string n/a yes vpc_config VPC configuration object n/a yes instance_type EC2 instance type string "t3.medium" no min_instances Minimum ASG size number 2 no max_instances Maximum ASG size number 10 no Outputs Name Description id Auto Scaling Group ID security_group_id Security Group ID launch_template_id Launch Template ID License MIT


Лучшие практики

  1. Используй версионирование — семантическое версионирование для модулей
  2. Валидируй входные переменные — используй validation blocks
  3. Документируй всё — описания для variables и outputs
  4. Избегай hardcoded значений — всё должно быть configurable
  5. Используй for_each вместо count — лучше управление state
  6. Группируй связанные ресурсы — логическая организация main.tf
  7. Тестируй модули — используй terratest или terraform test
  8. Следуй naming conventions — консистентное именование ресурсов
返回排行榜