Convert AWS CloudFormation Template For a Highly Available Web Server To Terraform Script
Table of contents
I tried out Terraform for the first time in one of my previous posts and since nothing beats learning by continuously doing, I decided to convert a CloudFormation script I wrote to "deploy infrastructure for highly available applications" to its Terraform version.
Remember this post? Yeah, the CloudFormation script from this project.
The project was mainly to understand (and practice) what to consider when deciding between high availability of applications vs. optimising costs, and how that translates to the architecture.
Prerequisites: Have Terraform Open Source installed.
Steps to Convert CloudFormation templates to Terraform scripts
There are three main steps after creating and writing the configurations but I'll be highlighting every other step as well.
- Structure the folder
The project uses the modules
/folder structure because real-world projects will typically be structured that way. I created sub-folders like setup
, security
, etc to create separate files with the configurations for each section.
As highlighted above, each folder had at least its main.tf
, outputs.tf
and variables.tf
files.
- Convert each resource declaration to terraform syntax
This is where I spent the most time; there are several resources provided by the Terraform team to learn about different aspects of the tool; language syntax, CLI commands, providers' documentation, etc. I also encountered several errors and got some clarifications from reading the documentation.
The final configuration files can be found in this repo.
And now to the "main" steps:
- Initialise the working directory
The directory that contains the configuration files defined above must be "initialised" before Terraform commands can be used to perform any operation. This is done with terraform init
and this pretty much sets up the folder with all the necessary configurations Terraform needs.
terraform plan
andterraform apply
The plan command generates a preview of the updates to be made (this can be saved in .tfplan
file.
P.S it can be saved in files other than the default
tfplan
but those require extra configurations that may be unnecessary.
One of the issues I encountered during this step was associating route tables with subnets. Unlike AWS CloudFormation where I had to create each subnet individually (hence having direct access to the individual subnet_id
), Terraform provides meta-arguments like for_each
that can be used to create similar subnets with just one configuration.
However, it becomes difficult to directly retrieve the subnet_id
s and use them in another for_each
for creating the matching route-table associations.
As suggested, a workaround would be to use the -target
option to apply just the setup
module before proceeding. This is not recommended as highlighted in the docs so I created the resources individually instead since the values I needed could not be defined statically beforehand. That did not seem efficient so there would most likely be another way.
Workaround #1:
terraform plan -out=tfplan -target=module.setup
terraform apply tfplan -target=module.setup
Workaround #2:
Let me know if you have another way of doing it!
Afterwards, run the commands as normal, and test:
terraform plan -out=tfplan
terraform apply tfplan
Don't forget to delete your resources after you are done!
The command terraform destroy
is the equivalent of deleting CloudFormation stacks.
The deployment can also be automated using a CI/CD tool so that's what I'd be trying out next!