[アップデート] SAM CLI で AWS へデプロイされた Lambda 関数を実行出来る sam remote invoke コマンドが利用可能になりました

2023.06.25

いわさです。

昨日こちらの記事に関して検証する中で AWS SAM のドキュメントを眺めていたのですが、SAM CLI で新しいコマンドsam remote invokeが使えるようになったというアップデート履歴があることに気が付きました。

たしかに 2 日前に SAM CLI の最新バージョン v1.88.0 がリリースされており、新機能が含まれていました。

feat: Make remote invoke command available

早速ローカルの SAM CLI をバージョンアップし新しい機能を試してみました。

% sam --version
SAM CLI, version 1.88.0

sam remote invoke について情報整理

SAM CLI で完結したいのかな?

これまでは開発中にsam local invokeコマンドを使って、ローカルコンテナ上にデプロイした Lambda 関数を実行することが出来ていました。
しかし、ローカルではなくクラウド上にデプロイした関数を実行する必要がある場合は、次のように AWS CLI などから実行する必要がありました。

また、それとは別でsam syncコマンドを使うことでローカルコードを迅速にクラウド上の Lambda 関数へ同期させる機能が SAM CLI にはあります。

このあたりのローカルとクラウドを行ったり来たりする開発フェーズでは SAM CLI で実行まで完結出来ると、普段 SAM を使って開発をしている人には便利なのかな?と思いました。

sam remote invoke の使い方

コマンドのリファレンスは以下です。

そのままですがリモート(クラウド上にデプロイ済み)の関数を実行するコマンドです。
おもしろいなと思ったのは SAM アプリケーションのローカルコンテキストをうまいこと解釈してくれる点です。

通常の Lambda Invoke コマンドだと関数の名前あるいは ARN を指定する必要があります。
sam remote invokeの場合はローカルのsamconfig.tomlやテンプレートからどの関数が対象なのか自動で判定してくれます。

後ほど検証した内容を紹介しますが、SAM アプリケーションに含まれる関数がひとつであれば関数名も何も指定しなくても実行出来ます。
あるいはスタック名を指定することで対象スタックに含まれている関数を自動で判別して実行してくれます。
このあたりは地味に便利だなぁと思いました。

試してみる

では実際に使ってみた様子を紹介します。

サンプルアプリ

いつもの単純なハローワールドから始めます。

% sam init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - Serverless Connector Hello World Example
        11 - Multi-step workflow with Connectors
        12 - Full Stack
        13 - Lambda EFS example
        14 - DynamoDB Example
        15 - Machine Learning
Template: 1

これでデプロイされるのは API Gateway + Lambda 関数が 1 つの、よくある最低限の SAM アプリケーションです。

template.yaml

:

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.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      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

:

関数は次のように静的なレスポンスを行うもの。

app.py

import json

def lambda_handler(event, context):

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world"
        }),
    }

sam sync しつつ sam remote invoke で使ってみる

sam syncを使ってローカルとクラウドの同期モードで開発しつつ、変更後にsam remote invokeを使って動作確認してみます。

まずはコード変更前にsam syncを実行しておきます。

% sam sync

The SAM CLI will use the AWS Lambda, Amazon API Gateway, and AWS StepFunctions APIs to upload your code without 
performing a CloudFormation deployment. This will cause drift in your CloudFormation stack. 
**The sync command should only be used against a development stack**.

:

Stack creation succeeded. Sync infra completed.                                                                                                                                             

CodeTrigger not created as CodeUri or DefinitionUri is missing for ServerlessRestApi.                                                                                                       
Infra sync completed.

sam syncはデフォルトでウォッチモードです。
そのため、ローカルでコードを変更して保存すると、数秒で AWS 上の Lambda 関数へも反映されます。
ここでは次のようにレスポンスのメッセージをちょっとだけ変えました。

app.py

import json

def lambda_handler(event, context):

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world!!!"
        }),
    }
Infra sync completed.                                                                                                                                                                       

Syncing Lambda Function HelloWorldFunction...                                                                                                                                               
Manifest is not changed for (HelloWorldFunction), running incremental build                                                                                                                 
Building codeuri: /Users/iwasa.takahito/work/hoge0625sam/hoge0625sam/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction                         
Running PythonPipBuilder:CopySource                                                                                                                                                         
Finished syncing Lambda Function HelloWorldFunction.

ほんと早い。
2~3 秒で反映されたのではないだろうか。

では、AWS 上での動作確認を行いたいのでsam remote invokeしてみましょう。

% sam remote invoke
Invoking Lambda Function HelloWorldFunction                                                                 
START RequestId: c295c58f-3046-44a4-bd34-975672472fb7 Version: $LATEST
END RequestId: c295c58f-3046-44a4-bd34-975672472fb7
REPORT RequestId: c295c58f-3046-44a4-bd34-975672472fb7  Duration: 0.99 ms       Billed Duration: 1 ms   Memory Size: 128 MB Max Memory Used: 36 MB  Init Duration: 96.03 ms
{"statusCode": 200, "body": "{\"message\": \"hello world!!!\"}"}

良いですね。特に何も指定せずにsam remote invokeを実行するだけでこのように動作確認することが出来ました。

他にも論理名やスタック名、ARNなど様々な呼び出し方が出来ます。
論理名やスタック名あたりは、Lambda 関数名ではなくて SAM の抽象化されたレイヤーでそのまま呼び出せているのでかなり良いですね。

% sam remote invoke HelloWorldFunction
Invoking Lambda Function HelloWorldFunction                                                                 
START RequestId: 18cb4582-ac91-42c3-b0a0-01a294cbd57f Version: $LATEST
END RequestId: 18cb4582-ac91-42c3-b0a0-01a294cbd57f
REPORT RequestId: 18cb4582-ac91-42c3-b0a0-01a294cbd57f  Duration: 1.67 ms       Billed Duration: 2 ms   Memory Size: 128 MB Max Memory Used: 36 MB  Init Duration: 105.84 ms
{"statusCode": 200, "body": "{\"message\": \"hello world???\"}"}%

パラメータを渡してみる

リファレンスを見て頂くとわかりますが、パラメータの渡し方もeventevent-fileなど色々サポートされてます。
試しにパラメータ渡して実行してみましょう。

次のようにローカルでコードを修正します。

app.py

import json

def lambda_handler(event, context):

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": event["hoge"]
        }),
    }

sam syncされている状態なので、これも即座にクラウド上にコードが反映されます。
その後、sam remote invokeでイベントパラメータを渡してみます。

% sam remote invoke -e '{"hoge": "fuga"}'                         
Invoking Lambda Function HelloWorldFunction                                                                 
START RequestId: 43dc9521-2f25-48a8-99c9-8d5e3fa41503 Version: $LATEST
END RequestId: 43dc9521-2f25-48a8-99c9-8d5e3fa41503
REPORT RequestId: 43dc9521-2f25-48a8-99c9-8d5e3fa41503  Duration: 1.12 ms       Billed Duration: 2 ms   Memory Size: 128 MB Max Memory Used: 36 MB
{"statusCode": 200, "body": "{\"message\": \"fuga\"}"}

% echo '{"hoge": "piyo"}' | sam remote invoke --event-file -           
Reading event from stdin (you can also pass it from file with --event-file)                                 
Invoking Lambda Function HelloWorldFunction                                                                 
START RequestId: 292635a0-887c-4464-8ecb-281840944bf2 Version: $LATEST
END RequestId: 292635a0-887c-4464-8ecb-281840944bf2
REPORT RequestId: 292635a0-887c-4464-8ecb-281840944bf2  Duration: 0.97 ms       Billed Duration: 1 ms   Memory Size: 128 MB Max Memory Used: 37 MB
{"statusCode": 200, "body": "{\"message\": \"piyo\"}"}

ここでは 2 パターン実行してみました。

さいごに

本日は SAM CLI で AWS へデプロイされた Lambda 関数を実行出来る sam remote invoke コマンドが利用可能になったので使ってみました。

他の SAM CLI のコマンドと同様に抽象化された状態でそのままクラウド上へデプロイした関数を実行することが出来ました。
SAM CLI を中心に開発しつつ、特にsam syncなどを使っていてローカルからクラウド上の関数を頻繁に実行・確認したい際には使えそうです。