Cloud9でLambda Layerに依存するJavaのLambdaをローカル実行する

今回、Cloud9上でLambda Layerに依存するJavaのLambdaをローカルで実行する機会があったので、その方法を紹介します。
2020.10.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Cloud9でJavaのLambdaを開発する際に、ちょっとLambdaを実行してみて動作確認をしたいことがよくありました。

しかし、動作確認のたびにLambdaを再デプロイするのは面倒くさいです。
そこで、 SAM(Serverless Application Model) を利用すれば、Lambdaのローカル実行が可能です。

今回、Cloud9上でLambda Layerに依存するJavaのLambdaをローカルで実行する機会があったので、その方法を紹介します。

前提

Cloud9でJavaのLambdaをデプロイする環境は、先日書いたブログと同様の環境がすでに構築されていることを前提にします。

また、SAMでDockerを利用する関係上、Dockerイメージをローカルにダウンロードするたディスク容量がそれなりに必要です。 デフォルトの8GBだと不足する可能性があります。

その場合、次のブログを参考にしてディスクサイズを拡張してください。

Layerを含むLambdaのローカル実行イメージ

SAMの sam local invoke コマンドを利用することで、Lambdaをローカル実行できます。

Lambda Layerを含むLambdaも同じ様にローカル実行できますが、次の図のようにLayer部分だけはデプロイされているLambda Layerを参照してローカルホストにキャッシュします。 そのため、Lambdaのローカル実行したい場合、依存するLambda Layer部分は先にデプロイしておく必要があります。

SAMテンプレートの修正

Lambda Layerに依存するLambdaをローカル実行したい場合、SAMテンプレートのLayerの指定に !Ref 組込み関数は使うとうまくいきません。 ARNを直接指定する必要があります。

template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Lambda application that calls the Lambda API.
Resources:
  function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/distributions/blank-java.zip
      Handler: example.Handler::handleRequest
      Runtime: java11
      Description: Java function
      MemorySize: 512
      Timeout: 10
      # Function's execution role
      Policies:
        - AWSLambdaBasicExecutionRole
        - AWSLambdaReadOnlyAccess
        - AWSXrayWriteOnlyAccess
        - AWSLambdaVPCAccessExecutionRole
      Tracing: Active
      Layers:
        - !Ref libs
  libs:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: blank-java-lib
      Description: Dependencies for the blank-java sample app.
      ContentUri: build/blank-java-lib.zip
      CompatibleRuntimes:
        - java11

デプロイされたLambda LayerのARNはマネジメントコンソール等で確認してください。

そしてSAMテンプレートのLambdaが依存するLayerをARNでの指定に変更します。

template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Lambda application that calls the Lambda API.
Resources:
  function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/distributions/blank-java.zip
      Handler: example.Handler::handleRequest
      Runtime: java11
      Description: Java function
      MemorySize: 512
      Timeout: 10
      # Function's execution role
      Policies:
        - AWSLambdaBasicExecutionRole
        - AWSLambdaReadOnlyAccess
        - AWSXrayWriteOnlyAccess
        - AWSLambdaVPCAccessExecutionRole
      Tracing: Active
      Layers:
        # - !Ref libs
        - 'arn:aws:lambda:ap-northeast-1:123456789012:layer:blank-java-lib:8'
  libs:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: blank-java-lib
      Description: Dependencies for the blank-java sample app.
      ContentUri: build/blank-java-lib.zip
      CompatibleRuntimes:
        - java11

Lambdaのローカル実行

SAMテンプレートでLayerをARNで指定すれば、 次のように sam local invoke コマンドでLambdaのローカル実行ができます。

$ cd ~/environment/aws-lambda-developer-guide/sample-apps/blank-java
$ sam local invoke -e event.json

Lambda Layerパッケージは、デフォルトでは ~/.aws-sam/layers-pkg/ にキャッシュされます。 sam local invoke 実行後に確認すると、Layerパッケージが自動でダウンロードされキャッシュされていることがわかります。

$ ls ~/.aws-sam/layers-pkg/
blank-java-lib-8-14f4e6cb4d

終わりに

Cloud9でLambda Layerに依存するJavaのLambdaのローカル実行をやってみました。

Lambdaのプログラムを修正して、ちょっとテスト実行してみたいことがよくあると思いますが、そのたびに再デプロイするのはちょっと面倒くさいです。 SAMの機能を使ってローカルでサッと実行して動作が確認できると開発しやすいと思います。