Welcome to this first part of Terraform for Dummies! In this series, you will learn about what Terraform is and how DevOps engineers use it to provision, deploy and orchestrate both on-prem and cloud infrastructure in a reliable and easy way.
If you’re a DevOps engineer, odds are you have at least heard of Terraform. In this series, we will use Terraform as an Infrastructure as Code (IaC) tool for provisioning Amazon Web Services (AWS) resources. We will also touch on important DevOps concepts along the way.
IaC is pretty much exactly what it sounds like. Using IaC tools like terraform, you can do away with manual configuration all together by defining your infrastructure in a code template. There are a few reasons why IaC champions over manual configuration:
- People are imperfect and get it wrong - misconfiguration becomes more likely as infrastructure scales due to human error.
- Transferring knowledge to teammates is difficult when environments are manually configured, especially across multiple projects. IaC allows any team member to read/edit IaC with little KT.
- Configuration compliance is also difficult. Enforcing compliance according to customer/company standards is easier with IaC.
Terraform uses their own configuration language called HCL, which we will dive into more in up-coming posts. You can use configuration scripts to automate creating, updating and destroying cloud infrastructure. Think of these configuration files as blueprints, much like a blueprint an architect would use to build a house.
Terraform supports a variety of providers outside of GCP, AWS and Azure and sometimes it’s the only provider available. It’s also open-source and extendable so any API can be used to create IaC tooling for any kind of cloud platform technology. E.g. Heroku, Spotify Playlists.
Terraform is also cloud-agnostic, meaning that it allows a single configuration to be used to manage multiple providers and even handle cross-cloud dependencies.
Immutability, or the inability to change the object state, is an important concept to grasp for understanding declarative vs imperative programming. Immutable types are safer from bugs, easier to understand, and more ready for change.
Declarative programming is a paradigm describing WHAT the program does, without explicitly specifying its control flow. There is zero chance of misconfiguration with declarative programming.
- Declarative languages don't have looping control structures, e.g. for and while, because due to immutability, the loop condition would never change.
- Declarative languages don't express control-flow other than nested function order (a.k.a logical dependencies), because due to immutability, other choices of evaluation order do not change the result.
Declarative programming uses scripting languages such as JSON, YAML, XML
Imperative programming is a paradigm describing HOW the program should do something by explicitly specifying each instruction (or statement) step by step, which mutate the program's state.
- Imperative programming is less verbose; you could end up with misconfiguration
- AWS CDK and Pulumi use imperative
So is Terraform declarative or imperative? Well, Terraform is declarative but it has imperative-like features like for loops, dynamic blocks, locals and complex data structures like maps and collections.
Idempotency is a principle of IaC that refers to the state of a configuration after applying changes.
Non-idempotent configurations will add the specified resources each time they are applied whereas idempotent configurations can be applied multiple times without changing the results.
Your configuration file specifies that you need three virtual machines. Each time you apply your configuration, you have 3 more virtual machines. So each time you apply, the number of VMs will increment by 3.
Your configuration file specifies that you need three virtual machines. Each time you apply your configuration, the number of virtual machines is always 3 virtual machines. So no matter how many times you apply, you will always have the same number of VMs in your configuration.
Configuration drift is simply unexpected changes to your infrastructure. This can happen for a number of different reasons, including manual adjustments to configurations, side effects of SDKs, CLIs, or APIs or even from malicious actors.
Terraform prevents configuration drift with the state file (.tfstate) which show what the configuration of files should be. To correct the drift, you can utilize the terraform plan and refresh commands which we will look to more in depth in the coming posts.
Terraform goes hand-in-hand with GitOps. In collaborative environments, you can use a git repository as a formal process to review and accept changes to IaC. Once those changes are accepted, a deployment is triggered.
In this example, Terraform code is pushed to a git repo such as Github or Bitbucket. The person who made the push can continue to commit until they are ready to create a pull request to the main branch. Once the pull request is approved by a reviewer, a CI/CD pipeline such as Jenkins, Concourse or Github Actions is triggered to deploy changes to your cloud environments.
Terraform cloud also has their own version of this where you have a git repo, PR, and Terraform cloud takes care of the CI/CD.
- At the start, you will update the code of your terraform configuration file
- Then you will initialize your project or pull the latest providers using terraform init
- Next, the plan allows you to speculate what your changes will be
- Validation happens automatically when your run plan but you can also validate manually
- Finally, you will execute the terraform plan to provision infrastructure using apply
- You can also destroy terraform infrastructure using apply or the destroy command
You now know the basics of Terraform! In the next post, we will set up a development environment for terraform and begin to start using terraform with AWS.