2019年2月1日金曜日

Serverless Framework 使ってみた

概要

Serverless Framework は AWS lambda のような Function as a Service を制御することができるツールです
同じようなツールに SAM などがあります
AWS の他にも Azure Functions や Google Cloud Functions を制御することができます
今回は AWS lambda を serverless コマンドを使って制御してみました

環境

  • serverless 1.36.3

serverless のインストール

  • npm install -g serverless

執筆時点では homebrew にもありましたが公式が npm なので一応 npm でインストールしました

サービスの作成

  • serverless create --template aws-ruby --path my-service

デプロイする

  • serverless deploy -v

これで CloudFormation と S3 および lambda にデプロイできます

自分は aws-cli の設定をすでに行っていたので特に認証などは聞かれませんでしたがもしかすると設定しないとエラーになるかもしれません
ログを見るとわかりますが SAM を使って lambda にパッケージをデプロイする手順と同様で CloudFormation にスタックを作成し S3 にアップロードし関数を lambda に登録しています

ログは以下の通りです

(node:15694) ExperimentalWarning: The fs.promises API is experimental
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
CloudFormation - CREATE_IN_PROGRESS - AWS::CloudFormation::Stack - my-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::CloudFormation::Stack - my-service-dev
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (266 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - my-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_COMPLETE - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersionenksLCJimutTnYkvXQRxsj92mdxvgp6T4iHWfW8IcvA
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersionenksLCJimutTnYkvXQRxsj92mdxvgp6T4iHWfW8IcvA
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersionenksLCJimutTnYkvXQRxsj92mdxvgp6T4iHWfW8IcvA
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - my-service-dev
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - my-service-dev
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: us-east-1
stack: my-service-dev
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  None

Stack Outputs
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:370162190418:function:my-service-dev-hello:1
ServerlessDeploymentBucketName: my-service-dev-serverlessdeploymentbucket-t8k07ycfl0of

デフォルトのリージョンは us-east-1 になっているようです

関数を実行する

  • serverless invoke -f hello

これで lambda に登録した関数を実行できます
JSON が返ってくれば OK です

  • serverless logs -f hello -t

で関数のログを監視することもできます

API Gateway トリガーと連携する

serverless.yaml を少し修正します

  • vim serverless.yml
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: users/create
          method: POST

events の部分がコメントになっているのでコメントアウトしましょう
特定のパスに POST でアクセスできるようにします
わかりやすくするため handler.rb も修正しましょう

  • vim handler.rb
require 'json'

def hello(event:, context:)
  begin
    raise if event['body'].nil?
    { statusCode: 200, body: JSON.generate(event['body']) }
  rescue StandardError => e  
    { statusCode: 400, body: JSON.generate("missing body") }
  end
end

リクエストボディに body がない場合は 400 が返ってくるようにします

再デプロイ

  • serverless deploy -v
Service Information
service: my-service
stage: dev
region: us-east-1
stack: my-service-dev
api keys:
  None
endpoints:
  GET - https://g66hn8ycj7.execute-api.us-east-1.amazonaws.com/dev/users/create
functions:
  hello: my-service-dev-hello
layers:
  None

一部抜粋ですが endpoints が新たに表示されています
ここにアクセスして動作確認してみましょう

  • curl -X POST -d "hawk" https://g66hn8ycj7.execute-api.us-east-1.amazonaws.com/dev/users/create

これで -d に指定した値が返ってくれば成功です
また -d がない場合にエラーのメッセージが返ってくることも確認しましょう

クリーンアップ

  • serverless remove

これで CloudFormation 経由で S3 および lambda のリソースが削除されます
CloudFormation のスタックも削除してくれるようです

おまけ: ローカルで function のテストをするには

今回で言えば handler.rb のテストです
今回のケースのように簡単な処理であれば問題ないですが、普通に考えれば deploy する前にテストしたいものです

例えば以下のようにローカルテスト用のスクリプトを書いてユニットテストしたりできます

  • touch handler_test.rb
  • vim handler_test.rb
require './handler.rb'
require 'test/unit'

class TestHandler < Test::Unit::TestCase
  def test_200()
    response = hello(event: {'body' => 'hoge'}, context: {})
    assert_equal 200, response[:statusCode]
    assert_match /hoge/, response[:body]
  end
  def test_400()
    response = hello(event: nil, context: {})
    assert_equal 400, response[:statusCode]
    assert_match /missing body/, response[:body]
  end
end
  • ruby handler_test.rb

最後に

Serverless Framework を使って AWS lambda を制御してみました
lambda を直接使った際の煩わしさはないかなと思います
ただ使う場合には lambda の動きを理解していないと厳しいと思います

今回はトリガー (API Gateway) との連携も行いました
Layers の機能も扱えるようなので lambda の機能はほぼ使えると思います

SAM と比較すると定義ファイルを YAML で記述する点は変わりません
機能的にもほぼ同じなのでどちらを使っても良いかなと思います
Serverless Framework を使えば、lambda 以外の FaaS も制御できるのでやはりその点が大きいかなと思います

参考サイト

0 件のコメント:

コメントを投稿