How Terraform Modules Works
How Terraform Modules Works
count = 5
source = "./module_server"
some_variable = some_value
}
How Terraform modules works?
Terraform is an IaC(infrastructure as Code) framework for managing and provisioning
the infrastructure but have you ever thought of creating only a single terraform
configuration file for managing the complete cloud infrastructure.
Well, it sounds insane because if you only have a single file for managing the complete
infrastructure then it will grow in complexity as well the line of configuration code will
be manifold. That is why terraform introduced a concept of module which will help you
to organize your terraform configuration so that you can re-use the configuration and
keep your terraform code more clean and modular.
In this blog post, we will create two modules module-1 and module-2. Inside each
module, we will install the apache httpd server and nginx server with each module is
having its home page.
2. Create an ec2 aws_instance along with the user_data block in which we will be
writing bash commands for installing the apache2 httpd server.
(Note - Here in this instance I have used the key_name aws_key. Follow this post
on how to create aws keys for your ec2 instance )
resource "aws_instance" "ec2_example" {
ami = "ami-0767046d1677be5a0"
instance_type = "t3.micro"
key_name= "mr-cloud-book"
vpc_security_group_ids = [aws_security_group.main.id]
}
and here is the user_data block for installing the apach2 httpd server.
We will be using the same user_data block for installing the apache2 httpd server .
user_data = <<-EOF
#!/bin/bash
sudo su
yum update -y
yum install -y httpd
cd /var/www/html
wget https://github.com/azeezsalu/techmax/archive/refs/heads/main.zip
unzip main.zip
cp -r techmax-main/* /var/www/html/
Module – 2
user_data = <<-EOF #cd /etc/nginx #cat nginx.conf
#!/bin/sh
3. Define the aws_security_group along with ingress rules for port 80 and 22.
We need to open the port 80 on the ec2 instance to access the apache httpd server
home page and port 22 will need to ssh into the ec2 instance.
Here is the resource block -
resource "aws_security_group" "main" {
name = "EC2-webserver-SG-2"
description = "Webserver for EC2 Instances"
ingress {
from_port = 80
protocol = "TCP"
to_port = 80
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
protocol = "TCP"
to_port = 22
cidr_blocks = ["115.97.103.44/32"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
BASH
ami = "ami-0767046d1677be5a0"
instance_type = "t3.micro"
key_name= "mr-cloud-book"
vpc_security_group_ids = [aws_security_group.main.id]
user_data = <<-EOF
#!/bin/bash
sudo su
yum update -y
cd /var/www/html
wget https://github.com/azeezsalu/techmax/archive/refs/heads/main.zip
unzip main.zip
cp -r techmax-main/* /var/www/html/
EOF
}
ingress {
from_port = 80
protocol = "TCP"
to_port = 80
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
protocol = "TCP"
to_port = 22
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
ami = "ami-0767046d1677be5a0"
instance_type = "t2.micro"
key_name= "aws_key"
vpc_security_group_ids = [aws_security_group.main.id]
user_data = <<-EOF
#!/bin/bash
sudo su
yum update -y
ingress {
from_port = 8080
protocol = "TCP"
to_port = 8080
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
protocol = "TCP"
to_port = 22
cidr_blocks = ["115.97.103.44/32"]
}
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_key_pair" "deployer" {
key_name = "aws_key"
public_key = "ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQCihDAhkioSWqfTDzJSKag2lqQCPNh/hayPl+3TTogfK2+F8WiWI
n3wXeP8F1xT1VzZY/
s+nGMvT+zGGtAfNk8WWdw7orLY7LRYP3zYNzlDSc8U3bg+CA3B4POaQvK6ypUAc+SW2zaRMyLYaQpMsF/
ZD3h7G6Ptr/7+A8xabEk2Lm4aHgXRLoqDOBnK99W1ri9i8Qc7HK3hgYdD3Bnc917NkNsKh/
qaOpKmpslKkRWICrDIR6wFnZYVWTkizr85KAjuC7HKPilCNkntYoYA6HDFhPPPZSb53+E8pFnwxSQjJzk
s9q1B+viZ0BUUbLSBMYnlR9CFrkAS2JI5BvrtGodV admin@DESKTOP-0S3CU0K
"
}
...
BASH
2. Module structure
In the step 1 we have seen the main.tf terraform files of module-1 and module-2.
Now let's talk about the complete structure of your terraform project where you will
have your parent main.tf file which will be calling the module-1 and module-2
module "webserver-1" {
source = ".//module-1"
}
module "webserver-2" {
source = ".//module-2"
}
BASH
4. Module Inputs
Just like any other programming language terraform also supports re-usability with the
help of terraform module. You might be familiar with the concept of functions in other
programming languages. In general functions always have some input parameter which
needs to passed during the function call, similarly terraform module can also accept
input parameters.
Example -
Let's take the same example where we have defined the module-1 but instead of hard
coding ec2 instance type let's create an input variable which can be passed later -
user_data = <<-EOF
#!/bin/sh
sudo apt-get update
sudo apt install -y apache2
sudo systemctl status apache2
sudo systemctl start apache2
sudo chown -R $USER:$USER /var/www/html
sudo echo "<html><body><h1>Hello this is module-1 at instance id
`curl http://169.254.169.254/latest/meta-data/instance-id`
</h1></body></html>" > /var/www/html/index.html
EOF
}
BASH
web_instance_type = "t2.large"
}
module "webserver-2" {
source = ".//module-2"
}
BASH
5. Module Output
Terraform module also have the capability to produce the return output just like
function which do return some value back after calling them.
Example -
ami = var.ami_id
instance_type = var.web_instance_type
key_name= "aws_key"
vpc_security_group_ids = [aws_security_group.main.id]
user_data = <<-EOF
#!/bin/sh
sudo apt-get update
sudo apt install -y apache2
sudo systemctl status apache2
sudo systemctl start apache2
sudo chown -R $USER:$USER /var/www/html
sudo echo "<html><body><h1>Hello this is module-1 at instance id
`curl http://169.254.169.254/latest/meta-data/instance-id`
</h1></body></html>" > /var/www/html/index.html
EOF
}
output "public_ip_ec2" {
value = aws_instance.app_server.public_ip
description = "Public IP address of EC2 instance"
}
BASH
module "webserver-1" {
source = ".//module-1"
web_instance_type = "t2.large"
}
output "public_ip_ec2" {
value = module.module-1.public_ip_ec2
description = "Public IP of EC2"
}
module "webserver-2" {
source = ".//module-2"
}
For google you can write the provider in the following manner -
provider "google" {
}
While you are trying to write you're terraforming module always keep in mind that you
have to go for simplicity and not to increase the complexity of your terraform project.
Always keep the modules bare minimum if possible so that it will help other developers
to understand and troubleshoot the issues if needed.
Terraform has a very good concept of local modules which you use to encapsulate your
infrastructure logic. Use of modules is always recommended from the start of the
project so that you have more control over the terraform code and it does not get
spread sporadically.
Refer to the terraform public registry for finding more stable modules so that you do not
have to re-invent the wheel.
Always keep and habit of publishing the modules so that it can be used by other teams
members also
6. Benefits of Modules
Well, you will always get benefited from modules if you implement it properly. But here
are certain advantages you will get with the terraform modules -
Organize configuration - With modules it is always easy to navigate and it helps any
developer to understand the terraform project with ease. Certain with the module you
can break down very complex infrastructure modules into very simplistic terraform
modules.
Encapsulation - You can benefit from the encapsulation also and with terraform module
you can hide the internal implementation of your infrastructure set up so that you can
prevent unwanted changes happening to your modules by other developers.
Re-usability - If you have broken down your infrastructure into smaller and generic
modules then it would help you to re-use the modules into another infrastructure setup.
Consistency - Following the best practices(encapsulation, organize, simple terraform
module) will help you to achieve consistent behavior across all the different
environments which will help you to reduce the debugging time and reduce the
infrastructure maintenance cost.