Deploy a Flask App to AWS Elastic Beanstalk with Terraform

If you have used AWS Elastic Beanstalk before, you know how easy it makes to deploy web apps and you only pay for the resources your app use, not the service itself.

There are multiple ways to deploy a web app to AWS Elastic Beanstalk like CDK, AWS console, AWS CLI, or EB(elastic beanstalk) CLI. All those ways are pretty cool and work just fine.

If you like to provision your resources with Terraform, you know how easy it is to replicate or share your code with others(Terraform has a lot more benefits) and then this article is you or anyone interested to learn.

Pre-requisite:

  • Understanding of Beanstalk, Terraform and Python
  • AWS CLI is configured, so terraform could provision to was
  • Create aws-elasticbeanstalk-ec2-role and attach AWSElasticBeanstalkWebTier, AWSElasticBeanstalkMulticontainerDocker, and AWSElasticBeanstalkWorkerTier AWS managed policies.

If you are in hurry and just want to access the code and test it. Here's the git repo link

Creating an App

Create your flask app in a virtual environment, name it application.py. By default, that's the name beanstalk looks for to deploy your app. Export your app dependencies (pip freeze > requirements) to a text file, I named it requirement.txt. Learn more on how to create a flask app

Now bundle these two files into a zip folder. DON'T create a folder, put the files in it, and then zip that folder. it will confuse beanstalk and your app may not work.

Building a Terraform template

First thing first, we need to tell Terraform the provider we want to use

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

create an S3 bucket and upload the zip folder. If the app.zip folder is not in your working directory, you need to specify the path for the source then.

resource "aws_s3_bucket" "eb_bucket" {
    bucket = "eb-python-gsingh"
}
resource "aws_s3_bucket_object" "eb_bucket_obj" {
    bucket = aws_s3_bucket.eb_bucket.id
    key = "beanstalk/app.zip"
    source = "app.zip"  
}

it's time to create an app and environment for it. Application_version resource needs to be created as well as there is no way to specify the source code for the app environment (creating in the next block)

resource "aws_elastic_beanstalk_application" "eb_app" {
  name  = "eb-tf-app"
  description = "simple flask app"

}
resource "aws_elastic_beanstalk_application_version" "eb_app_ver" {
    bucket = aws_s3_bucket.eb_bucket.id
    key = aws_s3_bucket_object.eb_bucket_obj.id
    application = aws_elastic_beanstalk_application.eb_app.name
    name = "eb-tf-app-version-lable"

}

Let's create an environment for our app. The platform needs to be declared, for the python app, try to use the latest - 64bit Amazon Linux 2 v3.3.7 running Python 3.8.

The setting section is to configure the app environment as per your needs, learn more

An instance profile setting is required to create this template as it gives permissions to beanstalk to create ec2 instances and more.

resource "aws_elastic_beanstalk_environment" "tfenv" {

  name = "eb-tf-env"
  application = aws_elastic_beanstalk_application.eb_app.name
  solution_stack_name = "64bit Amazon Linux 2 v3.3.7 running Python 3.8"
  description = "environment for flask app"
  version_label = aws_elastic_beanstalk_application_version.eb_app_ver.name

  setting {
      namespace = "aws:autoscaling:launchconfiguration"
      name = "IamInstanceProfile"
      value = "aws-elasticbeanstalk-ec2-role"
  }

}

Now just deploy this Terraform and see its magic!

Mistakes and learnings

Naming the application.py something else*

A lot of times we ignore tiny details from the documentation and the next thing you know nothing is working. I had a similar experience by naming my app file differently. It is not that you can't, but then you will have to make configuration changes in the environment.

**Uploading a folder to S3 **

Terraform doesn't support a folder or multiple files uploading. A folder or files need to be zipped.

**Zipping the folder incorrectly for beanstalk **

I created a folder, put the files in, and then zip it. Beanstalk didn't like that. Beanstalk expects application files once it unzips the folder, but I had another folder. so it was causing to fail the app deployment.

Git upload issues

The entire project folder was too big to upload to GitHub. I had to create a .gitignore file and ignore big folders.

That's it for this article. I hope you found it informative and useful.

23