What problems does a PaaS solution like Beanstalk solve?

Organizations consider a PaaS (Platform as a Service) solution to be a reliable tool for resolving their issues because of the speed at which it allows developers to create, test and deploy apps. A PaaS solution helps you to fail more quickly so that you can iterate over your code changes and deployment strategies.

A pay-as-you-go model makes it possible for individuals or organizations to use sophisticated development software and business intelligence and analytics tools that they could not afford to purchase outright.

Benefits of a PaaS solution

A solution like Beanstalk will take care of the scaling of your web servers by putting a reverse proxy in front of your application servers. It will easily manage requests in the order of early thousands concurrently and after that your load balancers will kick in rotating the user’s requests to other application servers according to the auto scaling policy you have mentioned in the configuration settings while setting your application.(only of course, if you have chosen your environment to be load balanced). Other PaaS solutions that are popular are Heroku cloud, Microsoft Azure Platform as a Service, AWS Lambda and Google App Engine.

Table of Contents

  • How Does Elastic Beanstalk fit into the picture?
  • Prerequisites to Deploy a New Flask app on AWS Elastic Beanstalk
  • Methods to Deploy on AWS Elastic Beanstalk
  • Deploying manually on Beanstalk using a ZIP file
  • Creating your Beanstalk Environment
  • Fine Tune Your Environment for Debugging
  • How to Deploy the App using a Script?
  • How to Deploy the App using Elastic Beanstalk CLI(Command Line Interface)
  • How to install HTTPS Certificates on your Application Server for a Domain Name

How does Elastic Beanstalk fit into the picture?

Elastic Beanstalk is one of the plethoras of services provided by Amazon Web services (AWS) which provides you with the capability to run scalable and highly available applications in no time. It’s a one-stop solution for you if you want a self-managed cloud infrastructure on AWS.

I feel that any Application deployed in production should be made such that it stands out on the following 3 features:

  1. Scalability
  2. High Availability(Resiliency)
  3. Maintainability

AWS Beanstalk takes care of the first two for you with great ease, adding fault tolerance to your app and lets you worry about the third point only.

Beanstalk provides you the capability with provisioning two types of app environments namely:

  1. Web Server Environment: an application that serves HTTP requests
  2. Worker Environment: an application that pulls tasks from a queue(here, most likely the SQS (simple queue service) by AWS)

We are going to proceed with the web server environment where we write API’s in Flask app (python) and have endpoints defined. The endpoints are suffixed to a URL which is a domain name of our choice provided by Beanstalk (of course, only if it’s available). We’ll be going over the steps to deploy an app without a database attached to it.

Let’s move on to setting a simple app on AWS Elastic Beanstalk.

Prerequisites to deploy a new Flask app on AWS Elastic Beanstalk

  1. Your code files should contain a file application.py which will serve as the entry point of the whole application and is needed by Beanstalk to run the App.
  2. The application object that Flask uses should be named application and not app.
  3. All the python dependencies should be placed in the file requirement .txtplaced in the root folder of your code repository.
  4. You can include a .ebextensions folder in the root folder of your code repository and let it remain empty for the time being.

When does a .ebextensions folder come handy for your app??

.ebextensions is compliance followed by Beanstalk, where if you mentioned some particular commands in YAML format text, it will be executed by a daemon process on all the application server instances. for eg, To enable HTTPS on my application servers, I earlier had to manually go into the AWS Management Console in the security groups to open ingress rules on port 443. Now I’ve mentioned the same in a config file some_name.config, which automatically opens port 443 on the server.

You can also mention some commands int the same file which you want to execute on the server before the application code is set on the instance. My file looks something like this:

Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
CidrIp: 0.0.0.0/0
commands:
name_your_command_here:
command: "sudo some command1;sudo some command2"

Methods to deploy your app on AWS Elastic Beanstalk

This is going to a long ride so buckle up !! Along with this, I’ll also walk you through setting up HTTPS certification for a domain name of your choice to make your API secure.

Deployment on Beanstalk can be done in 3 ways. ( I’ve mentioned 4, the last one being very similar to the first one so it should not count, but I want to tell you guys how I did it.)

  1. Making a source bundle of your application code manually zipping it in a file and uploading it to Elastic Beanstalk.
  2. Using an already written script to make a zip file and uploading the same zip to Beanstalk. This is 95% similar to the first one, just saves you from the hassle of selecting multiple files and zipping them.
  3. Using the AWS Elastic Beanstalk CLI(command line interface to directly deploy from your local system)
  4. Configuring CI/CD in your local system and CircleCI (or some other CI/CD tool), so that anytime you push your code to a Git repository, it will get automatically deployed to Beanstalk.

Deploying manually on Beanstalk using a ZIP file

Creating your Beanstalk environment

  1. Sign in into your AWS Account in any Region and navigate to AWS Elastic Beanstalk in the services section. Please make sure you have the Beanstalk Full Access IAM policy attached with your account.
  2. Click on Create New Application and give a possible description of your application.
  3. Click on Create one now to create an environment and select Web Server Environment.
  4. Type in a domain name of your choice and check if it’s available. This domain will be different from the one for which we will generate HTTPS certificates using certbot.
  5. Choose Python as the language in the list of preconfigured Platforms.
  6. Choose Upload your code as an option to deploy your code.
  7. Head over to the Directory in which you have the code on your system.
  8. Select all the files and create a zip out of it. Make sure you have selected the .ebextensions folder which will be hidden. Don’t include the virtual environment folder.
  9. Choose the option to upload the file from local storage. This zip will ultimately get uploaded to an S3 bucket created especially for your environment. If all goes well, you will have a flask app deployed successfully.

Fine Tune Your Environment for Debugging

  1. Head Over to your AWS Elastic Beanstalk Console in the Region it was set up in the earlier steps.
  2. Click on the Configure more options to finish configuring your environment.
  3. You’ll see many tiles but you have to configure options in the Instances and Security Tab.
  4. Click on the Instances tab and select the instance type and Save your changes.
  5. Click on the Security tab and select a key_pair to ssh into your application server. If no such key pair exists, then you would have to create one. Refer here.
  6. Click on Create Environment and AWS will take you to a live events page where all the resources needed for your app are seen spinning up. (This can take a few minutes, sit back and let AWS do the magic.)
  7. If Deployed Successfully, you will be redirected to the home page of your Environment, with a big green tick showing all is working good.
  8. If not, the status of the app may be InfoSevere or Degraded. In either of the cases, you can click on the Causes button and see the possible list of errors. Or you can SSH into your application servers using the pem file you selected and try to see the log files(either of access_logerror_log(in /var/log/httpd)or eb-activity.log(/var/log/eb-activity.log).Happy Debugging!

How to deploy the app using a script

1. A mentioned earlier, this method is 95 % similar to the above method except for the fact that we will automate the process of creating the zipped file containing the application code.

2. Rest processes are the same where we head over to the AWS Management Console and upload this zip file which gets deployed.

3. The contents of the file make a zipped folder of your application code.

import sys
import os
import glob
def make_zip_elastic_bs(zip_name):
zip_name = sys.argv[1]
files_grabbed = [glob.glob(e) for e in ['requirements.txt', '.py', '.csv','*.sh']]
#The above line tells to include the requirements files in the repository with
#along with all the files with .py ,.csv and .sh extensions.
files_grabbed = [item for sublist in files_grabbed for item in sublist]
if(os.path.isdir(os.getcwd() + '/some_folder_name')):
files_grabbed.append("some_folder_name")
else:
print("Please add this some folder to your code repository")
if(os.path.isdir(os.getcwd() + '/.ebextensions')):
files_grabbed.append(".ebextensions")
else:
print("Please add the .ebextensions folder to your current Directory")
for f in os.listdir(os.getcwd()):
if f in files_grabbed:
os.system("zip -r {}.zip {}".format(zip_name, f))
if name == 'main':
make_zip_elastic_bs(sys.argv[1])

4. Change the above code snippet according to your needs.

5. To run the script go to the directory where your script is, and type python make_elasticbeanstalk.py my_app. (Here, my_app is the name of your zipped folder which will get created in your current directory).

6. Head over to AWS Management and upload this zipped folder as explained earlier.

How to deploy the App using Elastic Beanstalk CLI (Command Line Interface)

  1. Install the eb-cli in your local system. You can Refer the docs here. Once installed, you can check the version of eb-cli if you have installed the eb-cli successfully.
  2. Change your directory to ~/.aws, and make a profile in both config and credentials file with the default region specified. You can add them just like this:
[default]
region = us-east-1
[profile eb-cli]
aws_access_key_id=##############
aws_secret_access_key=###############

3. You can also make a .gitignore or .ebignore file in the root folder of your code repo. If you have made a file, then AWS elastic beanstalk will not upload those files mentioned in the .gitignore. And if you have made a file, it will supersede the contents mentioned in the .gitignore file . My .gitignore file looked something like this:

/.vscode
*.pyc
/tests/some_test_data_folder
.Rhistory
*.zip

4. Now change into your code repo, and execute the following commands:

eb init EngineTestApp --profile eb-cli --region us-east-1 --platform "Python 3.6" -k elastic_bs
This command will initiate a beanstalk app with the Application name as EngineTestApp and use eb-cli as your AWS profile. We will use Python3.6as the platform with elastic_bs as the keypair to ssh into your instances. Make sure you have elastic_bs key available in the pem files for your AWS account.

eb create EngineTestEnv --profile eb-cli -d -i t2.large -k elastic_bs --single
This will create an Environment with the name EngineTestEnv with a single instance environment and ec2-instance type as t2.large(of course you can select some other type as well.)You can refer here to see the available instance types and choose the one according to your needs.

How to install HTTPS certificates on your application server for a domain name

We Will using cert-bot to install HTTPS certificates for your Beanstalk environment so that you no longer have to use that unsecure HTTP URL provided by Beanstalk anymore and can provide a better domain name for your App.

  1. After following the previous steps in deploying the app manually, ssh into the instance of your app using the pem file you had selected in the configuration settings.
  2. Change your directory: cd /opt/python/current/app
  3. Make a file with the name ssl_config in this directory : opt/python/current/app/
  4. Copy these contents into that file:
#LoadModule wsgi_module modules/mod_wsgi.so
WSGIPythonHome /opt/python/run/baselinenv
WSGISocketPrefix run/wsgi
WSGIRestrictEmbedded Onfiles_grabbed
WSGIDaemonProcess wsgi processes=1 threads=15 display-name=%{GROUP} \
python-home=/opt/python/run/venv/ \
python-path=/opt/python/current/app user=wsgi group=wsgi \
home=/opt/python/current/app
<VirtualHost *:80>
Alias /static/ /opt/python/current/app/static/
<Directory /opt/python/current/app/static/>
Order allow,deny
Allow from all
</Directory>
WSGIScriptAlias / /opt/python/current/app/application.py
WSGIProcessGroup wsgi
<Directory /opt/python/current/app/>
Require all granted
</Directory>
</VirtualHost>
LogFormat "%h (%{X-Forwarded-For}i) %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

5. I have written a bash script to install the certificates which will do the work for you. Just sit tight!!

!/bin/sh
EMAIL="your email address "
DOMAIN_NAME="your DNS name "
sudo wget https://dl.eff.org/certbot-auto;sudo chmod a+x certbot-auto
sudo yum install mod24_ssl -y
sudo service httpd stop
sudo ./certbot-auto certonly --debug --non-interactive --email $EMAIL --agree-tos --standalone --domains $DOMAIN_NAME --keep-until-expiring
sudo service httpd start
if [ -d "/opt/python/current/app/ssl_config" ]; then
sudo rm /etc/httpd/conf.d/wsgi.conf
sudo cp /opt/python/current/app/ssl_config /etc/httpd/conf.d/wsgi.conf
fi
sudo service httpd restart
sudo ./certbot-auto -d $DOMAIN_NAME --renew-by-default --redirect
sudo service httpd restart

6. Change the contents of this file accordingly. Like, change the DOMAIN_NAMEvariable to the domain you are pointing to. Make sure you have that domain name registered in the DNS records of your domain name registrar(eg GoDaddy) to the public IPv4 of your ec2-instance. Put in your email address in the EMAIL variable.

7. After changing the contents, execute the shell script using sh script_name.sh

8. You now have a secure HTTPS connection to your app server. However, these certificates will expire after 90 days, which we obviously do not want. Let’s fix that too.

Assuming you are SSH’ed into your application server. Start the cronjob service by running sudo service crond start .Run the command crontab -e on the terminal and you will get the file. Make the shell script which we saw earlier en executable by typing sudo chmod +x script_name.sh .

Enter the following contents in the file:

# m h  dom mon dow   command

* * * */2 * /path/to/your/script.sh

We are running the shell script as a cron job every 2 months just to be on the safe side that we do not let the certificates expire.

As you can clearly see, the application was up and running effortlessly. If we proceed with the bare minimum requirements, then Beanstalk just requires us to upload a zip folder with some prerequisites met and it will handle the rest deployment process for us. Installing HTTPS certificates for a domain name gives a personal touch to your application as it removes the elastic beanstalk substring from the URL provided to us by Beanstalk. The main advantage is that it saves you from deployment woes and lets you focus more on your code.

Congrats on your first AWS deployment and Happy Coding!

Still struggling to decode or want to know more? Book a demo today!


Also published on Medium.

8 Replies to “Deploying a Flask Application to AWS Elastic Beanstalk

  1. I love your blog.. very nice colors & theme. Did you create this website yourself? Plz reply back as I’m looking to create my own blog and would like to know wheere u got this from. thanks

Leave a Reply

Your email address will not be published. Required fields are marked *