The Ops Community

Cover image for Terraform Modules - A High Level Overview
Moses Itoya
Moses Itoya

Posted on

Terraform Modules - A High Level Overview

Topic Introduction

IaC helps with better complexity management and a much better visibility into infrastructure configuration. Whichever IaC tool you are using, it's important to have a code that is easier to read and more understandable, especially if you are in a team environment. This would ensure your code base is properly maintained and very well-organized. All these centers around refactoring, which reduces complexity and makes future releases more efficient. For Terraform, Modules helps a lot with Refactoring of your code.

Modules are containers for multiple resources that are used together. A module consists of a collection of .tf and/or .tf.json files kept together in a directory. To package and reuse resource configuration in Terraform, you'd need to understand modules and how they work, as this is the major way. The Agenda of this article is to:

  1. Know what modules are
  2. Know how modules interact
  3. Know modules best practices

NOTE: Knowledge of Terraform is needed to fully understand the contents of this article, It is assumed that you already have this Knowledge going forward.

While some who are new to terraform sometimes say Modules is a complex topic and try to avoid it, having a good understanding of it is crucial to writing codes that can be shared, easily read and reusable. Who wouldn't want that? Well, I'd say someone who don't understand how it works for sure. Let's take a brief look at what Modules really are, this insight would help going further down the somewhat intricate path of Terraform Modules.

What Are Modules

Even as a beginner to Terraform, you’ve already interacted with modules. That’s the Root module, which contains all resource configuration files ending with the .tf terraform extension in the main working directory. Modules is just simply a better way of organizing and maintaining your resources configuration for easy modifications and efficient management of your infrastructure.

For Example...

Imagine your Infrastructure code base needs several Instance resource with it's own VPC and Subnet, you can create a module with the required resource, and call it whenever you need to create such an Instance on your infrastructure. Say you need multiple of such instance, all you have to do is pass in the count, or for each meta-arguments when calling the module. Talking about Modules, there’s the Root module which we define. There’s also the child module, this is a module that is been called by the root module.

The Instance Module in the example above is an example of a child module as we would call it from the root module. Child modules can be called multiple times within the same configuration, and multiple configurations can use the same child module, either within the same configuration or in separate configurations, allowing resource configurations to be packaged and re-used. Later on in the article, we’d see how to create a module, that would also show how we call a module to include their resources into the configuration.

There's some more..

Other than the Root module and child module, there is also the Published module. Like we had the concept of backend in terraform where we can store our state locally or remotely, this is somewhat similar. Terraform has a registry where you can publish modules for others to use, and to use modules that have been published by others. This registry can either be public or private. There are lots of modules available for use today on the registry. Terraform Cloud and Terraform Enterprise both include a private module registry for sharing modules internally within your organization. Depends on what you plan to use, there’s a way to include it  or reference it in your configuration, we’d take a look at this in a later part of this article. 

Interacting with Modules

Now that we have a pretty detailed understanding of what modules are, let's take a look at how we can interact with it in our infrastructure configuration, i.e. calling the child module. The child module can either be sourced from

  • local path, i.e. for closely related modules used primarily for the purpose of refactoring out repeated code elements
  • Native Terraform module registry, i.e for modules intended to be shared by multiple calling configurations
  • Github, Bitbucket, see more modules sources here

The same source address can be specified in multiple module blocks to create multiple copies of the resources defined within, possibly with different variable values. After adding, removing, or modifying module blocks, you must re-run terraform init to allow Terraform adjust the installed modules

Our example child module block would be using a local path. To call a module means to include the contents of that module into the configuration with specific values for it's input variables. This input variables allow you tailor certain parts of Terraform modules without altering the module's own source code, therefore making your module composable and easily reusable. Take a look at this module block below:

module "Security" {
  source = "./modules/Security"
  vpc_id = module.VPC.vpc_id
Enter fullscreen mode Exit fullscreen mode

The label immediately after the module keyword is a local name , used to refer to the instance of the module by the calling module. To be able to interact with modules you have to know the arguments for the modules. A mandatory module argument is the source which tells terraform the location of the module, be it a local path or private registry or any of the source types. There is also the version argument which is recommended for modules from a registry so terraform can know which version of the module to use. As discussed already, the input variable defined by the module is also an important argument. Meta arguments are some special constructs in Terraform which are available for Resources and Modules, along with source and version. They include:

  • depends on
  • count
  • for_each
  • provider

In the example module block above, the security module source is a local path and it uses the relative filesystem path, not an absolute path. Terraform does not consider an absolute filesystem path(the same location in a file system relative to the root directory) to be a local path as it treats it as a remote module. It's best to use a relative filesystem path(points to a specific location in a file system relative to the current working directory you are working on). The input variable there which id the vpc_id passes in a vpc_id variable from another module called VPC in the same configuration.

You can use modules in various ways but it's best to keep everything easily understandable. I'd talk more about this in the next article which would be a continuation of this article and would center around "Terraform module best practices", this is in a bid to reduce the lengthiness of this article.

Discussion (0)