Edited at

Python サーバーレスフレームワークの比較 - Zappa vs Chalice

More than 1 year has passed since last update.


はじめに

この記事は、Serverless(2) Advent Calendar 2016 23日目の記事です。


Python サーバーレスフレームワーク

Pythonでサーバレスなアプリケーションを開発するためのフレームワークとしては、以下の2つが人気のようです。

今回はこの2つをざっくり比較してみます。

ちなみにNode.jsを使用するのであれば、Serverless FrameworkApexが有名です。

他にどういったサーバーレスフレームワークがあるかについては、以下のスライドが参考になります。

Unlimited Frameworks


chalice

Python Serverless Microframework for AWS


  • Amazon製だけあってAWS専用のフレームワーク

  • 簡単に開発できるように設計されていて、FlaskやBottoleのようなデコレータベースの軽量フレームワーク

  • IAMポリシーを自動生成してくれる

  • GatewayとLambda全てのAPIを網羅していない

  • S3やDynamoDBなどの他のAWSリソースへのアクセスもできない

  • API Gatewayに特化している

用意してあるコマンドはこれだけ。

Commands:

deploy
gen-policy
generate-sdk
local
logs
new-project
url

実際のchaliceを使ったソースコードをHow to create a thumbnail API service with AWS Lambdaを参考にみてみます。

写真をPOSTで受け取ってサムネイルを生成する処理をapp.pyが行なってます。

import base64

import uuid
from subprocess import Popen, PIPE

import boto3
from chalice import BadRequestError, Chalice

app = Chalice(app_name='thumbnail-service')
app.debug = True # TODO: Disable on production

S3 = boto3.client('s3')
S3_BUCKET = '' # TODO: Replace with valid bucket name

@app.route('/', methods=['POST'])
def index():
body = app.current_request.json_body

image = base64.b64decode(body['data'])
format = {'jpg': 'jpeg', 'png': 'png'}[body.get('format', 'jpg').lower()]
mode = {'max': '', 'min': '^', 'exact': '!'}[body.get('mode', 'max').lower()]
width = int(body.get('width', 128))
height = int(body.get('height', 128))

cmd = [
'convert', # ImageMagick Convert
'-', # Read original picture from StdIn
'-auto-orient', # Detect picture orientation from metadata
'-thumbnail', '{}x{}{}'.format(width, height, mode), # Thumbnail size
'-extent', '{}x{}'.format(width, height), # Fill if original picture is smaller than thumbnail
'-gravity', 'Center', # Extend (fill) from the thumbnail middle
'-unsharp',' 0x.5', # Un-sharpen slightly to improve small thumbnails
'-quality', '80%', # Thumbnail JPG quality
'{}:-'.format(format), # Write thumbnail with `format` to StdOut
]

p = Popen(cmd, stdout=PIPE, stdin=PIPE)
thumbnail = p.communicate(input=image)[0]

if not thumbnail:
raise BadRequestError('Image format not supported')

filename = '{}_{}x{}.{}'.format(uuid.uuid4(), width, height, format)
S3.put_object(
Bucket=S3_BUCKET,
Key=filename,
Body=thumbnail,
ACL='public-read',
ContentType='image/{}'.format(format),
)

return {
'url': 'https://s3.amazonaws.com/{}/{}'.format(S3_BUCKET, filename)
}


Zappa

Serverless Python Web Services


  • WSGIアプリケーションをデプロイする

  • なのでchaliceと違って、AWS以外のクラウドにも対応可能

  • 多機能なフルスタックなフレームワーク

  • "ハイブリッド"アプリケーションに必要となる、AWSイベントソース全てを自動サポート

それではchalice同様に、POSTで受け取った写真のサムネイル生成を行うアプリケーションをBuilding Serverless Microservices with Zappa and Flask - Gun.ioを参考にみてみます。

import base64

import boto3
import calendar
import io

from datetime import datetime, timedelta
from flask import Flask, request, render_template
from PIL import Image

s3 = boto3.resource('s3')
BUCKET_NAME = 'your_public_s3_bucket'

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
new_file_b64 = request.form['b64file']
if new_file_b64:

# Decode the image
new_file = base64.b64decode(new_file_b64)

# Crop the Image
img = Image.open(io.BytesIO(new_file))
img.thumbnail((200, 200))

# Tag this filename with an expiry time
future = datetime.utcnow() + timedelta(days=10)
timestamp = str(calendar.timegm(future.timetuple()))
filename = "thumb.%s.jpg" % timestamp

# Send the Bytes to S3
img_bytes = io.BytesIO()
img.save(img_bytes, format='JPEG')
s3_object = s3.Object(BUCKET_NAME, filename)
resp = s3_object.put(
Body=img_bytes.getvalue(),
ContentType='image/jpeg'
)

if resp['ResponseMetadata']['HTTPStatusCode'] == 200:

# Make the result public
object_acl = s3_object.Acl()
response = object_acl.put(
ACL='public-read')

# And return the URL
object_url = "https://{0}.s3.amazonaws.com/{1}".format(
BUCKET_NAME,
filename)
return object_url, 200
else:
return "Something went wrong :(", 400

return render_template('upload.html')

chaliceと違ってWSGIアプリケーションをデプロイできるので、写真アップロード画面なども一緒に用意できます。

またAWSイベントソースを利用することで、S3へのアップロードをフックにサムネイル処理をノンブロッキングに実行することもできます。

# zappa_settings.yml

---
dev:
app_function: your_project.main.app
events:
- function: your_project.users.thumbnailer
event_source:
arn: arn:aws:s3:::your_public_s3_bucket
events:
- s3:ObjectCreated:*

# your_project/users.py

import Pillow

def thumbnailer(event, context):
""" Upon PUT, thumbnail! """

# Get the bytes from S3
in_bucket = event['Records']['s3']['bucket']['name']
key = event['Records']['s3']['object']['key']
image_bytes = s3_client.download_file(in_bucket, key, '/tmp/' + key).read()

# Thumbnail it
size = (250, 250)
thumb = ImageOps.fit(image_bytes, size, Image.ANTIALIAS)

# Put it back on S3
s3_client.put_object(
ACL='public-read',
Body=thumb,
Key=key + 'thumbnail.jpg',
Bucket='avatar-bucket')

詳しくはServer-less Framework Comparison - Zappa Versus Chaliceを参照してください。


参考にしたもの


おわりに

Top 10 Python libraries of 2016 - Tryolabs BlogでもZappaが1位に輝いているように、2016年12月の時点ではchaliceよりもZappaの方が人気があるようです。

しかしここで見てきたように2つのフレームワークは特徴がはっきりしていて差別化されています。

用途に合わせて使い分けることで、Pythonサーバーレスフレームワーク界隈が盛り上がっていくといいですね。