In this post, we'll discuss using Terraform to deploy Arm EC2 instances on AWS.
Amazon EC2 A1 Instances were announced in November of 2018. These instances are based on the Arm Graviton processor which offer significant costs savings. If your workload is architecture agnostic like discussed in Architecture Agnostic Build Systems, you could easily take advantage of these lower cost instances. Below we will walk through the deployment of a few A1 instances using Terraform.
Terraform is an open source infrastructure management tool. There are many benefits to using Terraform, but one of the benefits is that it does not lock you into any specific cloud provider. It can be used to deploy infrastructure on AWS, Azure, etc. As we will see, it's also easy to get started with.
Any machine can be used as the infrastructure bootstrap machine. In our case, we will use a MacchiatoBin to deploy our A1 instances. The setup of a MacchiatoBin was discussed in Configuring The MacchiatoBin For Kubernetes and Swarm. Currently, the Terraform Arm release binary only comes as a 32-bit executable. However, given that the project is open source, a 64-bit binary can be compiled. Further, there is already a github PR to address this issue in the long term, so this is a minor issue.
Keep in mind that deploying these instances will incur charges on your AWS account. Very small charges, but charges nonetheless.
You should have an AWS account, and awscli installed on your machine. Terraform uses awscli to talk to the AWS servers to setup the infrastructure. awscli installation instructions can be found on the AWS site. After installation, be sure to configure your credentials as described in the awscli configuration instructions. The main things that need to be set up are your access key and you secret access key. These allow Terraform (via awscli) to authenticate your AWS account.
awscli
awscli)
Download the release for your OS and architecture from the releases page, and make sure your PATH variable points to the location of the binary. Run the following command to initialize Terraform.
PATH
terraform init
Let's create a Terraform Configuration called myA1Deployment.tf.
myA1Deployment.tf
variable "instances" { description = "A list of EC2 instance types to run." type = list(string) default = ["a1.medium", "a1.large", "a1.xlarge"] } provider "aws" { region = "us-east-2" } resource "aws_instance" "myA1Deployment" { count = 3 ami = "ami-0f2057f28f0a44d06" instance_type = "${element(var.instances, count.index)}" tags = { Name = "My-A1-Instance-${count.index}" } key_name = "A1DEMO" }
The above configuration file contains three main blocks. Let's take a closer look at each of them.
Input Variable Block
The first block defines an input variable called instances. There are three arguments within this variable. The first argument is a description which tells us that this variable holds a list of EC2 instance types to run. The second is a type argument which defines the data type; in our case, it's a list of strings. The last argument is a default list of instance types to assign to the variable. If a list is not provided by the user when calling Terraform, this default list will be used. Our default list shows instance types of a1.medium, a1.large, and a1.xlarge.
instances
description
type
default
Provider Block
The second block defines a provider. A provider tells Terraform which cloud provider API to use for setting up our infrastructure. In our case, the provider is set to AWS. There are many arguments that can be used within this block, but the only required one is the AWS region. In our configuration file, we've set it to us-east-2.
region
Resource Block
The third block describes a resource. Here we define an aws_instance resource named myA1Deployment. This tells Terraform that we want to deploy AWS EC2 instances. The first argument is count, which is a meta-argument of the resource block. count describes how many copies of this resource (i.e. EC2 instances) we would like to deploy. In our configuration, count is set to 3. Under the hood, using count tells Terraform to run a loop count (3) times in order to create the copies of the resource (aws_instance). Further, count exposes an attribute called count.index which can be used within distinct iterations of this loop. In the first iteration, count.index is 0, in the second it's 1, and in the third it's 2. This works similarly to a basic loop in any programming language. Later, we will see how count.index is used within the resource block definition.
myA1Deployment
count
count.index
The next argument is the Amazon Machine Image (ami) to use. It is set to ami-0f2057f28f0a44d06, this is the AMI ID for a 64-bit Arm Ubuntu 18.04 image. The picture below shows this ID next to the Ubuntu AMI name in the EC2 instance wizard.
ami
After the ami argument, we have the instance_type argument. Here we see something a little more interesting. We call a Terraform function called element. This allows us to access an element within our instances list. We use count.index to select an element from the instances list on each loop iteration. Assuming we are using the default instances list, this line produces 3 instances; each of type a1.medium, a1.large, and a1.xlarge. This corresponds to indices 0 to 2 of the instances list.
instance_type
After the instance_type, we have a tag called Name. Here we use count.index to give each instance a unique name by appending the count index to the end of the Name tag of each instance. This means we should expect our instances to take on the names My-A1-Instance-0 (a1.medium), My-A1-Instance-1 (a1.large), and My-A1-Instance-2 (a1.xlarge).
Name
Last, we have key_name, this is the name of a public-key pair for connecting to the instances without a password. This can be created ahead of time on your AWS account, or created within the Terraform configuration file. We will use this key to SSH into our instances once they are created. Our pre-created key is called A1DEMO. Information on how to create and use these keys can be found in the EC2 documentation.
key_name
A1DEMO
Now that we understand our configuration file, let's deploy the instances. Run the command terraform apply within the directory the myA1Deployment.tf file is located. You will need to type yes to confirm the deployment. If you see a NoCredentialProviders error. It means you didn't setup your awscli credentials properly. If this is the case, review the awscli configuration instructions again.
terraform apply
yes
NoCredentialProviders
Now we can switch over to the instance viewer on the EC2 page and see our instances.
As expected, we see 3 instances. We can also SSH into any of these instances provided that we have the private key (A1DEMO).
The instances can be removed by running the terraform destroy command.
terraform destroy
At this point, you can add to the Terraform configuration file to run a provisioner to manage the configuration of the instances.
As shown above, Terraform can be used to deploy A1 instances to your cloud infrastructure. Other than selecting the A1 instance type, nothing different or special needs to be done in order to run A1 instances on AWS. Given the lower costs associated with running A1 instances, we encourage DevOps teams to explore running at least part of their workloads on A1 instances. There is the potential for significant cost savings with minimal changes to your Terraform configuration files.
[CTAToken URL = "https://aws.amazon.com/ec2/instance-types/a1" target="_blank" text="Amazon EC2 A1 Instances" class ="green"]