正在加载,请稍候…

Terraform in Production: Modules, Remote State, and GitOps with Atlantis

Master Terraform for production infrastructure. Reusable modules, S3 remote state with DynamoDB locking, workspace strategy, Terratest testing, and Atlantis GitOps automation.

Terraform is the standard for infrastructure provisioning. The difference between a scalable Terraform codebase and a maintenance nightmare is module design and state management.

Module Structure

infrastructure/
├── modules/
│   ├── vpc/
│   ├── eks-cluster/
│   ├── rds/
│   └── service/
├── environments/
│   ├── staging/
│   │   ├── main.tf
│   │   └── terraform.tfvars
│   └── production/
│       ├── main.tf
│       └── terraform.tfvars
└── global/
    └── iam/

Production RDS Module

resource "aws_db_instance" "main" {
  identifier     = var.identifier
  engine         = var.engine
  engine_version = var.engine_version
  instance_class = var.instance_class

  db_name  = var.database_name
  username = var.master_username
  password = var.master_password

  allocated_storage     = var.allocated_storage
  max_allocated_storage = var.max_allocated_storage
  storage_type          = "gp3"
  storage_encrypted     = true

  multi_az            = var.environment == "production"
  deletion_protection = var.environment == "production"
  skip_final_snapshot = var.environment != "production"

  backup_retention_period = var.environment == "production" ? 30 : 7
  performance_insights_enabled = true
  monitoring_interval = 60

  tags = merge(var.tags, {
    Environment = var.environment
    ManagedBy   = "terraform"
  })

  lifecycle {
    ignore_changes = [password]
  }
}

variable "environment" {
  type = string
  validation {
    condition     = contains(["staging", "production"], var.environment)
    error_message = "Environment must be staging or production."
  }
}

Remote State with S3 + DynamoDB Locking

terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-locks"
    role_arn       = "arn:aws:iam::PROD-ACCOUNT:role/TerraformRole"
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-state-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

Using Data Sources

data "aws_vpc" "main" {
  tags = { Name = "production-vpc", Environment = "production" }
}

data "aws_secretsmanager_secret_version" "db_pass" {
  secret_id = "production/rds/master-password"
}

module "database" {
  source          = "../../modules/rds"
  identifier      = "production-main"
  environment     = "production"
  vpc_id          = data.aws_vpc.main.id
  master_password = jsondecode(data.aws_secretsmanager_secret_version.db_pass.secret_string)["password"]
}

Terratest for Integration Testing

func TestRDSModule(t *testing.T) {
    t.Parallel()
    opts := &terraform.Options{
        TerraformDir: "../modules/rds",
        Vars: map[string]interface{}{
            "identifier":     "test-rds",
            "environment":    "staging",
            "instance_class": "db.t3.micro",
        },
    }
    defer terraform.Destroy(t, opts)
    terraform.InitAndApply(t, opts)

    endpoint := terraform.Output(t, opts, "endpoint")
    assert.Contains(t, endpoint, "rds.amazonaws.com")
}

Atlantis GitOps

# atlantis.yaml
version: 3
projects:
  - name: staging
    dir: environments/staging
    autoplan:
      enabled: true
      when_modified: ["**/*.tf", "../../modules/**/*.tf"]
    apply_requirements: [approved, mergeable]

  - name: production
    dir: environments/production
    autoplan:
      enabled: false  # Require explicit plan comment
    apply_requirements: [approved, mergeable, undiverged]
    required_approvals: 2

Terraform's power is declarative infrastructure and the provider ecosystem. Module design early saves months of refactoring later.

→ Encode your Terraform variable files with the Base64 Converter tool.