Lambdaローカル開発環境構築メモ (SAM | LocalStack | TypeScript)

April 24, 2023

Intro

PC の入れ替えに伴い、Lambda のローカル実行環境を再構築した。メモとして残しておきます。 PC リプレースのついでに Lambda のローカル実行環境を再構築。メモとして残しておく。

技術要素

  • Volta
  • Lambda
  • LocalStack
  • TypeScript
  • SAM

前提条件

Installing Volta

  • Volta のインストール

Volta は Node.js のバージョン管理に特化したツールです。プロジェクトごとに異なる Node.js のバージョンを切り替えることができ、Node.js のバージョンを手動でインストール・管理することなく、異なるバージョンを簡単に管理することができます。Volta は、他のバージョン管理ツールと比較して切り替えが簡単という利点があり、OS やシェルに依存しないため様々な環境で利用することができます。

$ curl https://get.volta.sh | bash
$ echo 'export VOLTA_HOME="$HOME/.volta"' >> .zshrc
$ echo 'export PATH="$VOLTA_HOME/bin:$PATH"' >> .zshrc

Node.js と Yarn のインストール

利用可能なバージョンを確認するには、volta list node を使用します。特定のバージョンをインストールしたい場合は、volta install node@18.15.0 というフォーマットを使ってください。

$ volta install node
  success: installed and set node@18.15.0 (with npm@9.5.0) as default
$ volta install yarn
  success: installed and set yarn@4.0.0-rc.42 as default

SAM のインストール

以下の手順は macOS 用である。Windows ユーザーの方は公式サイトから MSI ファイルをダウンロードすることをお勧めします。

  • macOS
$ brew tap aws/tap
$ brew install aws-sam-cli

$ sam --version
SAM CLI, version 1.78.0

Creating a Project

$ sam init -r nodejs18.x

	SAM CLI now collects telemetry to better understand customer needs.

	You can OPT OUT and disable telemetry collection by setting the
	environment variable SAM_CLI_TELEMETRY=0 in your shell.
	Thanks for your help!

	Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

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 - Hello World Example With Powertools
	3 - Multi-step workflow
	4 - Standalone function
	5 - Scheduled task
	6 - Data processing
	7 - Serverless API
Template: 1

Based on your selections, the only Package type available is Zip.
We will proceed to selecting the Package type as Zip.

Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.

Select your starter template
	1 - Hello World Example
	2 - Hello World Example TypeScript
Template: 2

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: n

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: n

Project name [sam-app]: sam-local-study

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: sam-local-study
    Runtime: nodejs18.x
    Architectures: x86_64
    Dependency Manager: npm
    Application Template: hello-world-typescript
    Output Directory: .
    Configuration file: sam-local-study/samconfig.toml

    Next steps can be found in the README file at sam-local-study/README.md


Commands you can use next
=========================
[*] Create pipeline: cd sam-local-study && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-local-study && sam validate
[*] Test Function in the Cloud: cd sam-local-study && sam sync --stack-name {stack-name} --watch

プロンプトに従うと、以下のファイルが生成される:

$ tree .
.
└── sam-local-study
    ├── README.md
    ├── events
    │   └── event.json
    ├── hello-world
    │   ├── app.ts
    │   ├── jest.config.ts
    │   ├── package.json
    │   ├── tests
    │   │   └── unit
    │   │       └── test-handler.test.ts
    │   └── tsconfig.json
    ├── samconfig.toml
    └── template.yaml

6 directories, 9 files

メッセージを返すサンプル Lambda 関数の作成

メッセージを返す Lambda 関数のサンプルを作成し、SAM を使って実行してみましょう。

コードの準備

$ tree .
.
└── sam-local-study
    ├── src
    │   ├── handlers
    │      └── hello-from-lambda.js
    └── template.yaml
  • src/handlers/hello-from-lambda.js
exports.helloFromLambdaHandler = async () => {
    const message = "Hello from Lambda!";
    console.info(`${message}`);
    return message;
};
  • template.yaml
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/hello-from-lambda.helloFromLambdaHandler
      Runtime: nodejs18.x
      MemorySize: 128
      Timeout: 100
      Description: A Lambda function that returns a static string.
      Policies:
        - AWSLambdaBasicExecutionRole

“Hello “を返すラムダ関数の実行

  • Execute the command:
$ sam local invoke HelloWorldFunction
  • Output:
Invoking src/handlers/hello-from-lambda.helloFromLambdaHandler (nodejs18.x)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/nodejs:18-rapid-x86_64.

Mounting /lambda-sam-localstack/sam-local-study as /var/task:ro,delegated, inside runtime container
START RequestId: 6d2615de-b38f-4300-bf87-704e1fa6296a Version: $LATEST
2023-04-05T08:41:27.339Z	6d2615de-b38f-4300-bf87-704e1fa6296a	INFO	Hello from Lambda!
END RequestId: 6d2615de-b38f-4300-bf87-704e1fa6296a
REPORT RequestId: 6d2615de-b38f-4300-bf87-704e1fa6296a	Init Duration: 0.75 ms	Duration: 953.12 ms	Billed Duration: 954 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
"Hello from Lambda!"%

LocalStack を使う

  • クレデンシャルの設定 (~/.aws/credentials)
[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy
  • docker-compose.yml を用意する
  • docker-compose.yml を使って LocalStack を起動する
  • コマンド:docker-compose up -d
version: '3.7'

services:
  localstack:
    image: localstack/localstack
    ports:
      - '4566:4566'
    environment:
      - SERVICES=s3,dynamodb
      - PERSISTENCE=1
    volumes:
      - '${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack'
    networks:
      - localstack

networks:
  localstack:
    name: sam-local-localstack
  • SAM を使って LocalStack で実行する
sam local invoke HelloWorldFunction \
 -e events/event.json \
 --docker-network sam-local-localstack \
 --profile localstack

ローカル環境をプログラムから参照する方法

  • s3 を作成する
aws s3 mb s3://xxxxxxxx  --endpoint-url http://localhost:4566 --profile localstack
  • ローカル環境をプログラムから参照する方法。一部抜粋
const endpoint = env.isLocal ? "http://localstack:4566" : undefined;
const s3Client = new S3Client({
    apiVersion: "2006-03-01",
    endpoint: endpoint,
    forcePathStyle: env.isLocal ? true : false,
});
Nifty tech tag lists from Wouter Beeftink