Dynamic Terraform Environments
Introduction
Recently I have been playing with Terraform. It’s a lot of fun.
I had a little project that was perfect for it, but ran into a problem. Most examples of Terraform usage assume that your environments are static. So layouts like this are not uncommon:
terraform_folder/
modules/
myproject/main.tf
myproject/vars.tf
live/
main.tf
stage/
main.tf
dev/
main.tfProblem
All well and good, but in my project I needed to create environments on the fly, and perhaps many in existence at the same time. There was no ‘live’, just potentially hundreds of envs in use at once for a short period of time.
I also needed to keep a record of environments created and destroyed.
I researched and asked around, but couldn’t find any best practice for this, so came up with a pattern that may be useful to others.
Nothing a Shell Script Can’t Handle
In one sentence, this scheme creates a new folder on demand with a unique value which is destroyed when time is up.
The original code is elsewhere and somewhat more complex, so I put together this simple example code to illustrate the flow.
Here’s a video of it in action:

In addition to the standard main and vars files in the module, there are two scripts involved:
- create_dynamic_environment.sh
- destroy_dynamic_environment.sh
create_dynamic_environment.sh
- Create a directory with a unique (well, probably) ID
- Set up the main.tf file
- Terraform the environment
- (Git) add, commit and push the new directory
This script can be triggered when a new environment is required.
#!/bin/bash # Ensure we are in the right folder
pushd $(dirname ${BASH_SOURCE[0]})# Create a (probably) unique ID by concatenating two random
# values (RANDOM is a variable inherent to bash), with the day of year
# as a suffix.
ID="dynamic_environment_${RANDOM}${RANDOM}_$(date +%j)"# Create the terraform folder.
mkdir -p ${ID}
pushd ${ID}
cat > main.tf << END
module "dynamicenv" {
source = "../modules/dynamicenv"
dynamic_env_id = "${ID}"
}
END# Terraform ahoy!
terraform get
terraform plan
terraform applypopd# Record the creation in git and push. Assumes keys set up.
git add ${ID}
git commit -am "${ID} environment added"
git push
popd
destroy_dynamic_environments.sh
- After 7 days, retire the environment
- (Git) remove, commit and push the removal
This script can be run regularly in a cron.
In the ‘real’ aws environment I get the EC2 instance to self-destruct after a few hours, but for belt and braces we destroy the environment and remove it from git.
#!/bin/bash# We need extended glob capabilities.
shopt -s extglob# Ensure we are in the right folder
pushd $(dirname ${BASH_SOURCE[0]})# Default to destroying environments over 7 days old.
# If you want to destroy all of them, pass in '-1' as an argument.
DAYS=${1:-7}# Get today's 'day of year'
TODAY=$(date +%j)# Remove leading zeroes from the date.
TODAY=${TODAY##+(0)}# Go through all the environment folders, and terraform destroy,
# git remove and remove the folder.
for dir in $(find dynamic_environment_* -type d -maxdepth 0)
do
# Remove the folder prefix.
dir_day=${dir##*_} # Remove any leading zeroes from the day of year.
dir_day=${dir_day##+(0)} # If over 7 days old...
if [[ $(( ${TODAY} - ${dir_day})) -gt ${DAYS} ]]
then
pushd "${dir}" # Destroy the environment.
terraform destroy -force
popd # Remove from git.
git rm -rf "${dir}"
git commit -am "destroyed ${dir}"
git push # Remove left-over backup files.
rm -rf "${dir}"
fi
done
My book Docker in Practice
Get 39% off with the code: 39miell
