Unleashing Automation: Spinning Up EC2 Instances with the Dynamic Duo of Terraform and Ansible ๐Ÿš€

ยท

4 min read

๐Ÿ“” Introduction

In this example we are going to create an EC2 instance and install docker inside, using Terraform to deploy the instance and ansible to install docker and configure everything

๐Ÿ“š Prerequisites

๐Ÿ““ Steps

๐Ÿ“ Step 0 โ€” Create a repository from this one https://github.com/jd-apprentice/base-web-server

With this step, we are going to get the repository and start working locally

๐Ÿ“ Step 1 โ€” Create a ssh-key

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

REMEMBER TO NOT SHARE YOUR PRIVATE KEY

The program will ask you a few things like a name for the key, if you leave it blank with this algorithm it will be called something like id_rsa and id_rsa.pub.

This will create a ssh-key to when we have our instance we associate that key and connect to the server with it.

In case you want to read a more detailed example of how to create and what are ssh-key I'll leave you this post - https://www.atlassian.com/git/tutorials/git-ssh

๐Ÿ“ Step 2 โ€” Obtain your variables from AWS

In this step is up to you how are you going to handle your sensitive variables from AWS since you can just use root and that's all but it is not a recommended practice since is insecure, you should rather use IAM and create a user with the necessary permissions to create the resources in your account.

If you are going for the root route you go into Security Credentials then Access keys and create a new one, then copy the values.

If you want the secure way or at least not the worst one you can create a new user assign permissions and go into Access keys again to retrieve your values

Here is the detailed example they give - https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html?icmpid=docs_iam_console#Using_CreateAccessKey

Now at this point, we should have our ssh-key and the AWS environment variables let's go into our project.

๐Ÿ“ Step 3 โ€” Populate the fields

In our local project, we are going to need to create a secret.tfvars inside the terraform folder is used to store sensitive information which in this case is going to be the AWS keys.

Inside is going to look something like this

access_key = "your-key"
secret_key = "your-key"
ssh_key    = "path/to/public/ssh-key"

Also, we are going to populate the Makefile with the path to our private ssh-key

## Build and deploy the infrastructure
## Usage: make

deploy: apply all playbook

## For development and testing purposes

BOOK2USE = prepare.yml # name of the playbook to use
PRIVATE_KEY_PATH = ~/.ssh/id_rsa # path to your private key

The line where it says PRIVATE_KEY_PATH I'm going to write ~/.ssh/id_rsa since that is the key I've created with the example above.

๐Ÿ“ Step 4 โ€” Run the project

At this point, we can initialize our infrastructure with make init then if everything is okay we can run make.

And what will make do?

  • It will run the first command at the Makefile which is deploy: apply all playbook

  • This will at first run

      apply:
          cd terraform && terraform plan -var-file="secret.tfvars"
    

    It will apply the infrastructure to AWS (check resources.tf to see what is going to do.

  • Then is going to run all

all: terraform_output update_hosts clean_temp

terraform_output:
    cd terraform && terraform output instance_public_ip > $(TEMP_FILE)

update_hosts:
    echo "[aws_server]" > $(OUTPUT_FILE)
    cat ./terraform/$(TEMP_FILE) >> $(OUTPUT_FILE)
    echo "" >> $(OUTPUT_FILE)
    echo "[aws_server:vars]" >> $(OUTPUT_FILE)
    echo "ansible_ssh_user=ec2-user" >> $(OUTPUT_FILE)
    echo "ansible_ssh_private_key_file=$(PRIVATE_KEY_PATH)" >> $(OUTPUT_FILE)

clean_temp:
    rm ./terraform/$(TEMP_FILE)

At first it will output the instance public ip of the EC2 instance and save it into a temporary file called temp_ip.txt

output "instance_public_ip" {
  value = aws_instance.example_webserver.public_ip
}

Then we will populate the ansible/inventory/host file which contains information for ansible to connect to the instance and run the playbook

At the end, we will execute the playbook to access the instance and perform updates. Finally, we will install Docker.

๐ŸŽ Troubleshooting

If for some reason the ansible operation fails it means we have to connect manually for the first time. To solve this you can run

make connect

then we can close the connection typing exit and run make playbook to do the ansible part alone.

There we can see that everything went okay! At this point, we have our EC2 instance running with Amazon Linux and with docker installed.

๐Ÿ Conclusion

At the end we have a running instance with some initial configuration if we maybe need 30 machines with the same configuration it would be much easier to do with Terraform + Ansible rather than doing everything manually even if we do bash scripts to automate the process.

ย