This text demonstrates a pattern for using a single repository of Terraform code to manage multiple, completely independent environments that contain the same infrastructure.
It's based on simply overriding the terraform data and config files on each execution with:
$TF_DATA_DIR
-backend-config=
-var-file=
This is useful e.g. for running matching dev / test / stage / prod tiers in parallel.
This doesn't use Terraform Workspaces, which are intended for a different use case.
But IMO it addresses a common confusion where people expect Workspaces to do something like this (I did, anyway) -- see the bug report & discussion in hashicorp/terraform#16627
Create something like this to separate code and env-specific params and state
src/
foo.tf # Your tf code, as usual
variables.tf # Variables for per-env parameterization
.terraform.lock.hcl # (Autogenerated) (Should be version-controlled)
environments/
dev/
values.tfvars # Environment-specific values for variables.tf
tf/ # Directory for terraform-managed files
.terraform/ # (Autogenerated) Terraform data directory
terraform.tfstate # (Autogenerated) Terraform state file
acme.tfbackend # External backend storage configuration
# (mutually exclusive w/ terraform.tfstate)
test/ # As above
staging/
prod/
If you're using local terraform.tfstate
files, add this empty default
section verbatim in your Terraform codebase (src/*.tf
):
terraform {
backend "local" {
}
}
If you're using remote backend(s) for Terraform state (http, consul, s3, etc), add a similar empty setion, mentioning the backend driver:
terraform {
backend "acme" {
}
}
Create environments/${ENV}/tf/acme.tfbackend
. Populate it with whatever parameters
your chosen backend needs, pointing to the stored state for this environment.
acme_username = "foobar_ltd"
acme_bucket = "foobar_ltd_dev"
For more info, see https://www.terraform.io/language/settings/backends/configuration
Do this separately for every environment you're running. This creates terraform data
files in ../environments/YOURENV/tf/
and also records the backend config file's
location there.
ENVDIR=../environments/dev
TF_DATA_DIR=${ENVDIR}/tf/.terraform terraform init -backend-config=path=${ENVDIR}/tf/terraform.tfstate
ENVDIR=../environments/dev
TF_DATA_DIR=${ENVDIR}/tf/.terraform terraform init -backend-config=${ENVDIR}/tf/terraform.acme.tfbackend
With initialization done, you can use commands such as below to operate your separate terraform-managed environments.
ENVDIR=../environments/dev
TF_DATA_DIR=${ENVDIR}/tf/.terraform terraform plan -var-file=${ENVDIR}/values.tfvars -out=${ENVDIR}/tf/plan.tfplan
ENVDIR=../environments/dev
TF_DATA_DIR=${ENVDIR}/tf/.terraform terraform apply ${ENVDIR}/tf/plan.tfplan
ENVDIR=../environments/dev
TF_DATA_DIR=${ENVDIR}/tf/.terraform terraform show|output|state|etc ...