"Serverless" deployments


#1

One thing that’s come up a couple of times already is that API Star might be a good fit for the so called “Serverless” deployment model, such as that provided by AWS lamda.

I don’t personally have any experience with using this myself but v interested to here from Python folks who have, about what tooling and platforms they’ve been using, and how they’ve found it. What were the big wins, where were the pain points, which tooling combinations work well etc? When is it valuable? When isn’t it valuable?

Disclaimer. Yes “serverless” is an awfully misleading name, but there we go.


#2

Personally i will be deploying on AWS EB, but in Serverless land, it would probably be interesting for some to mingle with Zappa


#3

Zappa looks stunning. Looks like they have Python 3 support about to land imminently… https://github.com/Miserlou/Zappa/issues/793. (Only became available on AWS lamda within the last few days from what I understand)


#4

I’ve spent the last year or more diving into serverless with AWS.

Zappa is an effort to provide WSGI compatibility atop API Gateway + Lambda.

Chalice is an effort to provide a platform specific web API.

For deployments I’ve personally been using serverless.com which generates a CloudFormation config from your YAML config file.

I think for API*, a since it has its own URL routing, a single API Gateway endpoint with “ANY” verb and “{proxy+}” as the path would suffice.

Then it’s a matter of providing something more WSGI-like for the request…


#5

Successfully deployed API Star to AWS Lambda, using Zappa!

“Hello, world”: https://ty9oub8a70.execute-api.us-east-1.amazonaws.com/dev

Have added install instructions to the README:


#6

I’m having no end of trouble getting a Zappa deploy to work. I have a flacon api deployed in production and I’m eyeing Apistar for another project. So any helpful thoughts are appreciated.

My setup couldn’t be simpler. Default apistar new . --framework wsgi. I’m working in a venv created with python3 -m venv .venv and apistar and zappa are both installed.

Apistar works locally but when deployed with zappa deploy dev I get

{'message': 'not found'}

My instance:
gonzo:~ gonzo$ https://rb3mc3nisa.execute-api.us-east-1.amazonaws.com/dev
HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Length: 24
Content-Type: application/json
Date: Fri, 18 Aug 2017 03:20:34 GMT
Via: 1.1 296faebadd40feee8b2eb0e10d5786d2.cloudfront.net (CloudFront)
X-Amz-Cf-Id: PlSiqJRDS56vRTuYnHPjRmBwesrrEI8K3jL1OIaL-tljShrr2Ro6Mw==
X-Amzn-Trace-Id: sampled=0;root=1-59965d02-45bbd2d7ca8af7fcb10322f0
X-Cache: Error from cloudfront
x-amzn-RequestId: 32a45b2b-83c4-11e7-b1c1-afadb0a116cc

{
    "message": "Not found"
}

Trace:
[1503026349547] [DEBUG] 2017-08-18T03:19:09.547Z fdcf6be4-83c3-11e7-8e57-bb793172ae75 Zappa Event: {'resource': '/', 'path': '/', 'httpMethod': 'GET', 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'CloudFront-Forwarded-Proto': 'https', 'CloudFront-Is-Desktop-Viewer': 'true', 'CloudFront-Is-Mobile-Viewer': 'false', 'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Is-Tablet-Viewer': 'false', 'CloudFront-Viewer-Country': 'US', 'Host': '6dehxb5go6.execute-api.us-east-1.amazonaws.com', 'User-Agent': 'python-requests/2.18.4', 'Via': '1.1 990c804118e679d7ea0f4d3ca3cc4534.cloudfront.net (CloudFront)', 'X-Amz-Cf-Id': '7bRHNmZQn8a5Rbtg01N9bOlWhzjctQsb-RenoeXtBMdg1EtBeOMxdw==', 'X-Amzn-Trace-Id': 'Root=1-59965ca9-17ea3d8563af6dfe79c03832', 'X-Forwarded-For': '174.52.136.231, 54.239.203.76', 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https'}, 'queryStringParameters': None, 'pathParameters': None, 'stageVariables': None, 'requestContext': {'path': '/dev', 'accountId': '023557941564', 'resourceId': 'alqabjmjil', 'stage': 'dev', 'requestId': 'fdbf3fb7-83c3-11e7-8aee-cb4012249b13', 'identity': {'cognitoIdentityPoolId': None, 'accountId': None, 'cognitoIdentityId': None, 'caller': None, 'apiKey': '', 'sourceIp': '174.52.136.231', 'accessKey': None, 'cognitoAuthenticationType': None, 'cognitoAuthenticationProvider': None, 'userArn': None, 'userAgent': 'python-requests/2.18.4', 'user': None}, 'resourcePath': '/', 'httpMethod': 'GET', 'apiId': '6dehxb5go6'}, 'body': None, 'isBase64Encoded': False}


#7

Are you sure your API just doesn’t have anything at the / route? What happens if you try other routes in your API? Message Not Found is the default, route not found message, meaning your APIStar routes have no / pattern


#8

Thanks for the response.

Routing was my first thought – given these lines:

And it’s still possible that’s the case but I still haven’t managed to get even the ‘hello world’ to work via lambdas even though it’s working locally via both apistar and gunicorn.

I’m using the WSGIApp and my app.py is almost idiot-proof… once this idiot gets it working then it truly will be.

my app.py:

from apistar import Include, Route
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.handlers import docs_urls, static_urls


def hello(name=None):
    return {'message': 'Welcome to API Star, %s!' % name}

routes = [
    Route('/hello', 'GET', hello),
    Include('/docs', docs_urls),
    Include('/static', static_urls)
]

app = App(routes=routes)


if __name__ == '__main__':
    app.main()

and for what it’s worth my zappa-settings.json – a nearly identical file works with flask so the permissions on the IAM user are working as expected.

"dev": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "zappadeploy",
        "s3_bucket": "zappa-pgrrzxv0h"
    }
}

This is deployed so you can see the result yourself here:

https://rb3mc3nisa.execute-api.us-east-1.amazonaws.com/dev/hello?name=david


#9

Seems like the issue is with your zappa deployment, perhaps the API Gateway routes were not correctly created or the IAM role needed did not have enough access to create all the necessary pieces in AWS for the whole thing to work.

Here is a discussion on the minimum policy requirements to successfully deploy

https://github.com/Miserlou/Zappa/issues/244


#10

It seems unlikely my problem is permissions. When I said my working zappa/lambdas deploy with flask is using a similar zappa-settings.json perhaps I understated. Only the s3 bucket is different.

For comparison this works with flask:

my flask app.py

from flask import Flask
from flask import jsonify

app = Flask(__name__)

@app.route("/hello")
def hello():
    return jsonify({"hello": "world"})

with this zappa-settings.json:

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "us-east-1",
        "profile_name": "zappadeploy",
        "s3_bucket": "zappa-ef176008k"
    }
}

NOTE: I’m using the exact same profile/IAM user as I am in the apistar attempt above.

And here’s the working flask endpoint:
https://dczwpjdxh3.execute-api.us-east-1.amazonaws.com/dev/hello

@Ryanar might you point me to an example apistar “hello world” you’ve got to run on lambdas via zappa?


#11

Hey @dgonzo I think its your “app_function” key, remove the if __name__ == 'main': app.main() and change your key to app.app.wsgi, my working repo is https://github.com/audiolion/das-profiles , don’t know if anything changed with the 0.2 release though, haven’t updated it yet.

I guess the if name == ‘main’ isn’t an issue, but the wsgi callable is app.wsgi and its inside the app file, which is why I put

app = App(...)
wsgi_app = app.wsgi

then in my zappa-settings.json

{
  "dev": {
    "app_function": "app.wsgi_app",
    ...
  }
}

#12

I am on 0.2 release.

The new WSGIApp should take the place of referencing wsgi as was done in 0.1.

At this point you’ve helped me confirm that I’ve done things sanely but that something is still not working.

AWS Lambda is a bit tricky. I’ll file an issue and if I can figure out any changes that will get this to work I’ll push them there.

Thanks again for your help.


#13

I am having the same issue. It has to do with the routes defined in app.py

Because AWS lambda gives you a url like this https://dczwpjdxh3.execute-api.us-east-1.amazonaws.com/dev/

APIstar as far as I can see does not take into account the /dev/ part when trying to match the route

i.e /hello should be defined as /dev/hello in routes

Still trying to figure out why this is happening.


#14

Thanks @pringlewood. Now resolved in version 0.2.3.


#15

The staticfiles still do not load when deployed to Lambda, so the /docs url looks a bit sparse when it loads. I guess there is a path issue in there as well. Will try and take a look at it later this week.


#16

Hrm, okay. I guess either a path issue, or the statics not being transferred across.


#17

I’m unable to get Zappa to work with the example app.

app.py

from apistar import Include, Route
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.handlers import docs_urls, static_urls


def welcome(name=None):
    if name is None:
        return {'message': 'Welcome to API Star!'}
    return {'message': f'Welcome to API Star, ${name}!'}


routes = [
    Route('/', 'GET', welcome),
    Include('/docs', docs_urls),
    Include('/static', static_urls)
]

app = App(routes=routes)

zappa_settings.json

{
  "dev": {
    "app_function": "app.app",
    "s3_bucket": "zappa-g5g2n1tp0",
    "aws_region": "us-east-1",
    "profile_name": "default",
    "keep_warm": false,
    "project_name": "iborrowdesk-dev"
  }
}

output of zappa tail dev

 Instancing..
[1505683199588] The 'MarkupSafe>=0.23' distribution was not found and is required by jinja2: DistributionNotFound
Traceback (most recent call last):
  File "/var/task/handler.py", line 505, in lambda_handler
  return LambdaHandler.lambda_handler(event, context)
  File "/var/task/handler.py", line 239, in lambda_handler
  handler = cls()
  File "/var/task/handler.py", line 131, in __init__
  self.app_module = importlib.import_module(self.settings.APP_MODULE)
  File "/var/lang/lib/python3.6/importlib/__init__.py", line 126, in import_module
  return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "/var/task/app.py", line 2, in <module>
  from apistar.frameworks.wsgi import WSGIApp as App
  File "/var/task/apistar/frameworks/wsgi.py", line 5, in <module>
  from apistar import commands, exceptions, hooks, http
  File "/var/task/apistar/commands/__init__.py", line 3, in <module>
  from apistar.commands.schema import schema
  File "/var/task/apistar/commands/schema.py", line 7, in <module>
  name: codec for name, codec in get_installed_codecs().items()
  File "/var/task/coreapi/utils.py", line 26, in get_installed_codecs
  pkg_resources.iter_entry_points(group='coreapi.codecs')
  File "/var/task/coreapi/utils.py", line 25, in <listcomp>
  (package, package.load()) for package in
  File "/var/task/pkg_resources/__init__.py", line 2290, in load
  self.require(*args, **kwargs)
  File "/var/task/pkg_resources/__init__.py", line 2307, in require
  items = working_set.resolve(reqs, env, installer)
  File "/var/task/pkg_resources/__init__.py", line 853, in resolve
  raise DistributionNotFound(req, requirers)

#18

Long shot: https://discuss.erpnext.com/t/getting-error-while-creating-a-new-bench-directory/23647/10

And MarkupSafe is installed?


#19

I am having this problem as well, I am quite sure this is a python 3 incompatibility issue.


#20

Anyone having luck with the interactive docs or serving static files with Zappa?
Zappa’s use of the stage name as a prefix on all endpoints looks like the culprit but I’m not sure how to approach it.