1.2.1. Terraform Module Anatomy
In the topics explored in this book, the smallest unit is a single Terraform module. There are actually two different types of Terraform modules. The folder where we typically run commands like terraform apply is called the Root Module. The root module can directly declare various resource blocks (as most tutorials and example code do), but doing so goes against the modularization goals we described at the beginning. The other type of module is reusable module. This type of module is not intended for running any Terraform commands directly in its directory. Instead, it should be used within root modules and composed with other reusable modules to describe the desired infrastructure. Each reusable module should have clear domain boundaries, and should be highly focused on resources in a specific domain. For example, if a module responsible for creating and maintaining a Kubernetes cluster contains resources for creating and maintaining Virtual Networks and their subnets, this is very likely an anti-pattern (though there are exceptions, which we will describe in detail later).
The modules mentioned in this book, unless specifically stated otherwise, are all reusable modules.
1.2.1.1. Rules Make Order
Currently, we can further categorize reusable modules (we will detail this in later chapters), but regardless of which category of reusable module, they all follow the same set of rules:
- Have similar directory structures
- Follow the same coding standards
- Highly focused in a specific domain
- Provide clear input and output documentation, along with a set of example code for module users to learn usage and quickly experience functionality
- Consider not only Day 1 resource creation scenarios, but also Day 2 infrastructure maintenance needs
The fifth point means ensuring that when using the module, you can successfully create the desired infrastructure, and also considering that during future daily maintenance, when we want to execute certain changes, those changes will be executed correctly. When we don't want to execute any changes, terraform plan should not return any configuration drift - that is, the change plan should not contain any change requests. This sounds obvious, but in actual practice, achieving this often requires additional work (this is also why I believe all attempts to generate Terraform code and use Terraform merely as an execution tool are anti patterns. Terraform management must use high-quality modules, and high-quality modules often must hand crafted and maintained).
A standard Terraform module must include:
main.tfvariables.tfoutputs.tfterraform.tf- Documentation
examples/directory- Continuous integration pipeline code
Infrastructure as Code (IaC) code is also code, just like applications written in general-purpose programming languages, it must follow various coding standards. One incorrect mindset is to view Terraform code as the output of some code generator, treating Terraform as an executor, and thus not caring about the style and quality of the generated code. The biggest difference between Terraform and other scripting languages is that it has the concept of state. It is this state that requires us to be very careful about maintaining code quality and keeping the code highly maintainable, otherwise we might encounter unexpected data loss or very awkward situations. For this reason, we must establish many coding rules.
In this chapter, we will analyze one by one what a standard-compliant module should have and which rules should be followed when writing module code. Please note: These rules are what I personally follow and implement in my daily development work, and they carry a very strong personal style. Indeed, some people have expressed different opinions on certain parts, so please do not misunderstand them as some kind of "official" specifications or divine laws that will cause errors and misfortune if not followed. Please read with a critical attitude, thank you in advance!