AWS LambdaのFunctionを開発するときのMakefile
自分用のメモ
lambda-uploaderみたいなものもありますが、LambdaだけならAWS CLIで十分簡単に操作出来るのでMakefileを用意してみました。
API Gatewayに関しては、AWS CLIでやろうとすると1つのリソースあたり3個ぐらいコマンドを叩く必要があったり、AWS CLIで操作できるものではない印象でした。 まだ管理画面触ってる方が楽だと思います。 自動化したいならAWS CLIではなく、CloudFormationやServerlessフレームワークみたいなもの(例: serverless(node), Zappa(python2))を使ったほうが良さそうです(こちらについては、今作ってるフレームワークがあるのでまた後日記事書きます)。
Help text
$ make Description: Quickly deployment tool for AWS Lambda. Requirements: - AWS CLI - jq Commands: deploy Deploy to AWS Lambda functions Show the list of AWS Lambda functions help Show help text invoke Run lambda function and show the result and the log. ls-bucket Show the files in S3 Bucket roles Show the list of IAM Roles undeploy Remove deploy package from s3 and Delete lambda function update Update Lambda function
Deploy
- deploy packageの作成
- deploy packageをs3にupload
- Lambda関数の登録
- input.jsonの中身をeventとして、Lambdaを呼び出す
- base64 encodeでログが送られてくるので、jqでパースして、base64 decode。
- 実行結果とログを保存して、表示
Makefile
Makefileは、ちゃんと書いたことがなかったので変な書き方してるかも。 何か変なところあれば教えてください。
.PHONY: help roles functions ls-bucket upload invoke undeploy deploy update LAMBDA_NAME := image-upload LAMBDA_HANDLER := lambda_image_upload.lambda_handler DESCRIPTION := "Upload image posted by multipart/form-data." TIME_OUT := 16 INPUT_PYFILE := lambda_image_upload.py ZIP_FILE_NAME := lambda_image_upload.zip INPUT_JSON := input.json OUTPUT_FILE := result.json LOG_FILE := invoke.log S3_BUCKET := lambda-packages S3_KEY := lambda_image_upload.zip IAM_ROLE_ARN := xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx REGION := ap-northeast-1 .DEFAULT_GOAL := help help: ## Show help text @echo "Description:" @echo " Quickly deployment tool for AWS Lambda." @echo "" @echo "Requirements:" @echo " - AWS CLI" @echo " - jq" @echo "" @echo "Commands:" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' roles: ## Show the list of IAM Roles aws iam list-roles | jq '.Roles | .[] | .RoleName, .Arn' functions: ## Show the list of AWS Lambda functions aws lambda list-functions | jq '.Functions | .[] | .FunctionName' ls-bucket: ## Show the files in S3 Bucket aws s3 ls s3://$(S3_BUCKET) $(ZIP_FILE_NAME): $(INPUT_PYFILE) ## Create deploy package zip -r $(ZIP_FILE_NAME) $(INPUT_PYFILE) upload: # Upload deploy package to S3 make $(ZIP_FILE_NAME) aws s3 cp $(ZIP_FILE_NAME) s3://$(S3_BUCKET)/ # See http://docs.aws.amazon.com/lambda/latest/dg/with-userapp-walkthrough-custom-events-invoke.html invoke: ## Run lambda function and show the result and the log. @aws lambda invoke \ --payload file://$(INPUT_JSON) \ --function-name $(LAMBDA_NAME) \ --log-type Tail \ $(OUTPUT_FILE) \ | jq -r '.LogResult' \ | base64 --decode \ > $(LOG_FILE) @echo "-- Result\n" @cat $(OUTPUT_FILE) @echo "\n\n-- Log\n" @cat $(LOG_FILE) @echo "" undeploy: ## Remove deploy package from s3 and Delete lambda function aws s3 rm s3://$(S3_BUCKET)/$(S3_KEY) aws lambda delete-function --function-name $(LAMBDA_NAME) # See https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-on-demand-https-example-upload-deployment-pkg.html deploy: ## Deploy to AWS Lambda make upload aws lambda create-function \ --function-name $(LAMBDA_NAME) \ --region $(REGION) \ --code S3Bucket=$(S3_BUCKET),S3Key=$(S3_KEY) \ --handler $(LAMBDA_HANDLER) \ --timeout $(TIME_OUT) \ --description $(DESCRIPTION) \ --runtime python2.7 \ --role $(IAM_ROLE_ARN) update: ## Update Lambda function make upload aws lambda update-function-code \ --function-name $(LAMBDA_NAME) \ --s3-bucket $(S3_BUCKET) \ --s3-key $(S3_KEY)
参考資料
- 作者: 大澤文孝
- 出版社/メーカー: インプレス
- 発売日: 2017/10/16
- メディア: Kindle版
- この商品を含むブログを見る
AWS LambdaとAPI Gatewayを触ってみたのでメモ
PyCon JP スプリントの時に id:iktakahiro さんがLambdaの話をしていたのですが、Lambda + API Gatewayは覚えとくと便利そうなので試してみた。
Lambdaを触ってみる
まずAPI Gatewayは考えずに、Lambdaを触ってみる。 調べてみたら、公式のドキュメントにも今やりたいことに似たものがあった。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example.html
事前に、下のことをしておいた。
- Lambda実行用のIAMロールを作成
- RoleType: AWS Lambda
- Policy: AWSLambdaFullAccess, AmazonS3FullAccess, AWSLambdaBasicExecutionRole
- S3のバケットを2つ用意。
- bucketとlambdaは同じリージョンに作る
hoge-image-source
: 直接アップロードされた画像hoge-image-resized
: Lambdaによってサイズを変更した画像
image-resized
にtest.jpg
という画像データを保存- Lambdaの動きを確認する時に、
test.jpg
がcreatedされたというサンプルイベントデータを渡す。
- Lambdaの動きを確認する時に、
デプロイパッケージを作成
Pillowみたいなサードパーティのライブラリを使うときは、それらを一緒にzipに固めたデプロイパッケージを作る。
デプロイパッケージに含めるものは、 id:iktakahiro さんいわく ./vendors
に入れておくのがいいらしいのでとりあえず真似してみる。
$ virtualenv -p python2.7 venv # Python3使えないので注意 $ source venv/bin/activate $ pip install pillow -t ./vendors $ ls vendors/ PIL Pillow-3.3.1.dist-info
ただ、この方法はPillowとか使う場合うまくいかなかった。
Unable to import module 'lambda_function': /var/task/PIL/_imaging.so: invalid ELF header
ではまった。どうやらMacでビルドするのが行けないらしい。 Amazon LinuxのインスタンスをEC2で立ち上げてビルドした。 Dockerでうまくビルド出来るようにすると楽になれそう。
@c_bata_ あー Pillow は駄目だねぇ。軽く使いたいだけならこういうのもあるけどね https://t.co/tMtbYU6oxB
— Takahiro Ikeuchi (@iktakahiro) October 2, 2016
こういうビルド済みのファイルを提供しているリポジトリもあるらしい。
コードを書く
thumbnail-generator.py
from __future__ import print_function import boto3 import os import sys import uuid from PIL import Image s3_client = boto3.client('s3') RESIZED_BUCKET_NAME = 'hoge-image-resized' RESIZED_IMAGE_SIZE = (200, 100) def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(RESIZED_IMAGE_SIZE) image.save(resized_path) def lambda_handler(event, context): for record in event['Records']: bucket = record['s3']['bucket']['name'] key = record['s3']['object']['key'] download_path = '/tmp/{}{}'.format(uuid.uuid4(), key) upload_path = '/tmp/resized-{}'.format(key) s3_client.download_file(bucket, key, download_path) resize_image(download_path, upload_path) s3_client.upload_file(upload_path, RESIZED_BUCKET_NAME, key)
アップロード
10MB以上なら、S3を経由してUploadする必要がある。 10MB以下なら、Lambdaの設定画面からUpload出来る。
ログ
こんな感じでグラフ化されている。 それぞれの詳細のログも見れるので、確認したい項目はprintしておけばいいみたい。
動作確認
AWS CLIを使う方法とかもあるけど、ブラウザ上のTestボタンを押す方法が一番手軽な感じ。 CIの導入とかuploadからtestまで一発でやりたくなったら、AWS CLIを使う方法を試して追記。
Testボタン
事前に test.jpg
をアップロード済みなので、ブラウザからS3のPutイベントを発生させてみる。
管理画面でTestって名前がついた青いボタンがあるのでそれを押す。
awsRegionとbucketのarn, name, objectのkeyを変えて実行。
- awsRegion: ap-northeast-1
- s3 > object > key:
test.jpg
- s3 > bucket >
arn: arn:aws:s3:::hoge-image-source
- s3 > bucket >
name: hoge-image-source
ログを見ながらデバッグ。
うまくいくと、 hoge-image-resized
の方にサムネイルが生成されている。
Github
成果物
API Gateway
API Gatewayで画像のアップロード用APIを作りたい。 POSTで画像を受け取って、S3へアップロード、URLを返す。
リクエストの形式
まずリクエストのヘッダやボディがAPI Gateway経由でどのように渡されるのか確認する。 あとで気づいたのだけれど、API Gateway AWS ProxyのSample event templateを見ればわかった。
{ "body": "{\"test\":\"body\"}", "resource": "/{proxy+}", "requestContext": { "resourceId": "123456", "apiId": "1234567890", "resourcePath": "/{proxy+}", "httpMethod": "POST", "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", "accountId": "123456789012", "identity": { "apiKey": null, : (中略) }, "stage": "prod" }, "queryStringParameters": { "foo": "bar" }, "headers": { "Accept-Encoding": "gzip, deflate, sdch", : (中略) }, "pathParameters": { "proxy": "path/to/resource" }, "httpMethod": "POST", "stageVariables": { "baz": "qux" }, "path": "/path/to/resource" }
うん、とても分かりやすい。 楽をさせるために、request bodyはunicodeで渡されるらしい。
2016/10/04 削除
ここに色々書いてたのですが、文字列についてだいぶ大きな勘違いをしてました。 unicode形式だと画像とかファイルは受け取れないと思ってたんですが、普通にencodeすればいいだけなんですね。
レスポンスの形式
知らずにはまったんだけど、レスポンスは次の形式で返す必要がある。
よくよく考えたら、Hello World
みたいに文字列返すだけだとステータスコードとヘッダ渡す場所がないので当たり前だった。
from __future__ import print_function def lambda_handler(event, context): return { "statusCode": 200, "headers": {"headerName": "headerValue", "Foo": "bar"}, "body": "This is body" }
所感・メモ
Lambda
- Pythonは2系のみ
- 300秒まで使える
- バッチ処理とかだと厳しい場合が結構ありそう
- EC2立ち上げる人もいるらしい
- Lambda Functionはバージョニング可能
- VPC対応あり
- CloudWatch EventsのScheduleで定期実行できる
- 勝手にスケールしてくれる
API Gateway
リクエストの情報をかなりラップして渡してくれていて、手軽。
- リクエストのpayloadサイズに10MBの上限がある。画像とかファイルアップロードするときは厳しい
- 結構分かりやすい形式でLambdaにリクエストの情報を送ってくれる
- レスポンスの形式も明確
References
- AWS Lambda で本番/検証環境を切り替える - Librabuch
- Python で パッケージを vendoring しつつ AWS Lambda へデプロイ - Librabuch
- Amazon S3 プロキシとして API を作成する - Amazon API Gateway
- ステップ 2.3: Lambda 関数を作成し、手動でテストする - AWS Lambda
- Amazon API Gatewayが非常に便利なHTTPプロキシとして進化したらしいので使ってみた - Qiita
Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく (Informatics&IDEA)
- 作者: NRIネットコム株式会社,佐々木拓郎,佐藤瞬,石川修,高柳怜士,佐藤雄也,岸本勇貴
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2016/04/20
- メディア: 単行本
- この商品を含むブログ (1件) を見る
#pyconjp でWeb(WSGI)フレームワークの作り方について話してきました
昨年のPyConJPでは pandas-validator について話していたのですが、今回はトークセッションをしてきました。 Twitter見てると早速スライドを見ながら実装してくださってる方もいらっしゃって嬉しいかぎりです。
日本語のWSGIフレームワークの作り方の資料としては最もまとまっているものになっていると思うので、ぜひご活用ください。
基礎から学ぶWebアプリケーションフレームワークの作り方
WSGIの解説から始まり、ルーティング・リクエスト・レスポンス・HTMLテンプレートやミドルウェアについて順番に解説しながら、ボトムアップでフレームワークを作り上げていく話をしてきました。
半分ライブコーディングみたいな形だったので、少し不安もありました。 もう少しこうやればスムーズだったかなと反省点も少しありますが、スライドとかTogetterまとめがホッテントリ入りしていたらしく、周りからの反響もよくて一安心です。
動画
2_04 基礎から学ぶWebアプリケーションフレームワークの作り方
スライド
Togetterまとめ
GitHub - c-bata/webframework-in-python: "How to develop WSGI WEB Framework" talked at PyConJP 2016
明日はマイクロソフト社さんのオフィスで、PyConJPのスプリントがありますが会場にいるので、もし質問とかあればお声がけください。
remark.js の紹介
少し話がそれるのですが、資料作りにあたって、 Remark.js が素晴らしかったので紹介。
このように
shift + c
で新しいWindowを開くshift + p
でプレゼンテーションモードに変更
するとうまく同期してくれます。 reveal.jsだと発表者ノートを表示するためにwebsocketのサーバを立ち上げないといけませんが、こちらは必要ありません。Github Pagesでも上のスライドのリンクのようにそのまま動かせます。
最高です。
全体的な感想
- 1日目のパーティで沢山の方にお声がけいただけました。有名人になれたみたいで嬉しかったです。このブログすごい参考にしてますと言ってくださる方もいらっしゃったのでしっかり更新続けないとなと思いました
- スピーカーパーティの時にPyDataの山本さんという方とお話したのですが、xgboostや競馬予測に関して本当に面白い話をお聞きすることができました。データ系に詳しい参加者がたくさんいて、普段Webをやっている人間もデータ系の全く知らなかった話を知っていけるのは、Pythonのカンファレンスならではですね。
- 非同期に関して色々と知りたいこと・よく分かってないことが多いのですが、スピーカーパーティの時にjbkingさんからめちゃくちゃ丁寧な解説をいただきました。本当に面白くてコードを書くモチベーションがめちゃくちゃ高くなってしまった。
- 来年は非同期で高速なWebフレームワークに関して発表したい
以上、おつかれさまでした。
- 作者: Michal Jaworski,Tarek Ziade,稲田直哉,芝田将,渋川よしき,清水川貴之,森本哲也
- 出版社/メーカー: KADOKAWA
- 発売日: 2018/02/26
- メディア: 単行本
- この商品を含むブログを見る