What I do is break each environment into a separate directory and tf file. I have a global
that is shared across all the environment dirs using a symlink. In the variables file I keep all the resource IDs for those low-level network pieces that came into existence ahead of my use of terraform.
~/repos/terraform (master●)$ tree
.
├── base
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ ├── terraform.tfvars -> ../terraform.tfvars
├── environments
│ ├── int
│ │ ├── terraform.tfstate
│ │ ├── terraform.tfstate.backup
│ │ ├── terraform.tfvars -> ../../terraform.tfvars
│ ├── prd
│ │ ├── terraform.tfstate
│ │ ├── terraform.tfstate.backup
│ │ ├── terraform.tfvars -> ../../terraform.tfvars
│ ├── stg
│ │ ├── terraform.tfstate
│ │ ├── terraform.tfstate.backup
│ │ ├── terraform.tfvars -> ../../terraform.tfvars
│ └── tst
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ ├── terraform.tfvars -> ../../terraform.tfvars
├── modules
│ ├── admin
│ ├── batch
│ ├── image
│ ├── poolmonitor
│ ├── upload
│ └── web
├── secrets
│ ├── domain-cert.pem
│ ├── domain-chain.pem
│ ├── domain-key.pem
├── terraform.tfvars
├── user_data.txt
* sercrets and terraform.tfvars in .gitignore
An example of the kind of statically defined resources contained in the
variables.tf:
variable "nonprd_vpcs" {
default = {
us-east-1 = "vpc-77777777"
eu-west-1 = "vpc-88888888"
us-west-2 = "vpc-22222222"
us-west-1 = "vpc-44444444"
ap-southeast-2 = "vpc-1233333"
ap-northeast-1 = "vpc-9999999"
}
}
variable "nonprd_public_subnets" {
default = {
us-east-1 = "subnet-000000,subnet-12333333"
eu-west-1 = ""
us-west-2 = "subnet-12333331,subnet-7777777"
us-west-1 = ""
ap-southeast-2 = ""
ap-northeast-1 = ""
}
}
Then a given environments
main.tf that strictly makes use of modules for services may begin like so:
// env specific settings
variable "environment" { default = "int" }
variable "region" { default = "us-west-1" }
variable "instance_type" { default = "m3.large" }
module "upload" {
source = "../../modules/upload"
region = "${var.region}"
vpc_id = "${lookup(var.nonprd_vpcs, var.region)}"
subnets = "${lookup(var.nonprd_public_subnets, var.region)}"
....
}
In the end the VPC ids are only ever defined in one place. I use this pattern for VPCs, ec2 keys, subnets, and a few other low-level aws resources that preexisted terraform's use in our production environment.
Hope that helps. I hope to potentially get away from state-files-per-env. I think there's a better pattern. I can't leave this one till I can easily target a taint or destroy to a specific environment. Since "environment" is an abstract construct in Terraform I would have to represent an environment as a module or make use of features that don't exist (resource tagging/metaparams) to target/filter resources in a specific environment to take action upon.
-Ryan