This has become a habit so far to explore different ways of automated provisioning for each cloud provider. This time, I will try Terraform on AWS and reproduce the same deployment I have completed on Oracle Cloud, and as usual we won’t just deploy an instance but also configure a website linked to its public IP. I’ll end this post with some notes on OCI/AWS differences.
Note: I have done a similar task with my bash scripts and AWSCLI which was very helpful to understand the logic behind each IAC interaction during the resource creation (More details >here).
Overview and Concepts
The following illustration shows the layers involved between your workstation an Oracle cloud infrastructure while running the terraform commands along with the instance attributes we will be provisioning.
- Files are merged in alphabetical order but resource definition order doesn't matter (subfolders are not read).
- Common configurations have 3 type of tf files and a statefile.
- 1- main.tf: terraform declaration code (configuration) . The file name can be anything you choose
2- variables.tf: Resource variables needed for the deploy
3- outputs.tf: displays the resources detail at the end of the deploy
4- terraform.tfstate: keeps track of the state of the stack(resources) after each terraform apply run
Example for a VPC >>
1- Create a shell resource declaration for the vpc ina file called vpc.tf
2- Get the id of the vpc resource from your AWS Console
3- Run the Terraform import then run Terraform show to extract the vpc’s full declaration from aws in the same file (vpc.tf)
4- Now you can remove the id attribute with all non required attributes to create a vpc resource (Do that for each resource)
If you want to import all the existing resources in your account in bulk mode (not one by one) there is a tool called Terraforming, which can import both code and state from your AWS account automatically.
Terraform lab content: I have deliberately split this lab in 2:
- VPC Deployment: To grasp the basics of a single resource deployment.
- Instance Deployment: includes the instance provisioning (with above vpc) with a hosted web sever.
Linux: Download, unzip and move the binary to the local bin directory
Once installed run the version command to validate your installation
To authenticate with your aws account, Terraform will need to provide both access_key_id & secret_access_key . This can be done either by sharing the authentication parameters with aws-cli or by Including the access_key and key_id within the Terraform config (i.e. variables.tf)
- - I will assume that either of the two below authentication options are present/configured in your workstation:
- AWSCLI default profile configured with your aws credentials (Access keys). Refer to my Blog post for more details
Or AWS credentials imbedded in provider specific config section on one of your terraform files (See vpc.tf)
II. Clone the repository
- Pick an area that is close to your aws-terraform directory on your file system and issue the following command.
terraform-provider-aws/create-vpc/To grasp how we deploy a single VPC.
terraform-provider-aws/launch-instance/For the final instance deploy.
III. Provider setup
INSTALL AND SETUP THE AWS PROVIDER
- Cd Into the subdirectory
terraform-provider-aws/create-vpcwhere our configuration resides (i.e vpc)
create-vpcdirectory. Here, only
*.tffiles matter (click to see content)
IV. Partial Deployment
DEPLOY A SIMPLE VPC
- Once the authentication configured (access_key_id/secrete set) , we can run
terraform plancommand to create an execution plan (quick dry run to check the desired state/actions).
- The output being too verbose I deliberately kept only relevant attributes for the VPC resource plan
- Next, we can finally run
terraform deployto apply the changes required to create our VPC (listed in the plan)
Note: We’ll now destroy the vpc as the next instance deploy contains the same vpc specs.
V. Full deployment (Instance)
- Sweet, After our small test let's launch a full instance from scratch.
- First we need to switch to the second directory
Here's its content:
Note: As you can see we have 2 additional files and one Subfolder. compute.tf is where the compute instance and all its attributes are declared. All the other .tf files come from my vpc example with some additions for variables.tf and output.tf
public_key = file("~/id_rsa_aws.pub") } ## Change me
LAUNCH THE INSTANCE
- Once in “
launch-instance”directory, you can run the plan command to validate the 10 resources required to launch the ec2 instance (end-state). The output has been truncated to reduce verbosity
- Once the instance is provisioned, juts copy the public IP address(18.104.22.168) in your browser and Voila!
- Here I just embedded a video link into the index page but you can adapt the cloud-init file to your own liking (with a new content in the write_file section.
- You can also tear down this configuration by simply running terraform destroy from the same directory
- You can fetch any of the specified attributes in outputs.tf using terraform output command i.e:
Although terraform is a declarative language, there are still myriads of functions you can use to process strings/number /lists/mappings etc. In my case I had to do some tests to get the right syntax for outputting the ingress SG rules:
- Unlike OCI, most of aws resources don’t have a display-name attribute, hence a tag is necessary each time you want to create a resource in AWS
- If you are used to DNS-labels for Subnet/VCNs in OCI, this is not something you’ll find in AWS
- There is no direct way of setting the instance hostname like in OCI’s hostname_label attribute, you will have to do it via user-data
- Bummer: I wish AWS had a data source for aws_key_pair as we can’t check if a key pair exists while launching an instance. This is a drawback for cases where a dev team needs to share a key. The only option is to give it a different keyname for each deployment even if the key is the same, which will generate a lot of unnecessary duplicates .
- We have demonstrated in this tutorial how to quickly deploy an instance using terraform in AWS and leverage Cloud-init to bootstrap an instance into a webserver.
- Remember that all used attributes in this exercise can be modified in the
- Improvement: In my next blog post, I will look to improve the vpc.tf code to leverage for_each function on map collections to make security group rules creation dynamic and conditional.
Differences between OCI/AWS & things I wish AWS provider had
Thank you for reading!