Ansible Approach
In this article, we will use Ansible to launch EC2 instances in different availability zones. The launch_ec2_instances.yml playbook defines three tasks: the first to get the subnet facts, the next to set the subnet IDs and availability zones, and a final task responsible for launching an EC2 instance into two specific subnets.
ssh cloud_user@<PUBLIC_IP_ADDRESS>
Launch EC2 Instances with YAML Playbook using Ansible
Launch in us-east-1
Copy the AMI ID into the image:<******> into the launch_ec2_instances.yml file
touch launch_ec2_instances.yml
vim launch_ec2_instances.yml
- name: Launch EC2 Instances
hosts: localhost
gather_facts: false
vars_files:
- /home/ansible/keys.yml
tasks:
- name: Get Subnet Facts
ec2_vpc_subnet_info:
aws_access_key: "{{ AWS_ACCESS_KEY_ID }}"
aws_secret_key: "{{ AWS_SECRET_ACCESS_KEY }}"
region: us-east-1
register: subnet_facts
- name: Set Subnet IDs and Availability Zones
set_fact:
subnet_ids: "{{ subnet_facts.subnets|map(attribute='id')|list }}"
availability_zones: "{{ subnet_facts.subnets|map(attribute='availability_zone')|list }}"
- name: Launch EC2 Instances in Each Subnet
ec2:
aws_access_key: "{{ AWS_ACCESS_KEY_ID }}"
aws_secret_key: "{{ AWS_SECRET_ACCESS_KEY }}"
ec2_region: us-east-1
instance_type: t2.micro
image: ami-026ebd4cfe2c043b2
vpc_subnet_id: "{{ item }}"
wait: true
loop: "{{ subnet_ids }}"
Execute the Playbook
ansible-playbook launch_ec2_instances.ymlSince I had 2 subnets Two EC2 instances will be created
Terraform Approach
I used terraform data source.
You don’t rebuild the building, and you don’t change its structure you simply read where the walls, doors, and wiring already are so your new room fits perfectly.
In the same way, a data source lets Terraform look at existing infrastructure (like a VPC, subnet, or AMI) and use that information to safely build something new without disturbing what’s already there.
CONFIGURE AWS WITH CLI
installed packages
dnf install -y awscli
USED GITHUB CODESPACES
bash-5.1# cat /etc/os-release
NAME="Rocky Linux"
VERSION="9.3 (Blue Onyx)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="9.3"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Rocky Linux 9.3 (Blue Onyx)"
ANSI_COLOR="0;32"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:rocky:rocky:9::baseos"
HOME_URL="https://rockylinux.org/"
BUG_REPORT_URL="https://bugs.rockylinux.org/"
SUPPORT_END="2032-05-31"
ROCKY_SUPPORT_PRODUCT="Rocky-Linux-9"
ROCKY_SUPPORT_PRODUCT_VERSION="9.3"
REDHAT_SUPPORT_PRODUCT="Rocky Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.3"
main.tf
provider "aws" {
region = "us-east-1"
}
data "aws_vpc" "selected" {
id = "vpc-06110468de1ae8d0f"
}
data "aws_subnet" "selected" {
vpc_id = data.aws_vpc.selected.id
availability_zone = "us-east-1a"
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "state"
values = ["available"]
}
}
resource "aws_instance" "example" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
subnet_id = data.aws_subnet.selected.id
vpc_security_group_ids = [aws_security_group.ec2_sg.id]
tags = {
Name = "terraform-ec2"
}
}
resource "aws_security_group" "ec2_sg" {
name = "terraform-ec2-sg"
description = "Allow SSH"
vpc_id = data.aws_vpc.selected.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
cli
bash-5.1# terraform apply
data.aws_vpc.selected: Reading...
data.aws_ami.amazon_linux: Reading...
data.aws_vpc.selected: Read complete after 0s [id=vpc-06110468de1ae8d0f]
data.aws_subnet.selected: Reading...
data.aws_subnet.selected: Read complete after 0s [id=subnet-00e24cf4555b3ca63]
data.aws_ami.amazon_linux: Read complete after 0s [id=ami-03f9680ef0c07a3d1]
Terraform used the selected providers to generate
the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "example" {
+ ami = "ami-03f9680ef0c07a3d1"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ enable_primary_ipv6 = (known after apply)
+ force_destroy = false
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_group_id = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ region = "us-east-1"
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ spot_instance_request_id = (known after apply)
+ subnet_id = "subnet-00e24cf4555b3ca63"
+ tags = {
+ "Name" = "terraform-ec2"
}
+ tags_all = {
+ "Name" = "terraform-ec2"
}
+ tenancy = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
+ capacity_reservation_specification (known after apply)
+ cpu_options (known after apply)
+ ebs_block_device (known after apply)
+ enclave_options (known after apply)
+ ephemeral_block_device (known after apply)
+ instance_market_options (known after apply)
+ maintenance_options (known after apply)
+ metadata_options (known after apply)
+ network_interface (known after apply)
+ primary_network_interface (known after apply)
+ private_dns_name_options (known after apply)
+ root_block_device (known after apply)
}
# aws_security_group.ec2_sg will be created
+ resource "aws_security_group" "ec2_sg" {
+ arn = (known after apply)
+ description = "Allow SSH"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "-1"
+ security_groups = []
+ self = false
+ to_port = 0
# (1 unchanged attribute hidden)
},
]
+ id = (known after apply)
+ ingress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ from_port = 22
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "tcp"
+ security_groups = []
+ self = false
+ to_port = 22
# (1 unchanged attribute hidden)
},
]
+ name = "terraform-ec2-sg"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ region = "us-east-1"
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-06110468de1ae8d0f"
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_security_group.ec2_sg: Creating...
aws_security_group.ec2_sg: Creation complete after 1s [id=sg-09d80c75597b8624d]
aws_instance.example: Creating...
aws_instance.example: Still creating... [00m10s elapsed]
aws_instance.example: Still creating... [00m20s elapsed]
aws_instance.example: Still creating... [00m30s elapsed]
aws_instance.example: Creation complete after 32s [id=i-07e8658ca12915abf]
Fetch VPC-ID
bash-5.1# aws ec2 describe-vpcs
{
"Vpcs": [
{
"OwnerId": "080763862064",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0c2a3ddbd5c6aa364",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false,
"Tags": [
{
"Key": "aws:cloudformation:logical-id",
"Value": "VPC"
},
{
"Key": "Name",
"Value": "LinuxAcademy"
},
{
"Key": "aws:cloudformation:stack-id",
"Value": "arn:aws:cloudformation:us-east-1:080763862064:stack/cfst-4150-d757e6fc0ddc7949940f7ec1f4710dd8b2bdf1fecd5f43946c84cb1649b24e2a/1d83daf0-dc6a-11f0-8dbd-123b45f64b33"
},
{
"Key": "Network",
"Value": "VPC"
},
{
"Key": "Application",
"Value": "cfst-4150-d757e6fc0ddc7949940f7ec1f4710dd8b2bdf1fecd5f43946c84cb1649b24e2a"
},
{
"Key": "UserId",
"Value": "24701544"
},
{
"Key": "aws:cloudformation:stack-name",
"Value": "cfst-4150-d757e6fc0ddc7949940f7ec1f4710dd8b2bdf1fecd5f43946c84cb1649b24e2a"
}
],
"BlockPublicAccessStates": {
"InternetGatewayBlockMode": "off"
},
"VpcId": "vpc-0b76c79b6a607cb38",
"State": "available",
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-079e42f1be6dd68a4"
}
]
}
fetch subnet
{
"Key": "aws:cloudformation:stack-name",
"Value": "cfst-4150-cf678142718819a066a9339ffe1e112471fc9e300512621571a366cc45a4129d"
},
{
"Key": "Application",
"Value": "cfst-4150-cf678142718819a066a9339ffe1e112471fc9e300512621571a366cc45a4129d"
},
{
"Key": "Network",
"Value": "Public2"
}
],
"SubnetArn": "arn:aws:ec2:us-east-1:143108796152:subnet/subnet-0dcaed3327867a837",
"EnableDns64": false,
"Ipv6Native": false,
"PrivateDnsNameOptionsOnLaunch": {
"HostnameType": "ip-name",
"EnableResourceNameDnsARecord": false,
"EnableResourceNameDnsAAAARecord": false
},
"BlockPublicAccessStates": {
"InternetGatewayBlockMode": "off"
},
"SubnetId": "subnet-0dcaed3327867a837",
"State": "available",
"VpcId": "vpc-06110468de1ae8d0f",
"CidrBlock": "10.0.2.0/24",
"AvailableIpAddressCount": 251,
"AvailabilityZone": "us-east-1b",
"DefaultForAz": false,
"MapPublicIpOnLaunch": false
}
]
Successfully launched EC2 instance with terraform approach
References
- Pluralsight Hands-on Lab – AWS / Cloud Infrastructure Lab https://app.pluralsight.com/hands-on/labs/4dd1d104-d54e-4351-bc6c-bc8be053ec42





Top comments (0)