Terraform Modules Basics: Types, Use Cases, and Examples

Blog Featured image for a blog with a title - Terraform Modules Basics

Terraform Modules Basics: Types, Use Cases, and Examples

Blog Featured image for a blog with a title - Terraform Modules Basics
Categories

Introduction

Terraform modules are reusable, organized components that simplify infrastructure-as-code (IaC) development by grouping related Terraform configurations into a single package. By using Terraform modules, teams can standardize and automate infrastructure provisioning across multiple environments, ensuring scalability, consistency, and reduced code duplication. The modules assist in the management of complex infrastructure by dividing it into small, manageable components, which makes updating and maintenance easier. They may be obtained through public registries, through private repositories, or generated internally, providing flexibility in different use cases. Whether deploying cloud resources like VPCs, servers, or databases, Terraform modules promote best practices, faster deployments, and improved collaboration among DevOps teams. Leveraging them effectively can significantly streamline cloud infrastructure management.

For those looking to gain hands-on experience and a deeper understanding, enrolling in a Terraform and Ansible course can be a valuable step toward streamlining cloud infrastructure management and enhancing DevOps capabilities.

In this blog, we will help you understand modules in Terraform along with its types and use cases. We will also discuss how you can create Terraform modules with example.

What is Terraform module?

Terraform modules are a set of standard configuration files in a specific directory. Terraform modules encapsulate groups of resources dedicated to one task, reducing the amount of code you have to develop for similar infrastructure components.

Some say that modules in Terraform are a way of extending your present Terraform configuration with existing parts of reusable code, reducing the amount of code you have to develop for similar infrastructure components. Others state that the Terraform modules definition is one or more .tf files piled on top of each other in a directory of their own. Both are correct.

It is also possible to use module blocks to enforce compliance on other resources, e.g., to deploy databases with encrypted disks. Hard-coding the encryption configuration and not exposing it in variables, you are ensuring that whenever the module is called, the disks will be encrypted.

A typical module can look like this:

├── main.tf

├── outputs.tf

├── README.md

└── variables.tf

As you can see, virtually any Terraform configuration is already a module by itself. When you execute Terraform in this directory, then those configuration files will be the root module. It implies that this setup is the foundation of your operation, a nucleus that you can build on.

Below, we have discussed the basic difference between Terraform Resources and Terraform Modules.

Difference Between Resources and Modules in Terraform

A resource in Terraform describes a piece of infrastructure that is going to be created (e.g., a VPC, a subnet, an EC2 instance, etc), whereas a module is a collection of resources that are used together to achieve a reusable use case.

FactorsTerraform ResourcesTerraform Modules
DefinitionIndividual infrastructure componentsReusable groups of resources
ScopeSingle cloud object (VM, S3 bucket)Multiple related resources
Syntaxresource “type” “name” {}module “name” { source = “…” }
ReusabilityLimited to single useHighly reusable across projects
ComplexitySimple, atomic unitsComplex, multi-resource systems
Exampleaws_instance, azurerm_storage_accountVPC module, K8s cluster module
ParametersDirect argumentsInput variables
OutputAttributes via referencesExplicit output values
NestingCannot contain other resourcesCan contain resources & modules
PurposeCreate specific infrastructureEncapsulate & standardize patterns
State FileDirectly in state fileNamespaced in state file
VersioningN/ASupport versioning

Let us now move on to next section where we will discuss about different types of Terraform modules.

Types of Terraform modules

You can use modules to build reusable components within your infrastructure. There are primarily two types of modules, depending on how they are written (root and child modules), and depending on whether they are published or not, we identify two different types as well (local and published).

Root module

The root module is the collection of all the resources declared in the .tf files in a Terraform configuration, so every Terraform configuration has a root module.

Even when you are just making a main.tf with only a locals block in it with a local variable, that is still a root module.

This is a bit confusing, but remember that any Terraform configuration can be turned into a reusable module for other configurations. Each module may call other modules, and all modules called within a module are child modules.

Child module

To call a child module is to add all the resources defined in that module to the current configuration. This is achieved through a module block within your Terraform configuration:

module "webservers" {
   source = "../webservers"
}

Local module

A local module is a module that was not published in any registry, and when it is sourced, it is using the path to that module.

Published module

A published module is a module that has been published to a Terraform Registry, or even just on a VCS, and has a tag attached to it. In the case of sourcing a published module, the URL of the module is sourced either via the registry or directly via the VCS.

Let us now discuss the use cases of modules in Terraform.

Terraform Modules Use Cases

The short answer to the question “When should you use Terraform modules?” is always, but it may vary depending on your organization and where you are in the infrastructure as code journey.

The most effective approach to writing Terraform code is to remember about reusability. HCL is a declarative language and can be quite wordy, so repeating the same configuration many times will be tedious. Therefore, in most cases, you should define modules at the very beginning and then attempt to use them as much as possible to achieve maximum reusability.

When you are new to Terraform or IaC in general, you can skip the modules until you understand how Terraform works.

Creating your First Terraform modules

Alright, you now understand what a Terraform module is, so now we can have a look at a step-by-step process of creating them. With some terraform modules examples.

1. Create the module block

In order to use a Terraform module, you must first indicate that you want to use it in your present configuration. To accomplish this, apply the module block and enter the corresponding values of variables:

module "terraform_test_module" {
 source  = "spacelift.io/your-org/terraform_test_module"
 version = "1.0.0"
 
 argument_1                     = var.test_1
 argument_2                     = var.test_2
 argument_3                     = var.test_3
}

As you’re adding the variables, there are a few arguments that you should keep an eye on: their source, version, and four meta-arguments.

Sources

Terraforms modules can be stored either locally or remotely. The `source` argument will change depending on their location. As an example, suppose the module you want to call is in a directory called terraform-test-module in the same directory as your root module directory, then your root configuration would be:

module "terraform_test_module" {
 source  = "./terraform-test-module"
[...]

But, if you want to keep the module in a VCS (let’s assume git and GitHub), the source will need to point to the correct repository containing the appropriate version of the module that you’re calling:

module "terraform_test_module" {
 source  = "[email protected]:your-organization/the-repository-name.git?ref=1.0.0"
[...]

Terraform modules can also be stored in so-called registries. Registries are where modules published by other Terraform users can be found, or where you can store the modules you have created, either privately, to your company/yourself, or publicly, so that everyone can enjoy them. A registry-based Terraform module may appear as follows:

module "terraform_test_module" {
 source  = "<registry address/<organization>/<provider>/<module name>"
 version = "1.0.0"
[...]

As you can see, those two examples are slightly different. One of the major strengths of the Spacelift registry is that it has an example of every module. This implies that you can verify that the source argument in your configuration is accurate. Additionally, you can grab the entire example and use it as a template, filling in the blanks and starting your work right away!

Versions

Versioning allows you to manage what changes to modules should be applied to your infrastructure. Why is it useful? It assists in avoiding the destruction of your infrastructure by unpredictable updates or bad code. You are likely to have experienced that any update of software, packages, or applications on a production server can go wrong. This can also happen to Terraform modules if they’re not kept under control.

The syntax for version constraints is simple. Simply put, a version is a string containing one or more conditions.

The first part is an operator:

  • “=” (or no operator) means “Only one version—this specific version.”
  • “!=” translates to “Other versions are fine, except this one here”
  • “>, >=, <, <=” are used for comparisons. For example, “Use any version newer than 1.0.0, but older than 1.1.0”
  • “~>” is quite interesting. This operator allows only the rightmost part of the version number to increment. In other words, “~>2.6.0” would mean that you wish to use the newest patch version of the module (2.6.<anything>), but not the newer minor or major versions (2.7.0 or above).

The second syntax component is the version number. Although it isn’t absolutely required (except when using registries), it’s best to stick to the Semantic Versioning convention—it’s easy to understand and very transparent. A glance at the version, and you are aware of where you are.

As you may have already guessed, there is an exception to the rule of keeping things versioned; in two of the above examples, the version argument is defined. In one, it’s not. This is because Terraform treats modules loaded out of the same source repository as being of the same version as the caller. Local modules, incidentally, do not require any version constraints at all.

Meta-Arguments

Meta-arguments are special arguments that change the behavior of Terraform when parsing the declared module. Currently, there are four of them in active use:

  • “Count” and “for_each” are used to create multiple instances of the same module or resource. More on this: Terraform Count vs. For_Each Meta-Argument: When to Use Them
  • “providers”— this meta-argument enables you to explicitly specify the provider that the module should use to operate. This is useful when you have two accounts of cloud services and you need to create resources that are attached to the second one. To do that, you must design your Terraform modules correctly, so that it accepts the provider as an argument and forwards it, as follows:
provider "aws" {
 alias  = "frankfurt"
 region = "eu-central-1"
}
 
module "example" {
[...]
 
 providers = {
   aws.nested_provider_alias = aws.frankfurt
 }
}

“depends_on”—Terraform usually does a good job with implicit dependencies, but they are not always sufficient. When you must assert that one thing must be made prior to another, then you can use this meta-argument to establish a clear boundary between resources or modules.

2. Declare module outputs

There are times when you may have to utilize the values that are present in the already created resources. Those resources are fully encapsulated by a Terraform module, and this is how they can be accessed.

First, declare in your Terraform module that the selected value should be available as an output:

output "random_string" {
 value       = aws_example_resource.example_device.random_string
 description = "A random string from an example resource on AWS."
}

Then, call this value like this:

resource "example_resource" "example" {
 [...]
 
 random_string = module.example.random_string
}

The resources do not automatically transfer their module outputs to the next module-so unless you specify an output, it will not exist.

3. Taint Terraform modules

In some cases, you may have to rebuild some or even all of the component parts of the Terraform module. Since it is not possible to flag a whole module that should be recreated, you will have to manually taint all the resources that were created by the module. Although it might appear as a disadvantage, it is a characteristic that provides extra security against human error. Better still, you will hardly ever have to contaminate a whole Terraform module.

To taint the resources that were created by the example module presented above, try this:

terraform taint module.example.aws_example_resource.example_something

4. Test modules

Be it a blessing or a curse, the code of Terraform is code, and ought to be tested accordingly. It is absolutely crucial. However, it can be a pain when performed manually. Fortunately, Spacelift, among other upgrades and extensions, offers automated module testing and you will definitely adore it.

Terraform modules managed by the Spacelift registry get tested every time you push a new commit. They are used, erased, and you have all the information on the fly. Should anything go wrong in the process, the whole test fails as well. If everything goes smoothly, the test is successful. It is all automatic, though you can even write your own tests, like this one:

provider "aws" {
 region = "eu-central-1"
}
 
resource "random_string" "this" {
 length  = 16
 upper   = false
 number  = false
 special = false
}
 
resource "aws_vpc" "test" {
 cidr_block = "10.10.0.0/16"
}
 
module "test" {
 source = "../"
 
 cidr_blocks = {
   eu-central-1a = "10.10.0.0/24"
 }
 
 environment = "test-${random_string.this.result}"
 name        = "test-${random_string.this.result}"
 vpc_id      = aws_vpc.test.id
}

What problems do Terraform modules solve?

Alright, now that you know how to use Terraform modules and what to keep an eye on when doing it, let’s see what problems Terraform modules solve.

  • Code Repetition
  • Lack of Code Clarity
  • Lack of Compliance

Frequently Asked Questions

Q1. What is Terraform Module?

A Terraform module is a self-contained, reusable collection of Terraform configuration files organized within a single directory.

Q2. What is the main TF in Terraform?

The main TF in the context of Terraform stands to mean the main.tf file. This file is the place where you will most often start defining your core infrastructure configuration in a Terraform module or root module.

Q3. Why do we need Terraform Modules?

Terraform modules are essential for managing infrastructure as code due to the following reasons

  • Reuseability
  • Consistency
  • Abstraction
  • Scalability
  • Collaboration
  • Versioning

Q4. What are Terraform modules examples?

Some common examples of Terraform modules are VPC setups for networking, EC2 instances for servers, and RDS modules for databases. They save time by grouping related cloud resources together.

Conclusion

Modules in Terraform facilitate the management of infrastructure through reusable and repeatable configurations that are also scalable. They reduce unnecessary repetitions of code, improve the readability, and make it consistent in different environments. Teams can accelerate deployments, standardize and simplify updates without losing flexibility using local and published modules. Terraform Modules enhance cooperation and are easily manageable, which makes them essential to Infrastructure-as-Code procedures performed to establish VPCs, servers, or databases. Incorporation of modules in Terraform finally guarantees an accelerated, dependable, and future-proof infrastructure.

Get in touch

Blog
Looking For Networking Training- PyNetLabs

Popular Courses

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Automation

(FRESHERS / EXPERIENCED)

Network Expert

Leave a Reply

Your email address will not be published. Required fields are marked *