SAM-CLIでサーバーレスアプリケーション① - プロジェクトの作成とローカルでテスト実行 -

サーバーレスアプリケーションとは
バックグラウンドで処理をするアプリケーション(いわゆるLambda関数)

SAM-CLIとは
AWSの提供するクライアント用SAMコマンド(Serverless Application Model - Client)
ローカルでサーバーレスアプリケーションの作成やAWSへのデプロイができる
また、Dockerと組み合わせればローカルでのテスト実行が可能

公式の詳細は以下
https://aws.amazon.com/jp/serverless/sam/

Qiitaの参考記事
https://qiita.com/te20/items/5a28cef4966c75886218

この記事ではSAM-CLIを使ってLambda関数をローカルで実行する手順を紹介します。

プロジェクト作成

$ sam init
以下のような構成でファイルが作られる。
sam-app/
├── README.MD
├── event.json
├── hello-world
│ └── app.js
│ └── package.json
│ └── tests
│ └── unit
│ └── test-handler.js
├── template.yaml
※もちろんオプションによりプロジェクトの細かい設定が可能
※デフォルトで言語はnode.jsが選択される(この記事でもnode.jsを使用)
言語の選択
--runtime [識別子] で言語を選択可能、以下の識別子が利用できる
  • 名前(言語) → 識別子
  • Node.js 10(Node.js) → nodejs10.x
  • Node.js 8.10(Node.js) → nodejs8.10
  • Python 3.6(Python) → python3.6
  • Python 3.7(Python) → python3.7
  • Python 2.7(Python) → python2.7
  • Ruby 2.5(Ruby) → ruby2.5
  • Java 8(Java) → java8
  • Go 1.x(Go) → go1.x
  • .NET Core 2.1(C#) → dotnetcore2.1
  • .NET Core 1.0(C#) → dotnetcore1.0

app.js

app.jsの内容が以下
S3やSQSなどをトリガーにして、バックグラウンドで以下の処理が走るイメージ
引数のeventでS3なら生成されたオブジェクト、SQSならキューに積まれた内容が取得できる
exports.lambdaHandler = async (event, context) => {
    try {
        response = { 
            'statusCode': 200,
            'body': JSON.stringify({
                message: 'hello world',
            })  
        }   
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};

template.yaml

Lambda関数の設定などをこのファイルに記述する
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs10.x
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn
ResoucesのEventsにLambda関数のトリガーを設定できるはずが、うまく行かなかった...
やりたいことは「S3の既存バケットにオブジェクトが生成された時」をトリガーにしたかったが、既存のバケットを指定するとデプロイの時にこけてしまう。
デプロイ後にAWS上からトリガーを手動で設定することで対応した。

ここではローカルでテストするために、APIによりLambda関数を実行する設定のみを入れておく。(→Events.HelloWorld)
このAPIの設定はデフォルトで入っているが、本来セキュリティの観点から、特に理由がない限り閉じておくのが吉

Outputsは、デプロイの時にコンソールに表示されるログ。特に必要ないので消してしまってもOK

ローカルで実行してみる

$ cd sam-app
$ sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
template.yamlのディレクトリで sam local start-api コマンドを実行するとサーバーが立ち上がる。
Dockerでnginxが起動して入れば、そのままLambda関数を実行できる。
実行するためのAPIも教えてくれるのでそのまま叩いてみる。

$ curl -i http://127.0.0.1:3000/hello
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 25

{"message":"hello world"}
Lambda関数が実行される。
この時、SAM-CLI側のコンソールでは以下のようなログ(CloudWatchに出力されるやつ)が出力される。
Invoking app.lambdaHandler (nodejs10.x)

Fetching lambci/lambda:nodejs10.x Docker container image......
Mounting sam-app/hello-world as /var/task:ro,delegated inside runtime container
(CloudWatch↓)
START RequestId: [xxxxx-xxxxx] Version: $LATEST
END RequestId: [xxxxx-xxxxx]
REPORT RequestId: [xxxxx-xxxxx] Duration: 9.94 ms   Billed Duration: 100 ms Memory Size:
(CloudWatch↑)
 128 MB Max Memory Used: 42 MB  
No Content-Type given. Defaulting to 'application/json'.
127.0.0.1 - - [YYYY-MM-DD HH:MM:SS] "GET /hello HTTP/1.1" 200 -
勝手にDockerコンテナにマウントしてくれるので楽です。

この記事へのコメント

スポンサーリンク