serverlessとLambda


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で使用可能な言語


Lambdaの主な制限

  • package size
    • 250MB(Layer含む)
    • 50MB(Layer含まない)
  • functionのtimeout
    • 900秒(15分)
  • accountごとの同時実行数
    • 1000

アーキテクチャ設計における優先順位(推奨)

  1. LambdaでできることはLambda(faas)でやる
  2. Lambdaでできない(もしくは難しい)なら、ECSやsagemakerなどmanagedなコンテナ技術を使う
  3. それでも難しい場合は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を共通化できる)
  • 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
  ...

時間があったらdemoします