This Learning Path uses Terraform Cloud to automate creation of Arm instances. Reader may wish to also see:
You should have the prerequisite tools installed before starting the Learning Path.
Any computer which has the required tools installed can be used for this section. The computer can be your desktop, laptop, or a virtual machine with the required tools.
You will need an AWS account to complete this Learning Path. Create an account if you don’t have one. See the Creating an AWS account documentation for full instructions.
Before you begin, you will also need:
The instructions to create these keys are below.
Generate the SSH key-pair (public key, private key) using ssh-keygen
to use for AWS EC2 access. To generate the key-pair, follow this
guide
.
If you already have an SSH key-pair present in the ~/.ssh
directory, you can skip this step.
The installation of Terraform on your desktop or laptop needs to communicate with AWS. Thus, Terraform needs to be authenticated.
For authentication, generate access keys (access key ID and secret access key). These access keys are used by Terraform for making programmatic calls to AWS via the AWS CLI.
To generate and configure the Access key ID and Secret access key, follow this guide .
Terraform files are created with a .tf extension.
Start by creating a main.tf
file in your desired directory.
touch main.tf
Tell Terraform
which cloud provider to connect to, AWS for this example. Also, specify an AWS region for the connection.
Add the code below to the main.tf
file:
provider "aws" {
region = "us-east-2"
}
After defining the provider, define your resources. Resources are infrastructure objects that will be provisioned for your instance.
Here is the basic syntax for defining a resource:
resource "<PROVIDER>_<TYPE>" "<NAME>" {
[CONFIGS …]
}
Where:
PROVIDER
is the cloud provider name, aws
in this caseTYPE
is the type of resource to be declaredNAME
is an optional, local name used to reference this resourceCONFIGS
are configuration arguments, declared in a key-value formatFor additional information on resource blocks and their syntax, see the Terraform Documentation .
You will provision an AWS EC2 instance resource, which requires you to find and declare the following configuration arguments:
Alt+S
) for EC2
, or via Services > Compute > EC2.Choose an AMI that suits your compute needs by selecting an AMI category (Quickstart AMIs, AWS Marketplace AMIs, etc.) and utilizing the filters and search options.
For now, find a Ubuntu AMI (e.g., Ubuntu Server 22.04 LTS
) from Quickstart AMIs. Be sure to filter by 64-bit (Arm) Architecture.
Copy or make note of the AMI ID for 64-bit (Arm), as it will be used for your ami
argument.
A list of all AWS instance types can be
viewed here
. As a general rule, instances with a g
at the end of their name (e.g., M7g
, M6g
, T4g
) are Arm-based
Graviton
instances.
For now, select the T4g tab to view a list of Amazon EC2 T4g instance sizes.
For now, use a small, non-production level instance size, such as t4g.nano. Copy or make note of this Instance Size name, as it will be used for your instance_type
argument.
Shown below is the aws_instance
resource block configuration using the arguments found above:
resource "aws_instance" "ec2_example" {
ami = "ami-0a0c8eebcdd6dcbd0"
instance_type = "t4g.nano"
}
To complete the main.tf
file, we will need to include additional arguments to the aws_instance
resource and define additional resources.
Shown below is an example of a complete main.tf
file:
provider "aws" {
region = "us-east-2"
}
resource "aws_instance" "ec2_example" {
ami = "ami-0a0c8eebcdd6dcbd0"
instance_type = "t4g.nano"
key_name = aws_key_pair.deployer.key_name
vpc_security_group_ids = [aws_security_group.main.id]
provisioner "remote-exec" {
inline = [
"touch hello.txt",
"echo helloworld remote provisioner >> hello.txt",
]
}
provisioner "local-exec" {
command = "echo ${self.private_ip} >> private_ips.txt && echo ${self.public_ip} >> public_ips.txt && echo ${self.public_dns} >> public_ips.txt"
}
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
timeout = "4m"
}
}
resource "aws_security_group" "main" {
egress = [
{
cidr_blocks = ["0.0.0.0/0", ]
description = ""
from_port = 0
ipv6_cidr_blocks = []
prefix_list_ids = []
protocol = "-1"
security_groups = []
self = false
to_port = 0
}
]
ingress = [
{
cidr_blocks = ["0.0.0.0/0", ]
description = ""
from_port = 22
ipv6_cidr_blocks = []
prefix_list_ids = []
protocol = "tcp"
security_groups = []
self = false
to_port = 22
}
]
}
resource "aws_key_pair" "deployer" {
key_name = "id_rsa"
public_key = file("~/.ssh/id_rsa.pub")
}
Run terraform init
to initialize the Terraform deployment. This command is responsible for downloading all required dependencies for the provider AWS.
terraform init
The output should be similar to what is shown below:
Initializing the backend...
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Run terraform plan
to create and preview an execution plan before applying it to your cloud infrastructure.
terraform plan -out main.tfplan
A long output of resources to be created will be printed. The bottom of the output should be similar to:
Plan: 1 to add, 0 to change, 0 to destroy.
────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: main.tfplan
The terraform plan command is optional. You can directly run the terraform apply command, but it is always better to confirm the resources that will be created.
Run terraform apply
to apply the execution plan to your cloud infrastructure. The command below creates all required infrastructure.
terraform apply main.tfplan
If prompted to confirm if you want to create AWS resources, answer yes
.
The bottom of the output should be similar to:
aws_instance.ec2_example: Creation complete after 31s [id=i-000a33ed1fe30b5df]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Make note of the instance id
(e.g., i-000a33ed1fe30b5df
) to identify your instance. This is particularly useful when having multiple instances.
Verify the instance setup on the AWS Console.
Go to EC2 -> Instances and you should see an instance with the same Instance ID as your output id
above. Its Instance state should be Running
.
Click on the Instance ID to display the Instance Summary view which includes more details about your instance.
Connect to your EC2 Instance with your preferred SSH client. You will be using the private key created through
ssh-keygen
, located at ~/.ssh/id_rsa
.
In the Instance summary
view, click Connect
, and select the SSH client
tab to see the commands used to launch the native SSH client.
For example, if using a ubuntu
AMI:
ssh -i <private_key> ubuntu@<public_ip_address>
Replace <private_key>
with the private key on your local machine and <public_ip_address>
with the public IP of the target VM.
Terminal applications such as PuTTY , MobaXterm and similar can be used.
Different Linux distributions have different default usernames you can use to connect.
Default usernames for AMIs are listed in a table. Find your operating system and see the default username you should use to connect.
Once connected, you are now ready to use your instance.
Run terraform destroy
to delete all resources created through Terraform, including resource groups, virtual networks, and all other resources.
terraform destroy
A long output of resources to destroy will be printed. If prompted to confirm if you want to destroy all resources, answer yes
.
The bottom of the output should be similar to:
Destroy complete! Resources: 1 destroyed.
Use the uname utility to verify that you are using an Arm-based server. For example:
uname -m
will identify the host machine as aarch64
.
Install the gcc
compiler. If you are using Ubuntu
, use the following commands. If not, refer to the
GNU compiler install guide
:
sudo apt-get update
sudo apt install -y gcc
Using a text editor of your choice, create a file named hello.c
with the contents below:
#include <stdio.h>
int main(){
printf("hello world\n");
return 0;
}
Build and run the application:
gcc hello.c -o hello
./hello
The output is shown below:
hello world