Building highly available VMSS on Azure using Terraform Modules
To demonstrate how modules work in real life, we’ll be building an Azure Virtual Machine Scale Set cluster for multiple environments like dev, test and production.
We’ll be running a cloud-init script inside all of the Virtual Machines, which are part of the Scale set to install docker and run an Nginx web server. The code contains the rest of the configuration to expose the proper ports via a load balancer to access the nginx web servers on multiple machines. To build the same with modules, we would have to write a separate dev, test and production configuration in Terraform. Building multiple codebases for different environments would be a laborious activity with a likelihood of discrepancies in the configurations of the three environments. However, using modules would ensure that the base configuration for the cluster would always be the same, enabling us to maintain dev-prod parity.
Defining the Folder Structure
In building the Nginx VM Scale Set, we need to define the folder and file structure where we will store our module files. For example, the folder structure would look something like the one given below:
For this example, we will use the folder called modules as a container for all the separate modules we will use throughout this lab. The folder named vnet will be the place we’ll use to store the main.tf, output.tf and variables.tf files which hold the configuration for the vnet that the rest of the resources will use. Likewise, a subnet folder will be hosting similar files to our vnet folder. The subnet module will create the resources required for the subnets. Finally, we have the vmss folder that holds the configuration for the Azure Virtual Machine Scale Set. Within it, we create the required resources like public_ip, load balancers, an address pool, lb health check probe and rules to expose the ports on the load balancer. The environments folder has the folders corresponding to the environment names; we will use the <environment-name>.tfvars files to create the resources based on the environment in question. We will use the environment configuration in the tfvars files in the environment folders in the commands like plan and apply to override the terraform.tfvars stored in the root module. The backend.tf defines the cloud provider for our project. We will use azurerm in our case and the terraform config like the required_version and required_providers.
Writing the VNET Module
To use a module between multiple environments, first, we need to write a reusable terraform vnet module.
Before we define the modules, we need to write the variables that will be used by the modules, using the following configuration in the modules/vnet/variables.tf file:
The modules/vnet/main.tf file contains the configuration for the VNET module as given below:
The modules/vnet/outputs.tf file contains the output configuration for the VNET module as given below:
The outputs.tf file in the root module contains the output values that Terraform will print on the console. If there are no outputs, Terraform will not print the values of the infrastructure objects after we run the plan, apply, or the output command.
Writing the Subnet Module
Next, we need to write a reusable terraform subnet module. This module must create a subnet into which we can launch our VM scale sets.
Before we define the modules, we need to write the variables that will be used by the modules, using the following configuration in the modules/subnet/variables.tf file:
The modules/subnet/main.tf file contains the configuration for the subnet module as given below:
The modules/subnet/main.tf file contains the output configuration for the subnet module as given below:
The outputs.tf file in the root module contains the output values that Terraform will print on the console. If there are no outputs, Terraform will not print the values of the infrastructure objects after we run the plan, apply, or the output command.
Writing the VMSS Module
Next, we need to write a reusable terraform vmss module. This module is required to create Virtual Machine Scale Sets on which we will be running the Nginx web servers.
Before we define the modules, we need to write the variables that will be used by the modules, using the following configuration in the modules/vmss/variables.tf file:
The modules/vmss/main.tf file contains the configuration for the VMSS module as given below:
The modules/vnet/main.tf file contains the output configuration for the VMSS module as given below:
The outputs.tf file in the root module contains the output values that Terraform will print on the console. If there are no outputs, Terraform will not print the values of the infrastructure objects after we run the plan, apply, or the output command.
Writing the environment variable files
Now that we have defined our modules, we can create the environments folder to store the override tfvars for the dev, test and production environments. We have previously described a folder environment for the same, and under the folder, we have created folders with the names of the environments. In each folder, we’ll have a <environment-name>.tfvars file with similar variables to the terraform.tfvars file, which is in the root module.
First, we will define the dev environment for the cluster in the environment/dev folder in a dev.tfvars file, with the following configuration:
We have detained the configuration which we will use to create our dev environment with variables like:
capacity: defines the number of servers in the VM scale set.
location: the deployment region for the environment.
address_space: the CIDR for the VNet.
subnet: the CIDR for the subnet.
environment: the environment name.
default_tags: the tags for the resources.
application: the application name.
Similar to the above dev.tfvars file, we will define the override for the other environments like test and production.
Next, we will define the test environment for the cluster in the environment/test folder in a test.tfvars file, with the following configuration:
Finally, we will define the test environment for the cluster in the environment/prod folder in a prod.tfvars file, with the following configuration:
Using the Modules in the root module
We have defined the modules, and now we can use the modules in our main.tf file located at the directory’s root. We can define the main.tf file as given below:
Next, we define the outputs for the root module in the outputs.tf file given below:
Next, we will define the variables for our root module in the variables.tf file given below:
Finally, we need to declare the variables in the terraform.tfvars file present in the root module:
With a little effort, we can structure or restructure the codebase so that each significant infrastructure component sits within a module. Terraform modules written in a configurable and reusable manner can act as the basic building blocks of a clean, readable and scalable IaC codebase. In addition, writing modules would help us better manage a growing code base and reduce useless repetition in code.
Expand your knowledge of Infrastructure as Code and Terraform with our insightful collection of articles! Dive into a range of topics that will help you master the art of managing infrastructure:
Embrace the power of Terraform and Infrastructure as Code with this comprehensive collection of articles, and enhance your skills in deploying, managing, and maintaining your infrastructure.
Subscribe to Faizan Bashir
Get the latest posts delivered right to your inbox