An easy way to think about Terraform is that it’s infrastructure-as-code (IaC). Infrastructure-as-code is a source-code description of your apps infrastructure resources that you want to easily manage
Infrastructure-as-code enables you to version control your backend resources, just like you would your application’s source code. You’ll have a clear track record of what was changed, who changed it, and when it was changed. No second-guessing with the cloud management console or throwing chairs around the office
This also means your infrastructure is self-documenting. You’ll always have the latest copy of the documentation (actual documentation can often drift away from reality) and it will all be in one place
You’ll spend most of your time writing in the HCL. It’s how you describe what the managed resources look like
The HCL is a nice lightweight, declarative language that looks very similar to a serialised JavaScript object (just substitute a colon with an equals symbol), where you have key/values wrapped around curly braces
The declarative nature of the language means you can focus on output (describe the final state/configuration) and Terraform will figure out the best approach to get resources to that state. Internally, Terraform uses the functional programming paradigm so there will be no unexpected side effects that would otherwise not deliver the expected resources (you don’t need to care about the internals of Terraform from a user point of view)
A provider is an API between Terraform and the upstream service offering the infrastructure resources. Most of the time, the upstream service offering the infrastructure resources is the public cloud (GCP, AWS, Linode and DigitalOcean have all built Terraform providers)
You don’t need to understand the internal workings of how a Terraform provider works, but you’ll need to be familiar with the resources that the provider exposes when you are writing HCL
I’ve worked on multiple instances of Terraform that were shared by other people (i.e.: everyone worked in the same git repository that was tracking the HCL) and this created issues that I took the initiative to sort out
I needed a way to logically separate each “area” of work and limit the blast radius of other people's changes. When I’m working on the backend infrastructure for an application I’m developing, the last thing I feel like doing is having to figure out what these non-related changes are about and if they are OK to apply–I hate been slowed down like this
I discovered that modules provide this logical separation and you can exclusively work in your area of concern without affecting other people. Perfect!
Modules, in Terraform, feel very similar to functions in that they can take input from parameters provided to them
Modules can also declare output variables that will be returned to the module one layer back (often, the module one layer back is the root module) that you’ll be able to reference
module "module-name" { source = "./module-name-directory" parameter = value }
You’ll need to define the input parameters within the module itself. This can almost be seen as the modules constructor (in the sense that these are the properties/variables that are going to be used)
If you are following the standard directory structure layout, you would define these input parameters in variables.tf and you can also declare the type
variable "parameter" { type = string }
Targeting modules is really simple. You can use the -target option on the CLI and specify the module you want to work with as a value to this option
Here is an example:
# terraform apply -target=module.module-name
You can further target resources in the module by using the dot notation of subsequent resources or even nested modules:
# terraform apply -target=module.module-name.resource-type.resource-name
Don’t track the Terraform state locally in the repository. Doing this can lead to serious issues when multiple people are working on the project (constant conflicts and possible loss of management on the resources)
Something like this will work perfectly (ensure you wrap this around the terraform {} block in the root module):
backend "s3" { region = "ap-southeast-1" bucket = "terraform-state" key = "terraform.tfstate" }
A deeper explanation can be found in the documentation on how the backend configuration works
Terraform is definitely most popular in terms of infrastructure-as-code but there are alternatives out there
CloudFormation | website
Native to AWS and not cloud agnostic. I’ve used CloudFormation before. It’s really easy to parse JSON, which is what my custom tooling did when we needed to do anything with the AWS infrastructure
My tooling made it pretty simple to make changes to the CloudFormation stacks: it asked the user for the environment they wanted to duplicate and a other specific information about the new stack and boom–all changed for them
Pulumi | website
I’ve never used Pulumi but it does seem like you can step the code through how it should go about doing the resource management (I’m not convinced that this is the right approach for IaC)
And I’m not sure how the pricing works either but it does seem pretty scary