Setting Up Multi-Environment Terraform Workflows
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!