Deploying serverless: Zappa

I keep mentioning Zappa — so what is it, precisely?

Zappa is a wonderful open source package that you can use to easily run Python applications (including WSGI web apps) on AWS Lambda functions. The Lambdas are invoked by AWS API Gateway, and Zappa makes it easy to create and upload deployment packages with all relevant configuration information. Zappa does this through a very nice build system that takes care of all the relevant AWS configuration pieces. I think it's the best way to build web apps that have either low/moderate or spiky usage patterns. And best of all, there's no lock-in — if you end up needing to deploy your Flask (or Django, etc) application to a different environment, you can do that without altering your web app.

Installing

In the root directory of the companion code folder you'll see that zappa is included in the requirements.txt file, but if you'd like to install it manually all you have to do is

pip install zappa

And then if you've got an existing WSGI-compatible web app, all you need to do to get started is

zappa init

This will detect your application type (Flask/Django) and set up a configuration file called zappa_settings.json. It will auto-generate you an S3 bucket name to use if you don't choose a name (the bucket itself will eventually be created), and also use your configured AWS region if you have one set via the AWS CLI. There is an example zappa_settings.json in the github repo.

Deploying

Once you have a configuration generated, you can then run either

zappa deploy dev

or

zappa deploy production

Each of these are different deployment stages in your zappa configuration file. You can set up more of these if you'd like, just name them different things (for instance, you could add another section called stage).

Here's an example configuration with a dev and production stage:

{
    "dev": {
        "app_function": "profile-app.app",
        "aws_region": "us-east-1",
        "profile_name": "default",
        "project_name": "zappaapp",
        "runtime": "python3.6",
        "s3_bucket": "[enter dev bucket name here]"
    },
    "production": {
        "app_function": "profile-app.app",
        "aws_region": "us-east-1",
        "profile_name": "default",
        "project_name": "zappaapp",
        "runtime": "python3.6",
        "s3_bucket": "[enter prod bucket name here]",
        "certificate_arn": "[enter arn here]",
        "domain": "[enter custom domain here]"
    }
}

As you can see, you can specify a runtime, a bucket, a region, etc. You can also specify a certificate_arn and custom domain, which I'll talk about in the Custom domains chapter. For development purposes you can omit those parameters.

The zappa deploy commands above will use the relevant config in the zappa_settings.json file, and then do the following:

  • Package your code and virtual environment into a Lambda-compatible zip file,
  • set up the WSGI middleware,
  • copy the package to S3,
  • create and manage the necessary IAM role (please be aware that the default policies are very liberal and you'll probably want to limit them),
  • register a new Lambda,
  • create new API gateway routes and link them to the Lambda function,
  • and delete the zip from S3.

Each stage in your zappa_settings.json file will have a different package created for it, so they can behave independently of each other.

Once you've deployed you can update just the package code by running:

zappa update [stage]

Where [stage] is any stage in your settings file, like production or dev.

That's it! You can now run your Python app on Lambda, using the auto-generated API Gateway URL that Zappa provides.

Logging

Zappa has some really useful built-in logging functionality, particularly the ability to tail logs on running zappa instances. To tail logs for our production environment, all we need to do is run

zappa tail production

We can do the same thing for any of the other stages in our settings file (dev, etc). We can also use various filters to limit what we see in these logs, like —http for HTTP requests, and —non-http for everything else. Please see the Zappa logging documentation for more examples.


If you're finding this guide useful, you may want to sign up to receive more of my writing at cloudconsultant.dev.