I spent some time yesterday getting a Python Flask application into Amazon Web Services (AWS). Hopefully, this tutorial can help you save some time in doing the same for your own Python (or Docker) web applications!
Continuous Integration (CI) and Continuous Deployment (CD) are powerful techniques that enable teams to rapidly collaborate to produce consistent value. Each code push to a designated branch kicks off the pipeline to build, test, and deploy code to the target environment. CircleCI is an integration pipeline as a service that enables developers to create pipelines without having to worry about managing the infrastructure.
Docker is a wonderful technology that standardizes the management and delivery of applications. It's like the USPS motto, "If it fits, it ships". All of the major cloud providers have a solution to deploy and manage Docker containers, in this tutorial we will be utilizing AWS's ECR/ECS to do so.
- Python 3+
- Python Virtual Environments
- CircleCI Account
- Docker
- Terraform
- GitHub / BitBucket
- AWS Account
1. Git clone DEV3L: python-flask-aws
This is a barebones repository. It is intentionally slim, so you can focus on getting something up and running sooner than later.
: git clone https://dev3l@bitbucket.org/dev3l/python-flask-aws.git
: cd python-flask-aws
plython-flask-aws:
The following commands executed from the command line will create a new virtual environment called python-flask-aws
, activate it, install the dependencies inside of the requirements.txt
file, and finally launch the hello-world Flask application.
: python3 -m venv python-flask-aws
: source python-flask-aws/bin/activate
: pip install -r requirements.txt
: python app.py
---
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 262-674-088
We should be able to load the website by going to http://localhost
or http://0.0.0.0
. Once verified, go back to the terminal and press ctrl-c
to stop the application.
Now that we know the application can run outside of Docker, let's verify that we can get it to run inside of a container.
: docker build -t python-flask:latest .
: docker run -d -p 80:80 python-flask
Once again, at this point verify that the application is running available through the browser at http://localhost
Let's disconnect your local copy of the repository and push it up to your own. This could be done through a fork or manually. If not done through a fork, create a new empty git repository on GitHub or BitBucket.
: rm -rf .git
: git remote add origin <clone url>
: git add .
: git commit "Add flask-aws project scaffolding"
: git push
Once you have a separate or forked copy of the repository, in the browser navigate to CircleCI. From the left menu, choose Add Projects. If not already done, allow CircleCI to connect to your repositories. Click the Set Up Project
on your repository from the list.
CircleCI uses ./circleci/config.yml
as a template to build your application. Now we need to set build environment variables that are referenced within this file.
In order to do this we need four pieces of information:
- AWS Access Key
- AWS Secret Key
- AWS Account Id
- AWS Region
References on how to do get this information can be found here for the access and secret key. Your account id can be found under the My Account
menu from the AWS console.
In CircleCI for the pipeline, go to Setting and enter the following environment variables:
Variable | Description |
---|---|
AWS_ACCESS_KEY_ID |
Used by the AWS CLI |
AWS_SECRET_ACCESS_KEY |
Used by the AWS CLI |
AWS_DEFAULT_REGION |
Used by the AWS CLI. Example value: "us-east-1" (Please make sure the specified region is supported by the Fargate launch type) |
AWS_ACCOUNT_ID |
AWS account id. This information is required for deployment. |
AWS_RESOURCE_NAME_PREFIX |
Prefix that some of the required AWS resources are assumed to have in their names. The value should correspond to the aws_resource_prefix variable value in terraform_setup/terraform.tfvars . |
We need to create the AWS infrastructure necessary to host our application. This can be done manually following AWS tutorials to do so, but Terraform is a cloud-agnostic way to scaffold the pieces necessary. This approach allows us to easily create environments that are identical - for example, if we wanted to create a stack for our test environment that mirrors a production environment.
From the example repository, open up and edit the terraform.tfvars
file located in the cloudformation-templates
directory. I added this file into the .gitignore as to not accidentally push these secrets to the public repository, but please be careful on each push. Set the following to your specific values.
aws_access_key = ""
aws_secret_key = ""
aws_account_id = ""
aws_region = ""
Once this is done, open up a terminal session from inside the cloudformation-templates
directory.
: terraform init
: terraform plan
: terraform apply
It will take a few minutes. Afterward, you will now have the necessary infrastructure to deploy the application to AWS.
After all this preparation, we are finally ready to see the magic happen! With our repository setup, the pipeline in place, and infrastructure scaffolded through Terraform, all we have to do now is push a change to the master branch.
Once the build is green, the last step is to find the URL our application is hosted on!
I am sure there is a better way to do this, but I am going to walk through the steps that I followed to find the DNS A Record entry created by AWS.
- Sign in to the AWS Console
- Go to the EC2 service
- From the left menu, select Load Balancers
- The DNS name field for your load balancer
There is still much to be done here. For example, how do we enable SSL? I wanted this to be a starting point to create a CI/CD pipeline into AWS. Granted we only deployed a 'Hello, World!' application, the toolchain utilized is complex. Having an example lets us layer upon the complexity.