serverlessとLambda
話すこと
- lambdaでできること
- serverless frameworkでできること
Lambdaのusecase
- web application
- 定期的なtask処理
- Event処理
Faas
- Function as a serviceの略
- AWS Lambdaが一番有名なFaasだが他にもいっぱいある
- cloud functions(GCP)
- Azure Functions(microsoft)
Lambdaで使用可能な言語
- aws公式でサポートしている言語
- node
- Python
- Ruby
- Java
- golang
- 基本何でも動く
- custom runtimeを使えば何でも
- https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtimes-custom.html
- lambdaでRustを動かしている事例もあり
Lambdaの主な制限
- package size
- 250MB(Layer含む)
- 50MB(Layer含まない)
- functionのtimeout
- 900秒(15分)
- accountごとの同時実行数
- 1000
アーキテクチャ設計における優先順位(推奨)
- LambdaでできることはLambda(faas)でやる
- Lambdaでできない(もしくは難しい)なら、ECSやsagemakerなどmanagedなコンテナ技術を使う
- それでも難しい場合はec2を選択
Common problems
- package sizeが大きくなってしまい50MBに収まらない
- numpyやpandasのようなpackageを使う際によく起きる
- 後述のlayerである程度解決
- 一つのfunctionで同時実行数を専有してしまい、他のfunctionが動かない
- cross compile問題
- macでinstallしたpackageをそのままdeployしても動かない
- lambdaが動作しているamazon linux用のbuildが必要
LambdaのCost
- request
- 1000000件/0.20 USD で、無料利用枠は 1 か月に1000000
- compute
- 1GB-秒につき 0.00001667 USD で、無料利用枠は 400000GB-秒
- 1GBのmemoryなら400000/86400=4.62962963なので4-5日間は絶えず処理していても無料
Lambda layer
- 2018年のre:inventで発表された機能
- lambda functionを機能単位でlayerに切り出せる
- これまであったfat moduleの容量問題はこれで解決
- 1 functionにつけられるlayerは5まで
Layer前
Layer後
Frameworkがやってくれること
- faasのorchestration
- faasといっても、functionだけでsystemが成立することはほぼありえない
- web applicationでもendpointだったりstorageだったりが必要になる
各種Framework
- AWS SAM
- zappa
- Apex
- serverless framework
AWS SAM
- AWSが公式で提供しているFramework
- Serverless Application Model
- iaasにおけるterraformとcloudformationの関係性に近い
zappa
- aws で serverless python web serviceを実現するflaskベースのOSSフレームワーク
- apigateway + LambdaのよくあるパターンをFlaskで書く
- GCPは対応していない
- 事例があんま多くなさそう
Apex
- Lambdaのorchestration tool
- 面白い機能として、terraform integrationがある
- apex infra applyでterraformを実行できる
- 事例があんま多くなさそう
- No longer maintainedと書いてありもう長くなさそう、、
serverless framework
serverless frameworkのいいところ
- コミュニティが強力
- ググれば情報がたくさん出てくる
- pluginが多数あり、大抵のことはpluginを使えば実現できる
- いざというときは自分でpluginを作ればいい
- serverlessはnode製なのでnodeで実装
- eventから処理までがseamlessに書ける
- lambda+api gatewayというよくある組み合わせを爆速で作れる
get start
$ npm install -g serverless
$ sls create -t aws-python3
serverless frameworkのyamlに書けること
- provider
- 環境変数
- iam role
- cloudformationのstack
- custom
- layer
- function
provider
provider:
name: aws
runtime: python3.7
stage: ${opt:stage, self:custom.defaultStage}
environment: ${file(config/environments/${self:provider.stage}.yml)}
region: ${self:provider.environment.REGION}
timeout: ${self:provider.environment.TIMEOUT, "120"}
memorySize: ${self:provider.environment.MEMORY_SIZE, "256"}
# bucketの設定だが、serverSideEncryptionはserverless-deployment-bucketが必要
deploymentBucket:
name: ${self:provider.stage}-${self:service}-deployment
serverSideEncryption: AES256
iamRoleStatements:
- Effect: "Allow"
Action:
- "iam:ListAccountAliases"
Resource: "*"
function
- 呼び出す関数とその発火するeventを定義
- eventから処理までseamlessに書ける
function
# spotのeventを処理する
ec2_spot:
handler: handlers/main.spot_notify
events:
- cloudwatchEvent:
event:
source:
- "aws.ec2"
detail-type:
- "EC2 Spot Instance Interruption Warning"
# 定期的に処理する
cost_service:
handler: handlers/main.cost_notify
events:
- schedule: "cron(0 0 2 * ? *)"
function
def spot_notify(event, context):
instance_id = event.get("detail").get("instance-id")
...
return
def cost_notify(event, context):
...
return
- eventの中にserviceから送信される情報が入っている
ここまで書くとlocalで関数をdebug実行可能
$ sls invoke local --function ${関数名} -d '${callbackされるjson}'
- 静的言語だとできない模様(javaとか)
custom
- yaml内で使う変数の定義
- ${self:custom.XXXXX}でyaml内で参照できる
- pluginの設定
custom
custom:
defaultStage: dev
pythonRequirements:
...
localstack:
...
rust:
...
Layer
layers:
lib:
name: ${self:service}-lib-lambda-layer-${self:provider.stage}
path: layers/lib
package:
exclude:
- 'python/lib/__pycache__/**'
func_a:
handler: handlers/hoge.func_a
layers:
# ↑で独自で作ったlayer
- {Ref: LibLambdaLayer}
# serverless-python-requirementsが自動で作ってくれるlayer
- {Ref: PythonRequirementsLambdaLayer}
...
鉄板のplugin
- serverless-python-requirements
- pipの管理をうまくやってくれる
- requirements.txtからzipを生成してくれたり
- pipenvにも対応している
- layer化すると便利(packageを共通化できる)
- pipの管理をうまくやってくれる
- serverless-offline
- apigateway+lambdaに類似したセットをlocalで実行できる
- serverless-iam-roles-per-function
- lambda関数ごとに権限を分離できる
その他の使ってるplugin
- serverless-deployment-bucket
- deployに必要なbucketの暗号化
- serverless-rust
- serverlessでrustのcodeをbuild, deployしてくれる
- serverless-localstack
- localstack(仮想aws)を使ったtestを実行
web apiを作る際の組み合わせ例
awsgiとflaskでweb api(yaml)
functions:
flask:
handler: handlers/flask.handler
events:
- http:
path: /{any+}
method: ANY
awsgiとflaskでweb api(コード)
import awsgi
from flask import (
Flask,
jsonify,
)
app = Flask(__name__)
@app.route('/index')
def index():
return jsonify(status=200, message='OK')
@app.route('/submit', methods=['POST'])
def submit():
return request.get_data()
def handler(event, context):
return awsgi.response(app, event, context)
awsgiとflaskでweb api
- ANYにすることで、許可するpathやmethodをApplication側でハンドリングできる
- Lambda関数を量産する必要がない
- local開発ではserverless-offlineを使えばapi gatewayのendpointをlocalで起動できる
- RestのAPIを作る場合はこれが一番ラクだと思う
- もちろんgraphqlも使える
plugins:
- serverless-python-requirements
- serverless-offline
...