Optimising Terraform IaC Development with Proven Patterns

sam raza
FAUN — Developer Community 🐾
6 min readApr 17, 2023

--

Developing Terraform IaC can be challenging, especially when managing complex infrastructure and multiple environments. To address this, overtime various Terraform IaC development patterns have emerged that help organizations provision and manage infrastructure resources more efficiently and effectively. We will talk about some of most commonly used patterns and best practices in use today.

Photo by Christopher Gower on Unsplash

Please be aware that the examples provided in this post are for demonstration purposes only and may not include exact syntax. They are meant to convey ideas and concepts, and therefore may need to be adapted to your specific use case.

1. Usecase-driven IaC

Usecase-driven Infrastructure as Code (IaC) is an approach to infrastructure automation that focuses on defining infrastructure resources based on specific use cases or scenarios.

In this most commonly used approach for IaC, the infrastructure is designed and built based on the specific requirements of the application or service being deployed. Usecase-driven IaC involves creating a set of templates, scripts, and configuration files that can be used to quickly provision the required infrastructure resources for a given use case.

The use cases may vary depending on the nature of the application or service being deployed. For example, a use case may involve provisioning resources for a web application that needs to handle high traffic, or it may involve setting up a distributed data processing system for a big data application. Other use cases can range from building IaC for a cloud migration project, building infrastructure for a single or multiple private or public cloud platforms or just few services for a small startup.

Usecase driven Iac — Example.tf

Usecase-driven IaC is designed to provide a more efficient and effective way to manage infrastructure resources, by focusing on the specific needs of the application or service(s) being deployed. This approach can help ensure that the infrastructure is provisioned in a consistent and repeatable way, which can reduce the risk of errors and improve overall system reliability.

2. Domain driven IaC

As the name suggests, this approach to IaC considers the domain of the problem at hand. Regardless of the platform used to deploy infrastructure, it is important to work with both development and product owners. The components that make up the infrastructure services must be named and tagged appropriately, making it easier to maintain aggregates, contexts, and domain-specific terms while integrating IaC into existing domain knowledge.

By using a DSL that is tailored to the specific needs of the business, developers and operations teams can more easily collaborate and easily understand the domain context.

Domain-Driven IaC is an approach to infrastructure automation that focuses on creating a domain-specific language (DSL) for defining infrastructure and application resources. This DSL is designed to be easily understood and used by developers and other stakeholders, rather than being focused on low-level technical details.

In this example, a new module is created to create a set of resources for a web application domain, including a load balancer, a managed instance group, and a database instance.

Terraform Domain Drive Iac webapp module

When the webapp module is used, it can be reused for different departments within the organization. The locals block is used to manage the configuration/settings of each service, without needing to make changes to the module itself.

Terraform Domain Drive Iac local variables

Finally, when using the module webapp, domain-specific names are used for different organizational units and their user traffic needs, such as test_service, frontdesk_user_service, and internal_finance_service. Depending on the environment (test or not), the isTest value is used to inform the module to either create a single VM or an instance group.

Terraform Domain Drive Iac module usage

The goal of Domain-Driven IaC is to make it easier to automate the provisioning and management of infrastructure resources in a way that is closely aligned with the business goals of the organization. By using a DSL that is tailored to the specific needs of the business, developers and operations teams can more easily collaborate and ensure that infrastructure resources are provisioned in a way that meets the needs of the application and the organization as a whole.

3. Test driven IaC

Test-Driven Infrastructure as Code (IaC) is an approach to infrastructure automation that focuses on using automated testing to ensure that the infrastructure is provisioned and configured correctly.

Test-Driven Iac is mostly used with greenfield projects with very specific requirements and / or newer features being introduced by the cloud provider. It can also be used when working on infrastructure with compliance / security requirements.

In this approach, tests are written to validate the infrastructure code before it is deployed, which helps to catch errors and misconfigurations early in the development process. The tests are typically automated, so that they can be run on a regular basis to ensure that the infrastructure remains in a consistent state.

For example some of the test cases for the modules above can be written using InSpec’s DSL using a control block. These tests are provided inside the module “tests” and can be verified as and when needed. Here are some examples of how tests can be written for each module using InSpec’s control block.

Inspec Test Suite

Test-Driven IaC can help to reduce the risk of errors and misconfigurations that can lead to downtime, security vulnerabilities, or other issues. By using automated tests to validate the infrastructure code, organizations can ensure that the infrastructure is provisioned correctly, and that it remains in a consistent state over time.

Test-Driven IaC can also help to improve collaboration between development and operations teams, by providing a common set of tests that can be used to validate the infrastructure. This can help to ensure that everyone is working towards the same goals, and that the infrastructure is aligned with the needs of the application or service being deployed.

4. Environment parity IaC

Environmental parity in Infrastructure as Code (IaC) refers to the consistency and reproducibility of the deployment environments across different stages of the development cycle. The 12-factor app principles provide guidelines for building software that is scalable, resilient, and portable. When applied to IaC using Terraform, these principles can help ensure environmental parity and enable smooth deployments to different environments.

An example of implementing environmental parity in Terraform is by leveraging the use of variables to separate environment-specific configurations from the Terraform code. For example, in a Google Cloud Platform (GCP) project, we can define variables such as project_id, region, and zone for each environment (e.g., dev, staging, prod). This allows us to use the same Terraform codebase to deploy infrastructure to different environments, with only the variables changing between them.

Let’s assume we have some resources we need to deploy using terraform using environment parity principle. In the example below we define a VM, a database and a storage bucket. Nothing out of ordinary. You can ignore the locals block for now, we will come back to that in a bit.

We then initialize / create our environment workspaces using terraform.

terraform workspace new dev
terraform workspace new staging
terraform workspace new prod

Once those workspaces are created you can, for example create dev.tfvars, stage.tfvars and prod.tfvars files as below.

.tfvars files

This is where the locals block plays its role. The locals block defines vars_files and based on the workspace you have selected i.e. dev, stage or prod, it will use the appropriate .tfvars file to use instance_type and db_tier values. You can see the write once use in multiple environments approach benefit being provided by terraform workspaces here.

locals { 
vars_file = "${terraform.workspace}.tfvars" instance_type = try(file("${path.module}/${vars_file}"), {default = {}})["instance_type"] != "" ? try(file("${path.module}/${vars_file}"), {default = {}})["instance_type"] : var.instance_type
db_tier = try(file("${path.module}/${vars_file}"), {default = {}})["db_tier"] != "" ? try(file("${path.module}/${vars_file}"), {default = {}})["db_tier"] : var.db_tier
}

This approach massively helps in bringing all the environments in alignment on projects where devs must have no difference in infrastructure between environment, though costly this can increase development velocity, feature development and releases frequency.

Conclusion

Hopefully, by utilizing these Terraform IaC development patterns or mixing them based on the needs, infrastructure developers and terraform users can ensure that infrastructure resources are provisioned in a way that meets the specific needs of the business, improving overall system reliability and reducing the risk of errors and misconfigurations. At the end of the day workflows are as important as the tools involved.

👋 If you find this helpful, please click the clap 👏 button below a few times to show your support for the author 👇

🚀Join FAUN Developer Community & Get Similar Stories in your Inbox Each Week

--

--