How to use Terraform + GitHub Actions to Deploy a Flask app

·

3 min read

About 2 weeks ago, I shared my first Devops article: Deploy a Python app to An EC2 Instance using GitHub Actions. The next part of the task is to automate the entire process meaning. In the first task, I had to ensure the EC2 instance existed before deploying else the GitHub action run will fail.

My mentor suggested using Terraform for the automation process. Before this, I did not even have a vague idea of where their docs is located. I went into action and started looking for similar videos and posts about this.

What will happen is I went on a wild goose chase, the options I saw were people using VPC, subnets, load balancers, etc. This was not what I was looking for, it is much complex than what I want. In my next 1on1 with my mentor, she clarified I was expected to only stick to automating MY CURRENT WORKFLOW since I did not use any of those resources for now, just automate what you currently have. So my process is below:

  1. Install Terraform

  2. Create an IAM user and generate access and secret keys as they provide access to Terraform for AWS services.

    1. Save them as repository secrets in your GitHub repo so they can be referenced in the GitHub Action file in the format ${ACCESS_KEY}.
  3. Use remote backend to save terraform state information:

    • Remember you are deploying to an EC2 instance hence terraform will need access to this file to keep track of the state of your infrastructure else it will try recreating the resources everytime your GitHub Actions workflow runs.

    • Can use Cloud Champ's: Terraform Remote State Backend using S3 and DynamoDB

  4. Resource Script: Now we can write up the terraform script that will create the AWS resources we require. In my case I needed the following:

    1. An EC2 instance

    2. Security group: remember to open the inbound port 5000 and outbound port: 0

    3. Remember to attach the security group to the EC2 instance using the vpc_security_group_ids field in the EC2 definition block.

    4. Provide the execution steps inside the user_data field also in my EC2 block. This part was a back and forth task as I noticed the GitHub repo was not been cloned.

    5. I also provided user_data_replace_on_change and set it to true as user_data field runs once when the EC2 is created initially. Using this field allows the script in user_data be run again when either the EC2 instance or the security group is modified.

    6. Used an output variable to display the public IP of the EC2 instance when the script terminates, hence I do not need to login to AWS to get this information.

    7. Provided the terraform backend block since I am using AWS to save the state information.

  5. GitHub Actions Workflow

    • Made up of 2 workflows:

      • First was for any of 3 branches: chore, feature, or docs. If there was a push to any of these branches, checkout, create virtual environment, text and run linter

      • Second workflow: If the previous workflow fails, skip and do not run. Also it was for when a pull request was raised to merge into main branch. This workflow responsible for running the Terraform commands to initialize, validate and then applying (hence deploying my app) the necessary changes.

My resources:

Assignment Repository

Terraform script

GitHub Action Workflow