Unleashing Automation: Spinning Up EC2 Instances with the Dynamic Duo of Terraform and Ansible ๐
๐ 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
Terraform - https://developer.hashicorp.com/terraform/downloads
Ansible - https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
AWS Free tier account - https://aws.amazon.com/free/
Unix based OS - https://linuxmint.com/
๐ 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 isdeploy: 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.