Terraform: Creating a very basic EC2 module using “aws_ami” data source — 1
Tags: aws, terraform, ec2
Published: 2022-10-04 17:28:10


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lojs39rlnjjqubs2p1h8.png)


My organization wants to use a template to create **a very basic non-fuctional re-usable EC2 instance** module with an amazon linux 2 ami ID. A simple file — **ec2.tf** has been provided to me. I need to modify this simple file into a re-usable module for the other team members.

In the my next article, I plan to modify this project making the EC2 module fully functionable by adding more resources like VPC and its networking components so that you can SSH into it.


## **Requirements:**

1. Fork and locally clone a GitHub repository with an **ec2.tf template** as a starting point to create the EC2 module: [https://github.com/LevelUpInTech/terraformec2](https://github.com/LevelUpInTech/terraformec2.git)
2. Create a custom module for EC2 out of the resource block that you can use as repeatable infrastructure.
3. Push the new created module and the ec2.tf file to your Github repository.

For building this EC2 module, I have used a [data source for pulling in an AMI ID](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) instead of a hard-coded value. I have spent so much time to make this work, and after many, many attempts, I succeeded! I have also used [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) for this purpose.

## **Modules:**

A module is nothing but a collection of Terraform files in a single folder. You can group many resources into a module to be used over and over again.

In short, modules are the key ingredient to writing reusable, maintainable, and testable Terraform code, especially complex configurations making them easier to navigate, read, understand, and make changes.

I have used [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (use the navigation to the left to read about the available resources), [Derek Morgan’s course](https://learn.hashicorp.com/tutorials/terraform/module) and [Morethancertified course](https://courses.morethancertified.com/courses/1390185/lectures/31955645) for this project.

Follow the basic Terraform workflow: write, plan, deploy.

## **Pre-Requisites:**

- Access to AWS Console with an AWS Account (not root account).

- Cloud9 IDE

- GitHub account

- Install Terraform

---

_**Let’s begin!**_

Fork and locally clone a GitHub repository
Navigate to [https://github.com/LevelUpInTech/terraformec2](https://github.com/LevelUpInTech/terraformec2.git) and click the Fork button in the top right corner of the browser.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ha9rnmgs3e412jmug6fh.png)


Now, you can see a new repository in your GitHub.

Next, I will clone the repository in my IDE, I am using Cloud9:

- Open up the cloned repository
- Click on “Code” and copy the “HTTPS” URL


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kf82gztraibr3l40f7h.png)

Open up Cloud9 IDE terminal and clone the forked repository

```

git clone https://github.com/LevelUpInTech/terraformec2.git


```


Now you should see a new directory under your current working directory named **terraformec2**.

Change the name “**terraformec2**” to “**basic_ec2_module_1**”.

Change your **working directory** to **basic_ec2_module_1**.

**`cd basic_ec2_module_1`**

## **Start working on the Module**

I am going to implement this using a modular approach with [Terraform](https://www.terraform.io/) modules.

To get started, let’s create the following organizational structure as shown below.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9brinpwwnyv768hp85bx.png)


This infra has only 1 module “**ec2_instance**”

In the ec2_instance directory create **main.tf**, **outputs.tf**, and **variables.tf** files.

The **ec2.tf** file has a provider and a resource section.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dyl8y21osedg5kek0iwi.png)


- **main.tf** :

Cut and paste the resource information from ec2.tf into this file. Make neccessary changes to the resources section. I have used a [data source for pulling in an AMI ID](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) instead of a hard-coded value. I have spent so much time to make this work, and after many, many attempts, I succeeded! I have also used [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) for this purpose.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yn1y31v0haweei4xshk5.png)


```
# --- Terraform_projects/basic_ec2_module_1/ec2_instance/main.tf ---
# --- used this link to get information for aws_ami ---
# --- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance ---

data "aws_ami" "linux" {
   most_recent = true
   owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}



resource "aws_instance" "my_ec2" {
  ami                = data.aws_ami.linux.id
  instance_type      = var.instance_type

  tags = {
    Name = "my_ec2"
  }
}
```

- **variables.tf**:

create variables so that they are not hard coded in the parent module


```
# --- Terraform_projects/basic_ec2_module_1/ec2_instance/variables.tf ---

variable "aws_region" {
    type     = string
    default  = "us-east-1"
}



variable "instance_type" {
    type     = string
    default  = "t2.micro"
}
```

- **outputs.tf**:

As the name indicates, after executing Terraform apply, it outputs — the public ip and ec2 name tag values.


```
# --- Terraform_projects/basic_ec2_module_1/ec2_instance/outputs.tf ---

output "ec2_public_ip" {
  value = aws_instance.my_ec2.public_ip
}

output "my_ec2_name" {
  value = aws_instance.my_ec2.tags_all.Name
}
```

- **providers.tf** : 

cut and paste the Provider information from ec2.tf into this file.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qg79xcrwlcldnlfpo4lm.png)

Make changes in the **providers.tf** file to get the latest version for Terraform. Get the variables from the variables.tf file so that they are not hard-coded and reference them in the main.tf.


```
# --- Terraform_projects/basic_ec2_module_1/providers.tf ---

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.23"
    }
  }
  required_version = ">= 1.2.0"
}

provider "aws" {
  region = var.aws_region
}
```

- **ec2.tf**:

Now make this file to reference **instance module —** **ec2_instance**.

```
# --- Terraform_projects/basic_ec2_module_1/ec2.tf ---

module "ec2_instance" {
  source = "./ec2_instance"
}
```

- **outputs.tf**: 

After executing Terraform apply, the values for public ip and ec2 name tag will be displayed.

```
# --- Terraform_projects/basic_ec2_module_1/outputs.tf ---

output "ec2_public_ip" {
  value = module.ec2_instance.ec2_public_ip
}

output "my_ec2_name" {
  value = module.ec2_instance.my_ec2_name
}
```

**Now run these Terraform commands in the following order:**

Run **`terraform init`** to initialize Terraform.
Run **`terraform fmt`** to format the code.
Run **`terraform validate`** to check for any syntax errors.
Run **`terraform plan`** to see what resources will be created.
Run **`terraform apply`** and type **`yes`** when prompted.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibtufw2ghpbu3wvuu1v4.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mc1pf9u5am08lbsw3cql.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wpx0kw8ldlq9g0numscu.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyveuldqarlhi5y9njp5.png)


**To check ec2 instance from AWS Console**

Login to your AWS account and navigate to the us-east-1 region > EC2 > Instances to see if our instance was created.

**Push To GitHub**

Run these Git commands in the following order from the Cloud9 IDE terminal from the directory **Terraform_projects/basic_ec2_module_1** — which has all the files for this project.

Run **`git status`** to verify all your files are accounted for.
Run **`git add ec2_instance`** This will add your files to a staging area.
Run **`git add ec2.tf`** This will add your files to a staging area.
Run **`git add outputs.tf`** This will add your files to a staging area.
Run **`git add providers.tf`** This will add your files to a staging area.
Run **`git commit -m “initial commit”`** . This will commit your files.
run **`git push origin`** to push your code changes to your GitHub repository.


Open the [GitHub repository](https://github.com/awsmine/Terraform_projects/tree/main/basic_ec2_module_1) to verify all the files that have been added.

Run a **`terraform destroy`** from the Cloud9 IDE terminal to remove our instance. Type yes when prompted.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u377220s718w8sip5ipb.png)


Thanks for reading ! More in my next article…