Tutorial6 min read

Setting Up Multi-Environment Terraform Workflows

AR

Alex Rodriguez

2023-12-28

Setting Up Multi-Environment Terraform Workflows

Managing multiple environments (dev, staging, production) is a common challenge in infrastructure management. Here's how to set up efficient multi-environment workflows with FreeState.

Environment Strategy Overview

We'll implement a strategy that uses:

  • Separate workspaces for each environment
  • Shared modules for common infrastructure
  • Environment-specific variables for customization
  • Automated promotion between environments

Directory Structure

\\\`

terraform/

├── environments/

│ ├── dev/

│ │ ├── main.tf

│ │ ├── variables.tf

│ │ └── terraform.tfvars

│ ├── staging/

│ │ ├── main.tf

│ │ ├── variables.tf

│ │ └── terraform.tfvars

│ └── prod/

│ ├── main.tf

│ ├── variables.tf

│ └── terraform.tfvars

├── modules/

│ ├── vpc/

│ ├── app/

│ └── database/

└── shared/

├── variables.tf

└── outputs.tf

\\\`

Environment Configuration

Development Environment

\\\`hcl

environments/dev/main.tf

terraform {

backend "http" {

address = "https://api.freestate.cloud/terraform/state"

username = "mycompany-dev"

password = var.freestate_api_key

lock_address = "https://api.freestate.cloud/terraform/state/lock"

lock_method = "POST"

unlock_address = "https://api.freestate.cloud/terraform/state/lock"

unlock_method = "DELETE"

}

}

module "vpc" {

source = "../../modules/vpc"

environment = "dev"

cidr_block = "10.0.0.0/16"

tags = {

Environment = "development"

Team = "platform"

}

}

module "app" {

source = "../../modules/app"

environment = "dev"

instance_type = "t3.micro"

min_capacity = 1

max_capacity = 2

vpc_id = module.vpc.vpc_id

subnet_ids = module.vpc.private_subnet_ids

}

\\\`

Production Environment

\\\`hcl

environments/prod/main.tf

terraform {

backend "http" {

address = "https://api.freestate.cloud/terraform/state"

username = "mycompany-prod"

password = var.freestate_api_key

lock_address = "https://api.freestate.cloud/terraform/state/lock"

lock_method = "POST"

unlock_address = "https://api.freestate.cloud/terraform/state/lock"

unlock_method = "DELETE"

}

}

module "vpc" {

source = "../../modules/vpc"

environment = "prod"

cidr_block = "10.1.0.0/16"

tags = {

Environment = "production"

Team = "platform"

}

}

module "app" {

source = "../../modules/app"

environment = "prod"

instance_type = "t3.large"

min_capacity = 3

max_capacity = 10

vpc_id = module.vpc.vpc_id

subnet_ids = module.vpc.private_subnet_ids

}

\\\`

Variable Management

Environment-Specific Variables

\\\`hcl

environments/dev/terraform.tfvars

environment = "dev"

instance_type = "t3.micro"

min_capacity = 1

max_capacity = 2

Database settings

db_instance_class = "db.t3.micro"

db_allocated_storage = 20

Feature flags

enable_monitoring = false

enable_backup = false

\\\`

\\\`hcl

environments/prod/terraform.tfvars

environment = "prod"

instance_type = "t3.large"

min_capacity = 3

max_capacity = 10

Database settings

db_instance_class = "db.r5.xlarge"

db_allocated_storage = 100

Feature flags

enable_monitoring = true

enable_backup = true

backup_retention_period = 30

\\\`

CI/CD Pipeline Integration

GitHub Actions Workflow

Basic workflow structure without template literal conflicts:

  • Separate jobs for each environment
  • Manual approval for production deployments
  • Environment-specific secrets and configurations
  • Proper error handling and notifications

Environment Promotion Strategy

1. Development: Automatically deploy from develop branch

2. Staging: Promote from dev after successful tests

3. Production: Manual approval required for deployment

Best Practices for Multi-Environment

1. Use Consistent Naming

\\\`hcl

locals {

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

common_tags = {

Environment = var.environment

Project = var.project_name

ManagedBy = "terraform"

}

}

\\\`

2. Parameterize Everything

Make configurations flexible across environments:

\\\`hcl

variable "instance_sizes" {

type = map(string)

default = {

dev = "t3.micro"

staging = "t3.small"

prod = "t3.large"

}

}

resource "aws_instance" "app" {

instance_type = var.instance_sizes[var.environment]

... other configuration

}

\\\`

3. Environment-Specific Modules

\\\`hcl

Use different module versions or configurations

module "monitoring" {

count = var.environment == "prod" ? 1 : 0

source = "../../modules/monitoring"

... configuration

}

\\\`

4. Validation and Testing

\\\`hcl

Add validation rules

variable "environment" {

type = string

validation {

condition = contains([

"dev", "staging", "prod"

], var.environment)

error_message = "Environment must be dev, staging, or prod."

}

}

\\\`

Monitoring and Observability

Set up environment-specific monitoring:

  • Development: Basic logging
  • Staging: Full monitoring for testing
  • Production: Comprehensive monitoring with alerting

Conclusion

This multi-environment setup provides:

  • Isolation between environments
  • Consistency in infrastructure patterns
  • Flexibility for environment-specific needs
  • Automation through CI/CD pipelines

Start with this foundation and adapt it to your team's specific needs!