How to Deploy a Flask Web Application as Serverless App on AWS Lambda using Zappa

neotam Avatar

How to Deploy a Flask Web Application as Serverless App on AWS Lambda using Zappa
Posted on :

Zappa is the deployment framework for deploying serverless applications on AWS using AWS Lambda and API Gateway. In this article we will use Flask to demonestrate the deployment of serverless app using AWS Lambda with deployment framework Zappa

Tools and Technologies Used

AWS LambdaFunction a a Service (FaaS) by AWS
AWS API GatewayAWS API Gateway
ZappaDeployment Framework for AWS Lambda to deploy serverless applications
PythonProgramming Language
FlaskWeb Development Micro Framework
Tools used to deploy flask app on AWS Lambda using Zappa

FastTrack: App Depployment Using Zappa

For those who are not having time to sit back and learn, and in hurry to deploy. Here is simple 5 steps to deploy serverless

# 1. Create virtual env
python -m venv zvenv

# 2. Activate Virtual Env, then Create the zappa config
zappa init 

# 3. Deploy the app on AWS
zappa deploy 

AWS Lambda

AWS Lambda is the cloud delivery model known as FaaS (Function as a Service). Unlike traditional IaaS (Infrastructure a a Service) using AWS Lambda we don’t have to provision a full blown compute engines or VPS (virtual private servers) referred as EC2 in terms of AWS terminology. For small or less demanding work loads provisioning EC2 instance would not be a cost effective since we get billed for number of hourser server is up and running even though server time is not used or there is no traffic. By using AWS Lambda we only pay for number of requests made to AWS Lambda function. Such that, using lambda will be a significant savings since we don’t have to pay for server time that is not utilized

While using lambda is cost effective, it also intrinsically provides the infinite scalability of the application.


To understand, how cost effective it is let’s consider the following use case scenario

We small web application created to server as reporting tool which is used to export reports only once in every week 

According to the given use case scenario even if we create smallest EC2 instance of type t2.micro which costs “$0.0116” [1] which will cost you 8 x 720(H) = $8.352 for every month. So $8 may not seem that much, but this web application is getting used only 4 times a month, even if you stop the instance you get billed for elastic block storage, snapshots, and elastic IP address. Let’s keep the billing a side, you need take care of

  • Provisioning instance
  • Installing Dependencies
  • Attend restarts and health alerts when instance is unreachable
  • Take care of updates

Along with all tasks mentioned above, scalability of the web application is also a challanging if everyone is using the web application every day all the time by more than aniticipated number of users.

For these kind of usecase scenarios, if we use lambda. Pricing would be around less than $1 if you are making only thousands of hits per month if not hundreds.

What AWS Lambda has to offer

  • Implicit Scalability
  • Cost Effectiveness
  • Seamless Integration with other AWS services like API Gateway

About Zappa

Zappa is deployment framework for deploying serverless web applications on AWS using AWS Lmabda and AWS API Gateway. Zappa bundles the any app written in python and deploys to AWS Lambda.

Before proceeding with installation you may optionall create the virual environment

python -m venv venv 

Install Zappa

Install the zappa serverless deployment framework using pip as follows

pip install zappa 

Simple Flask App

Install the flask web application micro-framwork using pip as follows

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, From Lambda!</p>"

Deploying on AWS using Zappa

Before you deploy the created simple flask web application on AWS lambda we need to create credentials for zappa to use with proper policies and roles assignmed to access Lambda and API gateway.

Create the IAM user and download the Access key and Access Secret

Read about how to configure How to configure AWS CLI

Following the steps

  • Create the IAM user
  • Create the group ex: serverless_zappa and add created user to the group
  • Attach the inline policy to the group such that all users in the group will have same permissions

Use the inline-policy template to create custom inline policy to give access to Lambda, API gateway and S3 buckets to the users in the group created

Make sure to provide proper AWS account number

Configuring Zappa

Change the current working directory to the root folder of the project and then run ‘zappa init’ to initilize the zappa configuration to create ‘zappa_settings.json’ file

zappa init

Edit the zappa_settings.json file to reflect you project configuration. Here is the example,

{
    "dev": {
        "aws_region": "ap-southeast-2",
        "profile_name": "PROFILE_NAME",
        "project_name": "reporting",
        "runtime": "python3.8",
        "s3_bucket": "zappa-2jcuik342",
        "app_function": "main.app",
        "layers": ["arn:aws:lambda:ap-southeast-2:770693421928:layer:Klayers-p38-numpy:6"]
    },
    "v1": {
        "aws_region": "ap-southeast-2",
        "profile_name": "PROFILE_NAME",
        "project_name": "reporting",
        "runtime": "python3.8",
        "s3_bucket": "zappa-2jcuik342",
        "app_function": "main.app",
        "layers": ["arn:aws:lambda:ap-southeast-2:770693421928:layer:Klayers-p38-numpy:6"]
    }
}

Deploy, Update and Delete Deployment using Zappa

After all this work, all you need to do to deploy the serverless app using zappa to AWS lambda

zappa deploy dev

Where dev is the environment to choose from zappa_settings.json file

To modify or update deployment

zappa update dev 

To delete the serverless app deployment

zappa undeploy dev 

Deploying App using Zappa Summary

In simple steps

Install –> init –> deploy

$ pip install zappa
$ zappa init
$ zappa deploy

References

[1]“EC2 Instance Pricing – Amazon Web Services (AWS),” Amazon Web Services, Inc., 2003. https://aws.amazon.com/ec2/pricing/on-demand/
[2]“AWS Lambda – Pricing,” Amazon Web Services, Inc. https://aws.amazon.com/lambda/pricing/
[3]“Creating and sharing Lambda layers - AWS Lambda,” docs.aws.amazon.com. https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html

Appendix

inline policy template

{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "iam:AttachRolePolicy",
          "iam:GetRole",
          "iam:CreateRole",
          "iam:PassRole",
          "iam:PutRolePolicy"
        ],
        "Resource": [
          "arn:aws:iam::XXX_AWS_ACCOUNT_ID_XXX:role/*-ZappaLambdaExecutionRole"
        ]
      },
      {
        "Effect": "Allow",
        "Action": [
          "apigateway:DELETE",
          "apigateway:GET",
          "apigateway:PATCH",
          "apigateway:POST",
          "apigateway:PUT",
          "events:DeleteRule",
          "events:DescribeRule",
          "events:ListRules",
          "events:ListRuleNamesByTarget",
          "events:ListTargetsByRule",
          "events:PutRule",
          "events:PutTargets",
          "events:RemoveTargets",
          "lambda:AddPermission",
          "lambda:CreateFunction",
          "lambda:DeleteFunction",
          "lambda:GetAlias",
          "lambda:GetFunction",
          "lambda:GetFunctionConfiguration",
          "lambda:GetPolicy",
          "lambda:InvokeFunction",
          "lambda:DeleteFunctionConcurrency",
          "lambda:ListVersionsByFunction",
          "lambda:RemovePermission",
          "lambda:UpdateFunctionCode",
          "lambda:UpdateFunctionConfiguration",
          "cloudformation:CreateStack",
          "cloudformation:DeleteStack",
          "cloudformation:DescribeStackResource",
          "cloudformation:DescribeStacks",
          "cloudformation:ListStackResources",
          "cloudformation:UpdateStack",
          "cloudfront:UpdateDistribution",
          "logs:DeleteLogGroup",
          "logs:DescribeLogStreams",
          "logs:FilterLogEvents",
          "route53:ListHostedZones"
        ],
        "Resource": [
          "*"
        ]
      },
      {
        "Effect": "Allow",
        "Action": [
          "s3:CreateBucket",
          "s3:ListBucket",
          "s3:ListBucketMultipartUploads"
        ],
        "Resource": [
          "arn:aws:s3:::zappa-*"
        ]
      },
      {
        "Effect": "Allow",
        "Action": [
          "s3:DeleteObject",
          "s3:GetObject",
          "s3:PutObject",
          "s3:AbortMultipartUpload",
          "s3:ListMultipartUploadParts"
        ],
        "Resource": [
          "arn:aws:s3:::zappa-*/*"
        ]
      }
    ]
  }

Typical Configuration zappa settings for flask app

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "myawsprofile",
        "project_name": "newproj",
        "runtime": "python3.9",
        "s3_bucket": "zappa-rc8jdia"
    }
}

Typical configuration of zappa_settings for django project

{
    "dev": {
        "django_settings": "settings",
        "aws_region": "us-east-1",
        "profile_name": "myawsprofile",
        "project_name": "newproj",
        "runtime": "python3.9",
        "s3_bucket": "zappa-rc8jdia"
    }
}

Zappa Command Synopsis

zappa [-h] [-v] [--color {auto,never,always}]
             {certify,deploy,init,package,template,invoke,manage,rollback,schedule,status,tail,undeploy,unschedule,update,shell,save-python-settings-file} ...

Zappa - Deploy Python applications to AWS Lambda and API Gateway.

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         Print the zappa version
  --color {auto,never,always}

subcommands:
  {certify,deploy,init,package,template,invoke,manage,rollback,schedule,status,tail,undeploy,unschedule,update,shell,save-python-settings-file}
    certify             Create and install SSL certificate
    deploy              Deploy application.
    init                Initialize Zappa app.
    package             Build the application zip package locally.
    template            Create a CloudFormation template for this API Gateway.
    invoke              Invoke remote function.
    manage              Invoke remote Django manage.py commands.
    rollback            Rollback deployed code to a previous version.
    schedule            Schedule functions to occur at regular intervals.
    status              Show deployment status and event schedules.
    tail                Tail deployment logs.
    undeploy            Undeploy application.
    unschedule          Unschedule functions.
    update              Update deployed application.
    shell               A debug shell with a loaded Zappa object.
    save-python-settings-file
                        Generate & save the Zappa settings Python file for docker deployments

Troubleshooting

First thing is first, how to check logs to figure out what is going on? and what error causing the issue. Use the command

zappa tail 

Command “Zappa tail” prints the logs on console in realtime, which is really helpful to debug and throubleshoot

Zappa requires the virtual environment,

click.exceptions.ClickException: Zappa requires an active virtual environment!

There also, python version incompatibility. Use the supported python version

RuntimeError: This version of Python (3.11) is not supported!
Zappa (and AWS Lambda) support the following versions of Python: ['3.7', '3.8', '3.9', '3.10']

If you run into, error like Runtime.ImportModuleError. You have problem with dependencies that is due to either missing or version mismatch

 Runtime.ImportModuleError: Unable to import module 'handler': cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_' (/var/task/urllib3/util/ssl_.py)

Another kind of same import error

 Runtime.ImportModuleError: Unable to import module 'handler': attempted relative import with no known parent package

To solve this problem, use the following command to check if dependencies are properly installed in the virutalenv

pip freeze 

# install the missing, then update deployment

zappa update 

If you are using authorizer, that can be either lambda or AWS cognito. You need to specify that relevant information in zappa_settings.json.

Here is an example of zappa_settings.json with AWS Cognito authorizer

{
  "dev": {
    "app_function": "app.app",
    "aws_region": "us-east-1",
    "profile_name": "awscliProfile",
    "project_name": "myappname",
    "runtime": "python3.9",
    "s3_bucket": "zappa-r2342d",
    "authorizer": {
      "type": "COGNITO_USER_POOLS",
      "provider_arns": [
        "arn:aws:cognito-idp:{region}:{account_id}:userpool/{user_pool_id}"
      ]
    }
  }
}


Some times zappa wrongly detects the project as Django application when it is flask app. In such a case you can edit the zappa_settings.json to add “app_function” property and remove the property “django_settings”

Import Module Error

error

[1712944942173] LAMBDA_WARNING: Unhandled exception. The most likely cause is an issue in the function code. However, in rare cases, a Lambda runtime update can cause unexpected function behavior. For functions using managed runtimes, runtime updates can be triggered by a function change, or can be applied automatically. To determine if the runtime has been updated, check the runtime version in the INIT_START log entry. If this error correlates with a change in the runtime version, you may be able to mitigate this error by temporarily rolling back to the previous runtime version. For more information, see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html
[1712944942173] [ERROR] Runtime.ImportModuleError: Unable to import module 'handler': attempted relative import with no known parent package

To address this kind of import error: make sure zappa itself is installed in the project virtual environment

Leave a Reply

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