As we see a significant shift towards Infrastructure as Code (IaC) in managing cloud resources, Terraform emerges as a potent tool in the DevOps arsenal. This article will serve as a comprehensive guide on deploying resources on Microsoft Azure using Terraform, providing you with useful best practices, an example file structure, and a boilerplate codebase to get you started.
Understanding Terraform and Azure
Terraform, developed by HashiCorp, is an open-source tool that allows you to define and provision infrastructure using a high-level configuration language, HCL. Azure, on the other hand, is Microsoft’s cloud computing platform. Terraform allows you to automate the creation and management of your Azure resources efficiently and predictably.
Terraform interfaces with various cloud providers through provider plugins, which are responsible for understanding API interactions and exposing resources. For Azure, Terraform utilizes the ‘azurerm’ provider, which communicates directly with Azure Resource Manager (ARM), the deployment and management service for Azure.
Azure Resource Manager provides a consolidated view of resources in an Azure subscription, thus simplifying the process of managing and organizing these resources. It allows users to deploy, update, or delete all the resources for a particular solution in a single, coordinated operation.
Terraform makes API calls to Azure Resource Manager to create, read, update, and delete resources. The user defines the desired state of the infrastructure in HCL, and Terraform translates these declarations into a series of API calls to Azure Resource Manager.
Best Practices with Terraform on Azure
Modularize your Code
Break your code down into reusable modules. This approach promotes code reusability, reduces duplication, and makes your codebase easier to maintain.
Segregate Environment Variables
Maintain different variable files for each environment (dev, test, prod). This practice aids in maintaining a clean and clutter-free configuration.
Secure Sensitive Data
Terraform generates state files that may contain sensitive data. It is crucial to secure these files, possibly in Azure’s Blob Storage with versioning enabled.
Plan before Apply
Use the ‘terraform plan’ command to check what Terraform will do before actually doing it. This dry run is a great way to verify the changes.
Terraform File Structure for Azure
Consider an organized file structure like this:
terraform/
├─ dev/
│ ├─ dev.auto.tfvars
│ ├─ dev.backend.tfvars
├─ test/
├─ prod/
├─ modules/
| ├─ storage/
| | ├─ storage.tf
| | ├─ output.tf
| | ├─ variables.tf
├─ data.tf
├─ main.tf
├─ vatriables.tf
├─ versions.tf
├─ output.tf
This structure keeps your project maintainable and scalable. Some key takeaways:
Each env folder (dev/test/prod) contains an input file called env.auto.tfvars, which contains non-secret variables. When using these files, you provide them in terraform plan and terraform apply as follows:
terraform plan -var-file="./dev/dev.auto.tfvars" terraform apply -var-file"./dev/dev.auto.tfvarts"
Each env folder contains a file called backend.auto.tfvars. This file is used for local development or admin work when you’re outside of your CI/CD structure and need to connect to the state. For instance, if you want to work with the state locally and run terraform plan, you can add a parameter to the terraform init command to provide it with a backend config.
terraform init -backend-config="./dev/backend.auto.tfvars"
versions.tf
contains all the provider config. We separate this into another file to keep your main file readable.data.tf
contains all data source configuration. Just like versions.tf, we keep this in its own file for readability’s sake.
Boilerplate
To fast-track your deployment process, here’s a basic Terraform structure that creates a resource group and storage account in Azure. Use this as a template and a starting point for your project. You can clone or fork my boilerplate repository from my GitHub, which you can find here: terraform boilerplate