Multi-Environment Management with Terraform
Maintaining consistent infrastructure across development, staging, and production environments with minimal code duplication.
Overview
Terraform enables managing multiple environments efficiently by using variables, workspaces, and modules. A single configuration can be deployed to different environments with appropriate scaling and resource configurations.
Environment Structure with Workspaces
HCL - main.tf with Workspace Support
terraform {
required_version = ">= 1.0"
cloud {
organization = "my-org"
workspaces {
name = terraform.workspace
}
}
}
locals {
env = terraform.workspace
env_config = {
dev = {
instance_count = 1
machine_type = "e2-medium"
disk_size = 20
enable_backup = false
labels = { env = "dev", cost_center = "dev" }
}
staging = {
instance_count = 2
machine_type = "e2-standard-2"
disk_size = 50
enable_backup = true
labels = { env = "staging", cost_center = "qa" }
}
prod = {
instance_count = 5
machine_type = "e2-standard-4"
disk_size = 100
enable_backup = true
labels = { env = "prod", cost_center = "prod" }
}
}
config = local.env_config[local.env]
}
# Compute resources based on environment
resource "google_compute_instance" "app" {
count = local.config.instance_count
name = "${local.env}-app-${count.index}"
machine_type = local.config.machine_type
zone = "${var.gcp_region}-a"
boot_disk {
initialize_params {
size = local.config.disk_size
image = "projects/debian-cloud/global/images/debian-11"
}
}
labels = local.config.labels
metadata_startup_script = <<-EOT
#!/bin/bash
echo "Environment: ${local.env}"
EOT
}
# Database configuration per environment
resource "google_sql_database_instance" "db" {
name = "${local.env}-database"
database_version = "POSTGRES_15"
settings {
tier = local.config.machine_type == "e2-medium" ? "db-f1-micro" : "db-standard-2"
disk_size = local.config.disk_size
backup_configuration {
enabled = local.config.enable_backup
location = var.gcp_region
point_in_time_recovery_enabled = local.env == "prod"
}
database_flags {
name = "log_statement"
value = local.env == "prod" ? "all" : "none"
}
}
deletion_protection = local.env == "prod"
}
Variables Per Environment
HCL - terraform.tfvars (development)
gcp_project = "my-company-dev"
gcp_region = "us-central1"
# Development-specific settings
app_image_tag = "latest"
enable_monitoring = false
replica_count = 1
HCL - terraform.tfvars (production)
gcp_project = "my-company-prod"
gcp_region = "us-central1"
# Production-specific settings
app_image_tag = "v1.5.0"
enable_monitoring = true
replica_count = 5
Module-Based Environment Management
HCL - Directory Structure
terraform/
├── modules/
│ ├── app_service/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── database/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ └── terraform.tfvars
└── shared/
├── variables.tf
└── outputs.tf
Environment Module Usage
HCL - environments/prod/main.tf
terraform {
backend "gcs" {
bucket = "my-company-terraform-state"
prefix = "prod"
}
}
module "app_service" {
source = "../../modules/app_service"
environment = "prod"
replica_count = 5
machine_type = "e2-standard-4"
enable_ssl = true
enable_cdn = true
labels = {
environment = "prod"
managed = "terraform"
cost_center = "engineering"
}
}
module "database" {
source = "../../modules/database"
environment = "prod"
db_tier = "db-standard-2"
disk_size = 100
backup_config = {
enabled = true
location = "us"
point_in_time_recovery = true
}
labels = module.app_service.labels
}
output "app_url" {
value = module.app_service.url
}
output "database_connection_name" {
value = module.database.connection_name
}
Best Practices
- Use terraform.workspace to manage multiple environments
- Store state in separate backends per environment
- Use modules to reduce code duplication across environments
- Version and tag images per environment
- Implement different backup and monitoring strategies per environment
- Use variable validation to catch configuration errors early
- Separate sensitive data using terraform.tfvars in .gitignore
- Use HCP Terraform for state locking and runs across environments