How to Build a Terraform Module Example

Published:21 January 2022 - 6 min. read

Michael Thanh Image

Michael Thanh

Read more tutorials by Michael Thanh!

Terraform modules are a fantastic way to encapsulate common parts of code, making them more reusable across multiple Terraform projects and configurations. But how do you build a Terraform module example? Well, you’re in for a treat!

In this article, you’ll learn how to build a Terraform module that you can use to create a basic AWS EC2 instance.

Ready? Read on and start building!

Prerequisites to Build Terraform Module Example

This tutorial will be a hands-on demonstration. If you’d like to follow along, be sure you have the following:

  • An AWS account – If you don’t have an AWS account, a free tier account is available.
  • An EC2 instance with Terraform installed – This tutorial uses Terraform v0.14.4.
  • An installed and configured AWS CLI.

Setting up a Directory Structure

Why must you set up terraform project directory structure in the first place? Firstly, Terraform needs a directory structure to organize your scripts and files like other programming languages. Secondly, Terraform uses a .tf file to describe main Terraform configurations, and other terraform files (.tf states) to describe Terraform resources.

Terraform reads configurations from the root directory when it starts, so terraform configurations must be in the root directory.

1. Open your terminal and run the following commands to create a new directory named terraform_project and switch to that directory. You can name the directory differently as you prefer. This directory will hold all the files and subdirectories for this project.

mkdir terraform_project
cd terraform_project

2. Run the mkdir command below to create two directories. First is modules, a parent directory, and vpc, a subdirectory of the modules directory.

mkdir -p modules/vpc

3. Finally, run the following command to change your current directory to the vpc directory inside the modules directory using an absolute path. Be sure to replace cloud_user with your username.

You specify the absolute path of the vpc directory since each user in your system has their own home directory.

cd /home/cloud_user/terraform_project/modules/vpc/

Writing Terraform VPC Module Codes

Now that your project directory structure is ready, it’s time to build a Terraform module to create an AWS Virtual Private Cloud (VPC). You’ll create multiple Terraform configuration files, so get your favorite code/text editor ready.

You’ll create configuration files in the ~/terraform_project/modules/vpc/ directory throughout this section.

1. Create a new file called main.tf (Terraform VPC module) with your text editor and populate the file with the following code. The below code will initialize variables, declare the AWS provider block and specify the subnet range with the cidr_block attribute. The resource block belonging to this VPC module will define the AWS_VPC and AWS_SUBNET resources.

# The provider block is where the parameters for this module are defined. 
# In this case, it defines a single parameter named region, 
# which  is the AWS Region where the VPC will be deployed.
provider "aws" {
region = var.region
}

# This is a resource block and it's where you define VPC resources.
resource "aws_vpc" "this" {
# This cidr_block defines the VPC as a 10.0.0.0/16 network. 
# In other words, it's a 256 Class C (CIDR) IP address  range.
cidr_block = "10.0.0.0/16"
}
# This is a resource block and it's where you define VPC resources.
resource "aws_subnet" "this" {
# This line will bind the vpc_id to the vpc defined in the "aws_vpc" module.
vpc_id     = aws_vpc.this.id
cidr_block = "10.0.1.0/24"
}
# This block defines a single parameter for this module 
# named /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
data "aws_ssm_parameter" "this" {
name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

2. Next, create another file called variables.tf and populate the file with the following code. The variables.tf file contains all variables that the configuration file references.

# A variable block, which defines one or more variables inside it.
variable "region" {
	# Defines the data type of this variable as a string.
	type  = string
	# Sets the default value for the region variable.
	default = "us-east-1"
}

3. Finally, create a file called outputs.tf and paste the code below to the file.

The code below is critical to exporting values from a module to the calling environment. When a module is called, Terraform creates a single resource. That resource has the name of the module and a type of output.

The contents of outputs.tf define the values for this resource.

# Outputs the id of the subnet you created in the module
output "subnet_id" {
	value = aws_subnet.this.id
}
# Outputs the value of the 
# /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 parameter.
output "ami_id" {
	value = data.aws_ssm_parameter.this.value
}

Writing Main Terraform Codes

You’ve completed setting up your modules and auxiliary files, so you can now start working on the main code.

1. Run the below command to navigate to your main project directory (~/terraform_project)

cd ~/terraform_project 

2. Create a file called main.tf file with the following contents.

The code below will create a VPC with an ID of vpc-xxxxxxx in the AWS region specified by var.main_region and a single subnet with an ID of subnet-yyyyyyy.

# Binds the variable to the value of var.main_region.
variable "main_region" {
	type  = string
	default = "us-east-1"
}
# Binds the value of the variable to the AWS region.
provider "aws" {
	region = var.main_region
}
# Calls the code in the vpc module you created earlier.
module "vpc" {
	source = "./modules/vpc"
	region = var.main_region
}
resource "aws_instance" "my-instance" {
	# Binds the value of the ami variable to the AMI id in this module.
	ami = module.vpc.ami_id
	# Binds the value of the subnet id to the subnet id in the module.
	subnet_id = module.vpc.subnet_id
	# Binds the value of instance type to t2.micro.
	instance_type = "t2.micro"
}

3. Lastly, create another file called outputs.tf and populate the file with the code below.

The code below defines the values of outputs when this module is called.

# Print out the private ip of the EC2 instance that will be created using this module
output "PrivateIP" {
	description = "Private IP of EC2 instance"
	value    = aws_instance.my-instance.private_ip
}

Deploying Terraform Code

You now have your module and configuration files ready. But they’re not doing much at the moment unless you deploy your code.

1. Run the terraform fmt command below to ensure your code is formatted correctly. The -recursive flag tells Terraform to go through all the files in your directory.

Terraform uses a set of rules to determine how it should format your code called the Terraform Style Conventions. If you have files that do not comply with these rules, this command will resolve that for you.

terraform fmt -recursive
Checking the code format
Checking the code format

2. Next, run the terraform init command below to initialize your Terraform project.

This command is a helper that initializes a new Terraform project. This command goes through all the files in your project and automatically detects modules while downloading any necessary dependencies for modules.

terraform init

Make sure to run this terraform init command in your main project directory. You should also initialize a Terraform project only once, or you might end up with many useless files.

Initializing your Terraform project.

Initializing your Terraform project.

Run the terraform validate command to test your code for errors.

This command checks if the code you wrote is syntactically correct and will not break anything. If any files contain errors, this command will tell you which ones and how to fix them.

terraform validate

Ensure that you have no errors before continuing, or Terraform cannot deploy your code when the time comes.

Validating your code
Validating your code

4. Run the terraform plan command to create an execution plan.

This command analyzes all the files in your project and then displays what actions to perform without changing anything. terraform plan

terraform plan

In this demo, the output below shows three resources configured in this module, and no resources will be modified or deleted.

Creating an execution plan
Creating an execution plan

5. Now run the terraform apply to apply your execution plan (from step four) while accepting prompts automatically (--auto-approve). This command tells Terraform to start creating the resources described in the execution plan.

Deploying your resources may take a while, so be patient and just wait it out.

terraform apply --auto-approve

Once the creation phase is over, Terraform will present you with a summary of what took place, as shown below.

You can see that Terraform created the EC2 instance and outputted the private IP address as was configured in the outputs.tf file in your main project directory.

Previewing the execution plan deployment progress
Previewing the execution plan deployment progress

6. Finally, run the terraform state command below. This command lists resources that have been created and are now tracking in the state file.

The state file is a small file that stores the status of your resources. The state file also lets you run commands without specifying whether or not they have been created or destroyed. As a result, this file saves you time and makes Terraform run faster.

terraform state list

You will get a resources list, as shown below, that includes your EC2 instance that was configured and created by the main code.

You can also see three resources (with module.vpc as their prefix) configured and created via the VPC module code.

This output confirms that your modules are all working properly.

Confirming the modules are working properly
Confirming the modules are working properly

Conclusion

In this tutorial, you’ve gone through a Terraform module example and learned how to create one by writing your own code. You’ve also touched on passing variables between modules, testing code functionality before deployment, and applying the module to deploy the code.

At this point, you should be familiar with the basic structure of a Terraform module and how to create your own. Now, why not engage yourself more with Terraform? Perhaps learn how to Deploy an EC2 instance to run Docker with Terraform?

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!