Building a Custom EC2 Module with an Amazon Machine Image Using Terraform

In Terraform, modules are blocks containing multiple resources being used together. Modules allow you to feed information and other “child” modules into a “parent” module, though “parent” modules cannot be fed into “child” modules. In this exercise, we will make a custom module so that a standardized EC2 instance with an Amazon Linux 2 AMI can be easily reproduced and adjusted in the future.

Using modules in Terraform is great, but one should be cautious of over-using modules because it can be challenging to understand and maintain an unorganized or redundant family of modules.

For this exercise, I needed:

  • Terraform
  • IDE of choice (I used Atom)

STEP 1: Fork & Clone Repo

Image 1: Forking “create ec2” repo (circled in Yellow)

Then in Terminal I confirmed that I was in my home directory, and I used the command git clone to clone the forked repo (Image 2).

Image 2: Cloning the forked repo

Then I confirmed that I had a new working directory named “terraformec2” by changing into that directory (Image 3).

Image 3: Changing into new directory “terraformec2”

STEP 2: Module Setup

Image 4: Setting up the environment

We then needed to transfer the resource and provider section of to our new of our instance module, and so I did so in Atom as seen in Image 5 & 6.

Image 5: Copying resource and provider from “”
Image 6: Pasting resource and provider into “”

I then copied the instance resource from and pasted it in to be the provider (Image 7).

Image 7: Pasting the instance resource into “” from “”

I then cleared the information in, and replaced it with , as it will be our module file intaking code from the other files.

Image 8: Re-writing “” to source from the other files

I then changed directories back one by using the command cd ../. Once in the terraformec2 directory, I ran the following respectively to ensure my EC2 Instance was being created: terraform init, terraform fmt, terraform validate, terraform plan, terraform apply. Our successful result after typing “yes” to confirm terraform apply is shown in Image 9.

Image 9: The successful result of terraform apply

I confirmed in the my AWS Console that the EC2 instance had been created in region us-west-2 (Image 10).

Image 10: Confirming in the AWS Console the creation of the EC2 instance

We no longer needed this instance (it was just a test), so I then ran the command terraform destroy and typed “yes” to confirm the action (Image 11).

Image 11: Terraform destroy

At this point we had successfully set up the module, but as it stands at this point in the article, it is just a simple EC2 module offering no variability.

STEP 3: Variables

First I took the three original resources & made appropriate variables for each in (Image 12).

Image 12: Making appropriate variables in “” for our original three resources

I then referenced these variables in, (Image 13) where formly had the fixed values set.

Image 13: Referencing appropriate variables

I then added a variable to so that in the future we can specify how many instances we want to create (Image 14).

Image 14: Adding Instance Count to “”

Then in I added a line for Instance Count and made it equal to 2 (Image 15).

Image 15: Adding Instance Count to “”

Then I made an adjustment. I was concerned that, when launching multiple EC2 instances, it would be difficult to differentiate between instances. Therefore in I wrote Line 6 so that the Instance Count would be indicated in the name. Note I also wrote +1 because the instance count starts at zero (Image 16).

Image 16: Clarifying Instance Count in the name in “”

STEP 4: Outputs

I elected to clarify Public IPs and EC2 Tags by writing in as seen in Image 17.

Image 17: Writing “”

I then wrote the desired outputs in a new in /terraformec2 to go along with the module (Image 18).

Image 18: Writing “”

I now wanted to pause and ensure the module was working. When I ran terraform validate, I discovered that my count index was invalid (Image 19).

Image 19: Error due to Line 6 of having no context

I then resolved this issue by adding Line 4 to as seen in Image 20.

Image 20

I then re-ran terraform validate, and this time everything was valid (Image 21).

Image 21: Valid configuration

I then ran terraform apply and confirmed “yes.” Image 22 shows that the resources were created and our outputs from were printed.

Image 22: Successful apply with expected output

I then ran terraform destroy again, so as to avoid running these resources, accruing costs, etc.

STEP 5: Github

To do so I first made a .gitignore file in the root directory so as to ignore files that I didn’t want pushed (Image 23).

Image 23: Writing .gitignore

To ensure all files were set, I ran the command git status (Image 24).

Image 24: git status

To stage my files I ran the following command as seen in Image 25 to include all files that weren’t tracked or staged were ready.

git add .DS_Store .gitignore .terraform.lock.hcl instance/

Image 25: git add

I then ran the command git commit -m “initial commit” to commit my files (Image 26).

Image 26: git commit

I then used the command git push origin to push the files to my Github (Image 27).

Image 27: git push

I then confirmed in my Github that the custom EC2 module and all relevant files were there, and indeed they were (Image 28).

Image 28: Custom EC2 Module successfully pushed to my Github

Thanks for reading.

Credit: Level Up In Tech as was credited in the body of the article.

Cloud, DevOps, Blockchain.