Deploy Flask Apps to AWS Elastic Beanstalk using Travis CI

In this article, we are going to deploy a Flask application to AWS Elastic Beanstalk via a GitHub and Travis CI deployment pipeline. Our goal: After pushing changes to your code to GitHub, Travis CI should pull our code, perform all tests, and if they pass, deploy the application to AWS Elastic Beanstalk. Let’s go!

Step 1: Set up project directory and install dependencies

First, we need to install all dependencies on our local machine. Because AWS Elastic Beanstalk requires context about which environment our application needs to run in, we will create a Python virtual environment and install all dependencies within the virtual environment. Run the following commands in your terminal to get started and set up the project directory:

<span># create and go to project folder</span>
<span>export </span><span>PROJECT_NAME</span><span>=</span>deploy-eb-via-travis-ci
<span>mkdir</span> ~/VSCodeProjects/<span>$PROJECT_NAME</span>
<span>cd</span> ~/VSCodeProjects/<span>$PROJECT_NAME</span>
<span># create virtual environment and activate it</span>
python3 <span>-m</span> venv my_venv
<span>source </span>my_venv/bin/activate
<span># within virtual environment, install the following:</span>
python3 <span>-m</span> pip <span>install </span>flask
python3 <span>-m</span> pip freeze <span>></span> requirements.txt
deactivate
<span># set up file structure</span>
<span>touch </span>app.py wsgi.py .travis.yml
<span>mkdir </span>tests
<span>touch </span>tests/test_42.py
<span># create and go to project folder</span>
<span>export </span><span>PROJECT_NAME</span><span>=</span>deploy-eb-via-travis-ci
<span>mkdir</span> ~/VSCodeProjects/<span>$PROJECT_NAME</span>
<span>cd</span> ~/VSCodeProjects/<span>$PROJECT_NAME</span>
<span># create virtual environment and activate it</span>
python3 <span>-m</span> venv my_venv
<span>source </span>my_venv/bin/activate
<span># within virtual environment, install the following:</span>
python3 <span>-m</span> pip <span>install </span>flask
python3 <span>-m</span> pip freeze <span>></span> requirements.txt
deactivate
<span># set up file structure</span>
<span>touch </span>app.py wsgi.py .travis.yml 
<span>mkdir </span>tests
<span>touch </span>tests/test_42.py
# create and go to project folder export PROJECT_NAME=deploy-eb-via-travis-ci mkdir ~/VSCodeProjects/$PROJECT_NAME cd ~/VSCodeProjects/$PROJECT_NAME # create virtual environment and activate it python3 -m venv my_venv source my_venv/bin/activate # within virtual environment, install the following: python3 -m pip install flask python3 -m pip freeze > requirements.txt deactivate # set up file structure touch app.py wsgi.py .travis.yml mkdir tests touch tests/test_42.py

Enter fullscreen mode Exit fullscreen mode

Then, open your project directory with your favorite code editor. You can use your command line: For example for PyCharm you can just type charm . or for VSCode you can type code . Learn more about how to set up command line interfaces for PyCharm here or VSCode here.

Step 2: “Hello World” Flask Application

We need to create a basic “Hello World” Flask application, which we can then use for the purposes of setting up our continuous deployment pipeline scenario. Assume that this is a placeholder before you are able to deploy your (real) Flask application. The deployment of a real-world application likely follows very similar steps as described here. As seen above, we created four empty files.

In app.py paste the following code:

<span>from</span> <span>flask</span> <span>import</span> <span>Flask</span><span>,</span> <span>jsonify</span>
<span>app</span> <span>=</span> <span>Flask</span><span>(</span><span>__name__</span><span>)</span>
<span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>"/"</span><span>)</span>
<span>def</span> <span>index</span><span>():</span>
<span>return</span> <span>jsonify</span><span>({</span><span>"hello"</span><span>:</span> <span>"world"</span><span>,</span> <span>"from"</span><span>:</span> <span>"index"</span><span>})</span>
<span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>"/foo"</span><span>)</span>
<span>def</span> <span>foo</span><span>():</span>
<span>return</span> <span>jsonify</span><span>({</span><span>"hello"</span><span>:</span> <span>"world"</span><span>,</span> <span>"from"</span><span>:</span> <span>"foo"</span><span>})</span>
<span>if</span> <span>__name__</span> <span>==</span> <span>'__main__'</span><span>:</span>
<span>app</span><span>.</span><span>run</span><span>(</span><span>debug</span><span>=</span><span>True</span><span>)</span>
<span>from</span> <span>flask</span> <span>import</span> <span>Flask</span><span>,</span> <span>jsonify</span>
<span>app</span> <span>=</span> <span>Flask</span><span>(</span><span>__name__</span><span>)</span>
<span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>"/"</span><span>)</span>
<span>def</span> <span>index</span><span>():</span>
    <span>return</span> <span>jsonify</span><span>({</span><span>"hello"</span><span>:</span> <span>"world"</span><span>,</span> <span>"from"</span><span>:</span> <span>"index"</span><span>})</span>
<span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>"/foo"</span><span>)</span>
<span>def</span> <span>foo</span><span>():</span>
    <span>return</span> <span>jsonify</span><span>({</span><span>"hello"</span><span>:</span> <span>"world"</span><span>,</span> <span>"from"</span><span>:</span> <span>"foo"</span><span>})</span>
<span>if</span> <span>__name__</span> <span>==</span> <span>'__main__'</span><span>:</span>
    <span>app</span><span>.</span><span>run</span><span>(</span><span>debug</span><span>=</span><span>True</span><span>)</span>
from flask import Flask, jsonify app = Flask(__name__) @app.route("/") def index(): return jsonify({"hello": "world", "from": "index"}) @app.route("/foo") def foo(): return jsonify({"hello": "world", "from": "foo"}) if __name__ == '__main__': app.run(debug=True)

Enter fullscreen mode Exit fullscreen mode

Your wsgi.py should look like this:

<span>from</span> <span>app</span> <span>import</span> <span>app</span> <span>as</span> <span>application</span>
<span>if</span> <span>__name__</span> <span>==</span> <span>"__main__"</span><span>:</span>
<span>application</span><span>.</span><span>run</span><span>()</span>
<span>from</span> <span>app</span> <span>import</span> <span>app</span> <span>as</span> <span>application</span>
<span>if</span> <span>__name__</span> <span>==</span> <span>"__main__"</span><span>:</span>
    <span>application</span><span>.</span><span>run</span><span>()</span>
from app import app as application if __name__ == "__main__": application.run()

Enter fullscreen mode Exit fullscreen mode

In tests/test_42.py add a sample test (which will always pass):

def test_42<span>()</span>:
assert 42 <span>==</span> 42
def test_42<span>()</span>:
    assert 42 <span>==</span> 42
def test_42(): assert 42 == 42

Enter fullscreen mode Exit fullscreen mode

We will revisit the fourth required file, .travis.yml, when we are setting up the Travis CI integration. As for now, we are ready to (manually) deploy our first version to AWS Elastic Beanstalk.

Step 3: Deploy to AWS Elastic Beanstalk

Before we can deploy our application, make sure that the AWS Elastic Beanstalk CLI eb is installed. If it’s not installed on your local machine, you can follow the instructions here. You can check whether your local machine has eb installed by running the following command:

eb <span>--version</span>
eb <span>--version</span>
eb --version

Enter fullscreen mode Exit fullscreen mode

The following commands will set up AWS Elastic Beanstalk with an empty application. Make sure to provide your AWS region (in my case eu-west-1) and required Python version (in my case python-3.6 is the latest Python version supported by EB at the time of writing) accordingly:

<span>export </span><span>REGION</span><span>=</span>eu-west-1
<span>export </span><span>PYTHON_VERSION</span><span>=</span>python-3.6 <span># latest version supported as of January 2020</span>
eb init <span>-p</span> <span>$PYTHON_VERSION</span> <span>-r</span> <span>$REGION</span> <span>$PROJECT_NAME</span>
<span>export </span><span>REGION</span><span>=</span>eu-west-1
<span>export </span><span>PYTHON_VERSION</span><span>=</span>python-3.6 <span># latest version supported as of January 2020</span>
eb init <span>-p</span> <span>$PYTHON_VERSION</span> <span>-r</span> <span>$REGION</span> <span>$PROJECT_NAME</span>
export REGION=eu-west-1 export PYTHON_VERSION=python-3.6 # latest version supported as of January 2020 eb init -p $PYTHON_VERSION -r $REGION $PROJECT_NAME

Enter fullscreen mode Exit fullscreen mode

Next, we need to configure the default WSGI path. This will tell AWS Elastic Beanstalk where the entry point of our Flask application is located at. In our case, it’s the file wsgi.py. Run the following commands in your terminal:

<span># default is application.py</span>
<span># alternative way to configure this -> eb config and then set manually</span>
<span>mkdir</span> .ebextensions
<span>echo</span> <span>"option_settings: - namespace: aws:elasticbeanstalk:container:python option_name: WSGIPath value: wsgi.py"</span> <span>></span> .ebextensions/wsgi.config
<span># default is application.py</span>
<span># alternative way to configure this -> eb config and then set manually</span>
<span>mkdir</span> .ebextensions
<span>echo</span> <span>"option_settings: - namespace: aws:elasticbeanstalk:container:python option_name: WSGIPath value: wsgi.py"</span> <span>></span> .ebextensions/wsgi.config
# default is application.py # alternative way to configure this -> eb config and then set manually mkdir .ebextensions echo "option_settings: - namespace: aws:elasticbeanstalk:container:python option_name: WSGIPath value: wsgi.py" > .ebextensions/wsgi.config

Enter fullscreen mode Exit fullscreen mode

Our continuous deployment pipeline will be git-based, since we push our changes to GitHub. Initialize git with the following commands:

git init
git add <span>.</span>
git commit <span>-m</span> <span>"First commit"</span>
git init
git add <span>.</span>
git commit <span>-m</span> <span>"First commit"</span>
git init git add . git commit -m "First commit"

Enter fullscreen mode Exit fullscreen mode

Note: AWS Elastic Beanstalk will create .zip archives for application deployment based on your changes that are committed to git. Therefore, remember to commit your changes before manually deploying via eb deploy, otherwise your changes will not be deployed!

In a real-world context, you would have more than one environment for your application, the most basic scenario being a live deployment (where users are interacting with your app) and a test deployment (where you will deploy new releases to test them). You can create an environment on AWS Elastic Beanstalk with the following commands:

<span>export </span><span>ENVIRONMENT_NAME</span><span>=</span><span>test</span> <span># for example: "test" or "live"</span>
<span>export </span><span>INSTANCE_TYPE</span><span>=</span>t2.nano <span># specify the instance type</span>
eb create <span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span> <span>--single</span> <span>-i</span> <span>$INSTANCE_TYPE</span>
eb use <span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span>
<span>export </span><span>ENVIRONMENT_NAME</span><span>=</span><span>test</span> <span># for example: "test" or "live"</span>
<span>export </span><span>INSTANCE_TYPE</span><span>=</span>t2.nano <span># specify the instance type</span>
eb create <span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span> <span>--single</span> <span>-i</span> <span>$INSTANCE_TYPE</span>
eb use <span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span>
export ENVIRONMENT_NAME=test # for example: "test" or "live" export INSTANCE_TYPE=t2.nano # specify the instance type eb create $ENVIRONMENT_NAME-$PROJECT_NAME --single -i $INSTANCE_TYPE eb use $ENVIRONMENT_NAME-$PROJECT_NAME

Enter fullscreen mode Exit fullscreen mode

Now, you can trigger a manual deployment to AWS Elastic Beanstalk:

eb deploy
eb deploy
eb deploy

Enter fullscreen mode Exit fullscreen mode

If you can confirm your Flask application is working as expected, we can move on and integrate Travis CI to implement our continuous deployment pipeline.

Step 4: Setting up Travis CI pipeline

Before we can proceed, you need to push your changes to GitHub:

git remote add origin https://github.com/owner/repo.git
git push <span>-u</span> origin master
git remote add origin https://github.com/owner/repo.git
git push <span>-u</span> origin master
git remote add origin https://github.com/owner/repo.git git push -u origin master

Enter fullscreen mode Exit fullscreen mode

Make sure to enable Travis CI in the repository settings, either in your GitHub account or your Travis CI account. This will make Travis CI listen to changes of your repository automatically trigger a build for this repository whenever a push is registered. Your Travis CI account needs to have the required permissions to access your GitHub account and your repositories.

Make sure the Travis command line interface travis is installed:

travis <span>--version</span>
travis <span>--version</span>
travis --version

Enter fullscreen mode Exit fullscreen mode

If it’s not installed, you can run the following command in order to install it:

gem <span>install </span>travis
gem <span>install </span>travis
gem install travis

Enter fullscreen mode Exit fullscreen mode

There are two versions of Travis CI: A free version at travis-ci.org and a paid version travis-ci.com. If you are using the paid version instead of the open source version, you need to login first, and use the argument --pro with every command. In this article, we will use travis-ci.com. Ensure you are logged in to travis-ci.com by running:

travis <span>whoami</span> <span>--pro</span>
travis <span>whoami</span> <span>--pro</span>
travis whoami --pro

Enter fullscreen mode Exit fullscreen mode

If your username shows up, you’re all set. Otherwise, sign in from your terminal using:

travis login <span>--pro</span>
travis login <span>--pro</span>
travis login --pro

Enter fullscreen mode Exit fullscreen mode

The repository is automatically inferred from your git remote (which is GitHub). To tell Travis CI more about our application, what needs to be tested, and where our application should be deployed to, add the following configuration to .travis.yml :

<span>language</span><span>:</span> <span>python</span>
<span>python</span><span>:</span>
<span>-</span> <span>3.6</span>
<span>before_install</span><span>:</span>
<span>-</span> <span>python --version</span>
<span>-</span> <span>pip install -U pip</span>
<span>-</span> <span>pip install -U pytest pytest-cov</span>
<span>-</span> <span>pip install codecov</span>
<span>script</span><span>:</span> <span>pytest</span>
<span>after_success</span><span>:</span>
<span>-</span> <span>pytest --cov=./</span>
<span>-</span> <span>codecov</span>
<span>deploy</span><span>:</span>
<span>provider</span><span>:</span> <span>elasticbeanstalk</span>
<span>access_key_id</span><span>:</span>
<span>secure</span><span>:</span> <span>$AWS_ACCESS_KEY_ID</span>
<span>secret_access_key</span><span>:</span>
<span>secure</span><span>:</span> <span>$AWS_ACCESS_KEY_SECRET</span>
<span>region</span><span>:</span> <span>$AWS_REGION</span>
<span>app</span><span>:</span> <span>$AWS_EB_APPLICATION</span>
<span>env</span><span>:</span> <span>$AWS_EB_ENVIRONMENT</span>
<span>bucket_name</span><span>:</span> <span>$AWS_EB_S3_BUCKET</span>
<span>language</span><span>:</span> <span>python</span>
<span>python</span><span>:</span>
  <span>-</span> <span>3.6</span>
<span>before_install</span><span>:</span>
  <span>-</span> <span>python --version</span>
  <span>-</span> <span>pip install -U pip</span>
  <span>-</span> <span>pip install -U pytest pytest-cov</span>
  <span>-</span> <span>pip install codecov</span>
<span>script</span><span>:</span> <span>pytest</span>
<span>after_success</span><span>:</span>
  <span>-</span> <span>pytest --cov=./</span>
  <span>-</span> <span>codecov</span>
<span>deploy</span><span>:</span>
  <span>provider</span><span>:</span> <span>elasticbeanstalk</span>
  <span>access_key_id</span><span>:</span>
    <span>secure</span><span>:</span> <span>$AWS_ACCESS_KEY_ID</span>
  <span>secret_access_key</span><span>:</span>
    <span>secure</span><span>:</span> <span>$AWS_ACCESS_KEY_SECRET</span>
  <span>region</span><span>:</span> <span>$AWS_REGION</span>
  <span>app</span><span>:</span> <span>$AWS_EB_APPLICATION</span>
  <span>env</span><span>:</span> <span>$AWS_EB_ENVIRONMENT</span>
  <span>bucket_name</span><span>:</span> <span>$AWS_EB_S3_BUCKET</span>
language: python python: - 3.6 before_install: - python --version - pip install -U pip - pip install -U pytest pytest-cov - pip install codecov script: pytest after_success: - pytest --cov=./ - codecov deploy: provider: elasticbeanstalk access_key_id: secure: $AWS_ACCESS_KEY_ID secret_access_key: secure: $AWS_ACCESS_KEY_SECRET region: $AWS_REGION app: $AWS_EB_APPLICATION env: $AWS_EB_ENVIRONMENT bucket_name: $AWS_EB_S3_BUCKET

Enter fullscreen mode Exit fullscreen mode

Then add the necessary encrypted environment variables automatically to your .travis.yml file (see references above):

travis encrypt <span>--pro</span> <span>AWS_ACCESS_KEY_ID</span><span>=</span><span>"YOUR_KEY_ID_HERE"</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_ACCESS_KEY_SECRET</span><span>=</span><span>"YOUR_KEY_SECRET_HERE"</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_REGION</span><span>=</span><span>$REGION</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_APPLICATION</span><span>=</span><span>$PROJECT_NAME</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_ENVIRONMENT</span><span>=</span><span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_S3_BUCKET</span><span>=</span><span>"YOUR_BUCKET_HERE"</span> <span>--add</span> <span># change this as needed – a new bucket will be automatically created if it does not yet exist </span>
travis encrypt <span>--pro</span> <span>AWS_ACCESS_KEY_ID</span><span>=</span><span>"YOUR_KEY_ID_HERE"</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_ACCESS_KEY_SECRET</span><span>=</span><span>"YOUR_KEY_SECRET_HERE"</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_REGION</span><span>=</span><span>$REGION</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_APPLICATION</span><span>=</span><span>$PROJECT_NAME</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_ENVIRONMENT</span><span>=</span><span>$ENVIRONMENT_NAME</span>-<span>$PROJECT_NAME</span> <span>--add</span>
travis encrypt <span>--pro</span> <span>AWS_EB_S3_BUCKET</span><span>=</span><span>"YOUR_BUCKET_HERE"</span> <span>--add</span> <span># change this as needed – a new bucket will be automatically created if it does not yet exist </span>
travis encrypt --pro AWS_ACCESS_KEY_ID="YOUR_KEY_ID_HERE" --add travis encrypt --pro AWS_ACCESS_KEY_SECRET="YOUR_KEY_SECRET_HERE" --add travis encrypt --pro AWS_REGION=$REGION --add travis encrypt --pro AWS_EB_APPLICATION=$PROJECT_NAME --add travis encrypt --pro AWS_EB_ENVIRONMENT=$ENVIRONMENT_NAME-$PROJECT_NAME --add travis encrypt --pro AWS_EB_S3_BUCKET="YOUR_BUCKET_HERE" --add # change this as needed – a new bucket will be automatically created if it does not yet exist

Enter fullscreen mode Exit fullscreen mode

It’s strongly recommended to encrypt environment variables with sensititve information, such as AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY_SECRET. Sensitive information should never end up in source control. Check out this resource for more information on how to encrypt environment variables for Travis CI. An alternative to the above step (travis encrypt ...) is to configure the environment variables using the Travis CI web application and adding them to the repository settings. An alternative to setting encrypted environment variables is to use the following command: travis env set VARIABLE_NAME "value"

And… we’re done! From now on, you can make changes to your application and simply push them to GitHub. Everything else is set up and done automatically for you: Travis CI will pull your code, perform the tests, and if they pass, deploy the application to AWS Elastic Beanstalk. Should the tests not pass, the application version will not be deployed, and you will be able to investigate further as to why.

Conclusion

You now have gone through the required steps to create a continuous deployment pipeline for your Flask application. Newly pushed changes are automatically analyzed and tested by Travis CI. If all tests pass, new versions of your Flask application will be continuously deployed to the specified environment(s) within AWS Elastic Beanstalk.

I hope you enjoyed this article –  please let me know what you think, or if you have any questions.

原文链接:Deploy Flask Apps to AWS Elastic Beanstalk using Travis CI

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
Pain changes people. However, love will finally guide them back.
伤痛会改变一个人,但爱最终总会让你找回最初的自己
评论 抢沙发

请登录后发表评论

    暂无评论内容