Terraform: Creating A Custom Module For EC2

Use Case

A simple Terraform file has been made by team member in your organization to launch an EC2 instance. Your company would like to use this template as the standard for launching EC2 instances, however it does not currently follow Terraform best practices. You have been directed to modify the file so that it is a module, allowing easy re-use by team members within the company.

Steps

  1. Fork and clone the original repo locally with the ec2.tf template as a starting point to create the EC2 : https://github.com/LevelUpInTech/terraformec2.git
  2. Create a custom module for EC2 out of the resource block that can be used as repeatable infrastructure.
  3. Push the newly created module and the EC2.tf file our repo.
  4. To view my full code please visit my GitHub.

Modules

As your infrastructure grows, it can get increasingly complex and difficult to manage in a single file. Understanding and navigating the file can become difficult due to the size and number of resources. Sharing parts of the configuration with team members is error prone and hard to maintain for the same reason. Modules can be used to organize, encapsulate, and re-use your configuration. Modules can also provide consistency and ensure best practices are followed.

Prerequisite

Fork and Clone Repository

  1. Navigate to https://github.com/LevelUpInTech/terraformec2.git and click the Fork button in the top right corner of the browser.

2. Open your preferred IDE and clone the now forked repository .

$ git clone https://github.com/<your GitHub>/terraformec2.git

3. You should now have a new directory under your current working directory named terraformec2. Change into the terraformec2 directory.

$ cd terraformec2

Setting Up Our Module

  1. Create a new directory in our terraformec2 directory named instance.
  2. In the instance directory create main.tf, outputs.tf, providers.tf, and variables.tf files.

3. The ec2.tf file currently has a provider section and a resource section. Both of which need to be moved to our new instance module. First let’s take the Provider information and cut and paste it to the providers.tf file.

4. Take the aws_instance resource and cut and paste into the main.tf file.

5. ec2.tf should now be a blank file.

6. Add the following to the ec2.tf to reference our instance module.

7. While in the terraformec2 directory run terraform init to initialize Terraform.

8. Run terraform fmt to format our code.

9. Run terraform validate to ensure we don’t have any syntax errors.

10. Run terraform plan to see what resources we will create.

11. Run terraform apply and type yes when prompted.

12. Open your AWS account and navigate to the US West (Oregon) us-west-2 region > EC2 > Instances to see if our instance was created.

13. Success! Now go ahead and run a terraform destroy from the terminal to remove our instance. Type yes when prompted.

Adding Variables

We’ve proved the basic functionality of the module, but let’s make it more reusable by adding some variables.

  1. First let’s take all the current resources and create variables for them in the variables.tf file.

2. Next in our main.tf let’s reference these variables.

3. Let’s set up the module so we can specify how many instances we would like to launch. Add a variable for instance-count in variables.tf.

4. In main.tf add a reference to the instance-count variable.

5. In ec2.tf add a reference to instance_count and set it equal to 2. Make sure you save all your changes.

6. While in the terraformec2 directory run your terraform fmt , terraform validate , terraform plan , and finally if there are no issues terraform apply . From this point on it will be assumed that you go through this entire process before running terraform apply .

7. Terraform successfully created two EC2 instances, however there is no way to differentiate between the two. Let’s add a way to do just that. Go ahead and destroy these resources.

8. Remove the tag_name variable from the variables.tf file. Here I’ve commented it out but you’ll want to delete it.

9. Update tags to no longer use the variable and instead to use our new Name, which utilized count.index. Indexes start at 0 so that is why we are adding 1.

10. Now when you run a terraform apply you will see the servers with differentiated names.

Do not destroy your resources at this point. In the next few steps we will apply changes to the current state.

Adding Outputs

Having different Names for the servers can be helpful, but it would be nice if we didn’t have to go into the console each time to see information about our servers. We can add outputs to our module file so information is printed in the terminal after a successful apply.

  1. Open the outputs.tf file in the instance directory.
  2. Add the following code to output the public ips and tags for each instance.

3. Having these outputs in the module by itself will not return any outputs for us in the terminal so we will need to create an outputs.tf file in our root directory.

4. Add the following to reference the outputs from the instance module.

5. Now go through your Terraform workflow and do a terraform apply . Notice that when we make changes, it updates our state. Since we are only adding outputs, nothing was changed with our resources. You should now see the desired output after a successful apply.

6. Go ahead and do another terraform destroy .

Push To GitHub

  1. Since we are going to be pushing our code to GitHub, you will want to add a .gitignore file to your root directory to ignore files that you don’t want to push. Here is a link to the one I’ll be using: .gitignore
  2. In the terminal run git status to verify all your files are accounted for.
  3. Next run git add ec2.tf .gitignore instance/ outputs.tf . This will add your files to a staging area.
  4. Next run git commit -m “initial commit” . This will commit your files.
  5. Next run git push origin to push your code changes to your GitHub repository.
  6. Open your GitHub and verify all your files have been added.

Congratulations on creating a custom EC2 Module!

DevOps Engineer | AWS Certified Solutions Architect - Associate | Terraform Associate | Python | Linux