Next steps with Terraform
By: David Calder
Tags: Terraform

The objective

You’ll recall from my last article that the next steps were:

Fix the map constraint error.

Find out how I connect to the EC2 instance.

See if I can install something on the EC2 instance using Terraform.

Fix the map constraint error

Given that the tutorial is a little out of date (I’m using Terraform v0.13.5) and the error says…

Warning: Quoted type constraints are deprecated on variables.tf line 6, in variable "amis": 6: type = "map" Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. To silence this warning, remove the quotes around "map" and write map(string) instead to explicitly indicate that the map elements are strings.

…this is just a syntax that needs to be updated. However, I feel I should read the docs about this to understand variable maps better.

Find out how I connect to the EC2 instance

On the AWS console I find my running EC2 instance in the EC2 dashboard. One of the options is to “Connect”. Here, I find three options: EC2 Instance Connect, which appears to be a dashboard; Session Manager, which says I can’t connect as the SSM agent isn’t installed on the instance; and SSH Client, which says I don’t have an associated key pair. I’m sure I could resolve any one of these using the AWS console, but I want to do it with Terraform. I have a look at the Tutorials again and find a lesson called Provision. This tells me it will show me how to “Use Packer or Cloud-Init to automatically provision SSH keys and a web server onto a Linux VM created by Terraform in AWS”. Sounds like this could also help me achieve my third and final objective. I start the tutorial keeping in mind that the previous tutorial was out of date.

Some of the hurdles I encounter along the way:

Using cloud-init — no issues. I need to find out what cloud-init is though so I have a quick flick through its website. It seems it’s a tool for provisioning Linux instances on cloud infrastructure providers. This causes a slight paradigm shift as I thought that was what Terraform was for. Fortunately, late last night I skimmed over this article and I learnt there is a difference between build (create the instances) and provision (set up the instances for use). Also Terraform goes beyond creating Linux instances (e.g. load balancers, S3 buckets, Lambda functions etc).

Cloud. Innit?!

Using packer…

When I build the packer image I get the error:

==> amazon-ebs: E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_4.4.0-194.226_amd64.deb 404 Not Found [IP: 91.189.88.152 80]

So I go to http://security.ubuntu.com/ubuntu/pool/main/l/linux/ and find the image that most closely matches this: linux-libc-dev_4.4.0–198.230_amd64.deb. I then update it in the …err… I can’t find a reference to it in the images.json or setup.sh files.

I look back at the output and I see that the error follows this command:

amazon-ebs: linux-libc-dev make manpages-dev pkg-config

So this is an error running on the image that is being provisioned. I then spot the following advice:

==> amazon-ebs: E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

A further inspection of the output suggests this is all related to the installation of dependencies for golang-go:

==> amazon-ebs: + sudo apt -y -qq install golang-go

So I add the command sudo apt-get update to script.sh just before this line. And Bingo, it works! However, I think this is a workaround to complete the installation rather than a solution I would want to use for a Production instance. If I was a betting man I would say that the apt repository for golang-backports is out of date:

==> amazon-ebs: + sudo add-apt-repository ppa:longsleep/golang-backports -y

Interestingly though, I find this site which says that you should run apt-get update after adding the apt repository anyway. Perhaps the versions of the dependencies all matched up when the tutorial was first written and you could get away with not updating apt-get at the time. Maybe the base t2.micro’s apt repository has since moved on. Who knows?

Other than that one issue it’s all plain sailing and I complete the tutorial with a simple game of Tetris.

What I’ve learned

Terraform isn’t going to be the only tool I use to manage cloud infrastructure. There are other tools that will help me provision servers. For instance, I have used cloud-init and Packer to provision servers that can run a web app. However, it looks like I will be orchestrating the builds using Terraform.

In conclusion

I have learnt how to pass in variables into Terraform and I’ve learnt how they can be given a type (e.g. string, number) and can also be passed as a collection (e.g. map). I’ve also learnt that because the version of Terraform is still 0.x, the syntax continues to evolve and may not always be backwards compatible.

When learning how to provision servers, I have used Terraform to call the cloud-init service which is installed on the EC2 instance. Terraform passes a script to cloud-init that provisions the server.

Packer is slightly different. This creates, for example, a t2.micro instance, provisions it with a bash script containing normal run-of-the-mill commands, such as apt-get, and then creates an AMI from it. Terraform is then used to build EC2 instances from this AMI.

Next steps: have a go at using Terraform to leverage AWS services