DEV Community

Cover image for Deploying a Flask App to AWS Lambda
David Porter
David Porter

Posted on • Updated on

Deploying a Flask App to AWS Lambda

In which I compare deploying Flask Apps to AWS Lambda with Zappa and Serverless Framework

GitHub logo divporter / flask-lambda

Deploying a Flask App to AWS Lambda

One of the first programming languages I learned was Python. The first version (v0) of my hobby site VeganFeeds however was written in PHP with an Apache server connected to a PostgreSQL database serving up dynamically rendered HTML. In the second version, confusingly named v1, I moved from the traditional LAMP stack (or LAPP in my case) to the JAM stack. Being familiar with Python, I decided that Flask would be the 'A' in my JAM stack.

After having built the Flask app, instead of continuing with a traditional web server I decided to give the serverless approach a try. Now that I've finished my trip down memory lane, let's skip ahead to deploying a Flask app to AWS Lambda.

While SAM CLI can deploy Python Lambdas, you can't deploy a Flask app straight out of the box. Although you can with a little help from flask-serverless. I have not used it personally so I won't review it here.

Zappa

Given an existing Flask app, Zappa is the easiest way to get your Flask app up there. And when I first discovered Zappa I knew next to nothing about the AWS ecosystem and so it was a friendly resource to enable me to get my Flask app out into the wild.

It is as simple as:



$ pip install zappa
$ zappa init
$ zappa deploy


Enter fullscreen mode Exit fullscreen mode

Unfortunately though it's never that easy. The above assumes that you have installed your dependencies in a virtual environment within the project directory. So if you haven't done that you will get an error like below:



Error: Zappa requires an active virtual environment!


Enter fullscreen mode Exit fullscreen mode

So let's remedy that by setting up a virtual environment and installing our dependencies into it.



$ python3 -m venv venv
$ source venv/bin/activate
$ pip install zappa flask 


Enter fullscreen mode Exit fullscreen mode

OK, so now we're ready to deploy. If we run zappa deploy again we now face a new error.



Error: This application is already deployed - did you mean to call update?


Enter fullscreen mode Exit fullscreen mode

As featured as Zappa is, I find having separate commands for an initial deploy and updating an existing deployments annoying. Anyway, let's do it. Let's call zappa update. And hooray it works.



Your updated Zappa deployment is live!: https://051zc5ynck.execute-api.ap-southeast-2.amazonaws.com/dev


Enter fullscreen mode Exit fullscreen mode

Let's have a look in the browser.

Alt Text
Yep! Looks good.

Chances are though, if you're building an app beyond "hello world" you may end up adding a dependency that works fine on your development OS but is incompatible in the Lambda environment. Then you're going to need to mimic the Lambda environment when installing your dependencies with docker using the very handy Lambda Docker images built by the lambci team. So you could do something like:



$ pip freeze > requirements.txt
$ docker run -ti -v $(pwd):/var/task  --rm lambci/lambda:build-python3.6 bash -c "python3 -m venv zappa_venv && source zappa_venv/bin/activate && pip install -r requirements.txt"


Enter fullscreen mode Exit fullscreen mode

Now the dependencies are built in the correct environment and when you run zappa deploy your Lambda should now work again. But that's a great big ugly command. Sure you use a Dockerfile, but if you're unfamiliar with Docker then that's going to make things harder.

Serverless Framework

Now despite all that Zappa bashing it was around when there was little else and really stretched the capabilities of CloudFormation and did a lot of heavy lifting behind the scenes before native support was rolled out as standard. It also comes with a lot of handy features such as the keep_warm feature to get around the cold start issue.

The Serverless Framework is a more generic tool. Not only covering languages other than Python, such as Node.js and Ruby, but also other Function-as-a-Service (FaaS) providers such as Google Cloud and Microsoft Azure.

Installation-wise the Serverless Framework is not as friendly to set up the first time as Zappa. Obviously aside from a Python installation you will also need Node.js installed as a prerequisite.

Assuming you have node next is to install serverless via npm which ships with Node.js



$ npm install -g serverless


Enter fullscreen mode Exit fullscreen mode

The -g flag means it is now available globally and you need not install it again for future projects. OK, so now what?



$ serverless create --template aws-python3


Enter fullscreen mode Exit fullscreen mode

OK cool, so we have a few files now. handler.py,.gitignore and serverless.yml Focusing on handler.py, this file reveals the bare bones of a Python Lambda handler. So how do we squeeze our Flask app into this? Well we're actually not going to use it at all. We're going to use a plugin. The Serverless community is very active with a slew of plugins to keep things nice and simple. The serverless-wsgi plugin like Zappa is designed for deploying Python WSGI apps to Lambda and abstracting away the handler protocols. You'll notice at the bottom of the link that the plugin draws inspiration from Zappa. To add the plugin you'll need to run



$ sls plugin install -n serverless-wsgi


Enter fullscreen mode Exit fullscreen mode

Note that sls is a handy alias for serverless.
Next we need to add a few lines to the bottom of our serverless.yml file.



custom:
  wsgi:
    app: app.app


Enter fullscreen mode Exit fullscreen mode

Next we need to modify our serverless.yml in the functions section so that it looks like this



functions:
  hello:
    handler: handler.hello
  api:
    handler: wsgi_handler.handler
    events:
      - http: ANY /
      - http: ANY {proxy+}


Enter fullscreen mode Exit fullscreen mode

Unlike Zappa there is no dependency on running a virtual environment, however serverless-wsgi relies on the virtualenv module. In case you don't have it installed simply run



$ pip install virtualenv


Enter fullscreen mode Exit fullscreen mode

followed by



$ sls deploy


Enter fullscreen mode Exit fullscreen mode

With any luck the output will now show the url for our newly created api
Alt Text

And if we open in a browser...

Alt Text

It works great. Now what if we want to add a second exclamation and say 'Hello, World!!'. Unlike Zappa we can just run sls deploy again. The deploy command handles both creation and updates. Lovely!

OK, but what about my dependencies that I need docker for? Well thankfully there's a plugin for that. serverless-python-requirements will do the Docker/lambci stuff for you. It does other nifty stuff too, like zipping them up to reduce their size or even throwing them in a layer for you!

What about Chalice?

Chalice is the offical AWS tool for deploying Python Lambdas. It has a similar syntax to Flask (and other Python WSGI frameworks), so for Flask users it will feel comfortable. But unlike Zappa or Serverless you can't use Chalice to deploy an existing Flask app. You must refactor it first.

Chalice is not as configurable as Zappa and Serverless, so you will not get to enjoy all the features of a Flask App along with the flexibility of Zappa or Serverless. For starting a simple project Chalice will help you get up and running quickly. Then if you find it doesn't meet your needs then you can look to Zappa and Serverless.

Top comments (0)