This repository follows Terraform best practices with an environment-based folder structure, allowing for clear separation of concerns and environment-specific configurations.
.
├── envs/ # Environment-specific configurations
│ ├── dev/ # Development environment
│ ├── staging/ # Staging environment
│ └── prod/ # Production environment
├── modules/ # Reusable Terraform modules
│ └── aks/ # AKS cluster module
├── examples/ # Example configurations
├── test/ # Terratest integration tests
└── docs/ # Documentation
Each environment has its own directory under envs/ containing:
main.tf- Main Terraform configurationvariables.tf- Variable definitionsoutputs.tf- Output definitionsterraform.tfvars- Environment-specific variable valuesproviders.tf- Provider configuration- Additional environment-specific files
- Purpose: Development and testing
- Location:
envs/dev/ - Characteristics:
- Free SKU tier for cost savings
- Smaller VM sizes (D2s_v3 for system, D4s_v3 for Spark)
- Minimal node counts (1-3 nodes)
- Separate VNet range: 10.0.1.0/24
- Purpose: Quality assurance and testing
- Location:
envs/qa/ - Characteristics:
- Standard SKU tier for testing
- Small VM sizes (D2s_v3 for system, D4s_v3 for Spark)
- Minimal node counts (1-3 nodes)
- Separate VNet range: 10.0.2.0/24
- Purpose: Pre-production testing and validation
- Location:
envs/staging/ - Characteristics:
- Standard SKU tier for reliability testing
- Medium VM sizes (D4s_v3 for system, D8s_v3 for Spark)
- Moderate node counts (2-5 nodes)
- Separate VNet range: 10.0.3.0/24
- Purpose: Production workloads
- Location:
envs/prod/ - Characteristics:
- Standard SKU tier with SLA
- Production VM sizes (D8s_v3 for both system and Spark)
- Production node counts (3-10 nodes)
- Production VNet range: 10.0.4.0/24
- ExpressRoute connectivity ready
cd envs/dev
terraform initterraform planterraform applyEach environment has its own terraform.tfvars file with environment-specific settings. You can also override variables:
terraform apply -var="node_count=5"The AKS module is located in modules/aks/ and is referenced by all environments:
module "aks" {
source = "../../modules/aks"
# Module configuration
cluster_name = var.cluster_name
location = var.location
# ... other configurations
}- State Management: Each environment should have its own remote state backend
- Variable Management: Use
terraform.tfvarsfor non-sensitive values, use environment variables or secret management for sensitive data - Promotion Workflow: Test changes in dev → staging → prod
- Module Versioning: Consider versioning modules for production stability
Add a backend.tf file to each environment:
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "tfstate${environment}"
container_name = "tfstate"
key = "aks-${environment}.tfstate"
}
}This structure works well with CI/CD pipelines:
# Example GitHub Actions workflow
- name: Terraform Plan Dev
run: |
cd envs/dev
terraform init
terraform plan
- name: Terraform Apply Dev
if: github.ref == 'refs/heads/develop'
run: |
cd envs/dev
terraform apply -auto-approveIf migrating from a root-level configuration:
- Copy state file to the appropriate environment directory
- Update backend configuration
- Run
terraform init -migrate-state - Verify with
terraform plan(should show no changes)
If you get "Module not installed" errors:
terraform init -upgradeIf using remote state and encounter locks:
terraform force-unlock <lock-id>Use .terraform-version file in each environment directory for version management with tools like tfenv.