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 Lambda | Function a a Service (FaaS) by AWS |
AWS API Gateway | AWS API Gateway |
Zappa | Deployment Framework for AWS Lambda to deploy serverless applications |
Python | Programming Language |
Flask | Web Development Micro Framework |
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. 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
Leave a Reply