AWS

AWS SAM + DynamoDB を使用したローカルLambda開発環境のセットアップ

AWS
この記事は約23分で読めます。

はじめに

株式会社implの奈良です。

現在、進行中の案件でAWS Lambdaを使用したサーバーレス開発を進めるにあたり、ローカル環境でLambdaを開発するための環境構築方法について調査しました。

その結果、AWS SAMLocalStackの2つが候補として挙がりましたが、8月29日に参加した【イチから理解するサーバーレスアプリ開発 | AWS オンラインセミナー】の影響を受け、今回はAWS SAMを使用して開発環境を整えることにしました。

AWS Lambdaの開発を効率的に進めるため、AWS SAM (Serverless Application Model) を活用し、ローカル環境でDynamoDBと連携する方法をご紹介します。この環境を使用することで、クラウドにデプロイする前に、ローカルでLambdaの動作確認を行い、充分なテストが可能になります。

対象読者

  • AWS Lambda を使ったサーバーレス開発を行いたい方
  • ローカル環境で DynamoDB や S3 との連携を試したい方
  • AWS SAM を使って効率的に開発を行いたい方

前提条件

まず、開発環境を整えるために以下のツールが必要です。

  • AWS CLI: AWS リソースの操作を行うために使用します。
  • AWS SAM CLI: サーバーレスアプリケーションの開発、テスト、デプロイを行うためのツールです。
  • Docker: ローカル環境でLambda関数やDynamoDBの動作をテストするために使用します。

インストール手順

AWS CLI のインストール

brew install awscli
aws --version

AWS SAM CLI のインストール

brew tap aws/tap
brew install aws-sam-cli
sam --version

Docker のインストール

下記公式サイトから Docker をインストールしてくださいhttps://www.docker.com/get-started

プロジェクトのセットアップ

新規プロジェクトの作成

以下のコマンドで新しい SAM プロジェクトを作成します。

mkdir impl-sam-dynamodb # 新しいディレクトリを作成
cd impl-sam-dynamodb # 移動
sam init # SAMアプリケーションを作成

sam initで特定のruntimeを選択する場合(nodejs20)

sam initコマンドを実行すると対話式プロンプトが表示されて、下記のような選択項目がでますが、今回はnodejs20をオプションで選択した場合のフローを紹介します。

今回のような【AWS SAM + DynamoDBのローカルLambda開発】においては、Choose an AWS Quick Start application templateのプロンプトで選択しているServerless APIを選択することをお勧めします。

sam init --runtime nodejs20.x  # Lambdaで使用するruntimeにnodejs20.xを使用
Which template source would you like to use? # 基本的に1で問題ない
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template 
	1 - Hello World Example
	2 - GraphQLApi Hello World Example
	3 - Hello World Example with Powertools for AWS Lambda
	4 - Multi-step workflow
	5 - Standalone function
	6 - Scheduled task
	7 - Data processing
	8 - Serverless API
	9 - Full Stack
	10 - Lambda Response Streaming
Template: 8

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.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: y
X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details

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]: y
AppInsights monitoring may incur additional cost. View https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/appinsights-what-is.html#appinsights-pricing for more details

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: y
Structured Logging in JSON format might incur an additional cost. View https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-pricing for more details

Project name [sam-app]: impl-sam-app

    -----------------------
    Generating application:
    -----------------------
    Name: impl-sam-app
    Runtime: nodejs20.x
    Architectures: x86_64
    Dependency Manager: npm
    Application Template: quick-start-web
    Output Directory: .
    Configuration file: impl-sam-app/samconfig.toml

    Next steps can be found in the README file at impl-sam-app/README.md


Commands you can use next
=========================
[*] Create pipeline: cd impl-sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd impl-sam-app && sam validate
[*] Test Function in the Cloud: cd impl-sam-app && sam sync --stack-name {stack-name} --watch
選択肢項目の解説
Choose an AWS Quick Start application templateの選択肢
  1. Hello World Example
    • 概要: Lambda関数を使用して簡単な「Hello World」を返すサーバーレスアプリケーションの基本例です。
    • 適用例: サーバーレスアプリケーションの基礎を学びたい場合や、LambdaやAPI Gatewayの動作確認に最適です。
  2. GraphQLApi Hello World Example
    • 概要: AWS AppSyncを使用したGraphQL APIの基本例です。GraphQLを使ったAPI開発を学ぶことができます。
    • 適用例: GraphQL APIの構築や、クエリ、ミューテーションの学習に適しています。
  3. Hello World Example with Powertools for AWS Lambda
    • 概要: AWS Lambda Powertoolsを使用して、ロギングやトレーシング、メトリクス収集を行う「Hello World」の例です。
    • 適用例: サーバーレスアプリケーションにおいて、モニタリングやデバッグ機能を強化したい場合に適しています。
  4. Multi-step workflow
    • 概要: AWS Step Functionsを使用して、複数のLambda関数やサービスを統合し、マルチステップのワークフローを構築する例です。
    • 適用例: 分岐や条件に基づいた複雑な処理フローを実装する際に最適です。
  5. Standalone function
    • 概要: 単一のLambda関数を実行するシンプルなテンプレートです。API Gatewayを使用せずにLambda関数のみを動作させます。
    • 適用例: 単一のイベントソースやトリガーで動作するLambda関数を構築したい場合に適しています。
  6. Scheduled task
    • 概要: AWS EventBridge(旧CloudWatch Events)を使用して、定期的にLambda関数を実行するスケジュールタスクの例です。
    • 適用例: 定期的に実行するバッチ処理やメンテナンスタスクに適しています。
  7. Data processing
    • 概要: KinesisやS3を使用して、Lambda関数でデータをリアルタイムまたはバッチ処理する例です。
    • 適用例: 大量のデータをストリーム処理したり、S3からバッチ処理を実行するアプリケーションに適しています。
  8. Serverless API
    • 概要: Lambda関数とAPI Gatewayを使用して、完全なサーバーレスAPIを構築するテンプレートです。
    • 適用例: RESTfulなAPIを構築したい場合や、CRUD操作を実装したい場合に最適です。
  9. Full Stack
    • 概要: Lambda、API Gateway、DynamoDB、S3などのAWSサービスを使って、サーバーレスのフルスタックアプリケーションを構築するテンプレートです。
    • 適用例: フロントエンドとバックエンドが統合されたアプリケーションの開発に最適です。
  10. Lambda Response Streaming
  • 概要: Lambda関数を使用して、レスポンスをストリーミングする例です。チャンク単位でデータをクライアントに送信します。
  • 適用例: 大量のデータを効率的に配信するストリーミングAPIや、分割してレスポンスを返す処理に最適です。
X-Ray Tracing とは

AWS X-Rayは、分散アプリケーションのトレースを行うサービスです。具体的には、リクエストがアプリケーション内をどのように流れているか、どのコンポーネントが遅延しているか、どの部分でエラーが発生しているかなどを可視化することができます。これにより、アプリケーションのパフォーマンスを監視し、ボトルネックやエラーの特定が容易になります。

「Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]」という質問は、「アプリケーションの関数に対してX-Rayトレースを有効にしますか?」という意味です。

  • y (Yes): X-Rayトレースを有効にします。Lambda関数の実行中にトレースデータが収集され、後でAWS X-Rayでこのデータを解析できます。
  • N (No): X-Rayトレースを有効にしません。Lambda関数のパフォーマンスやエラーのトレースが不要であれば、これを選ぶことで余計なオーバーヘッドを避けることができます。
CloudWatch Application Insights とは

AWS CloudWatch Application Insightsは、アプリケーションの監視を自動化するサービスです。具体的には、アプリケーションのパフォーマンスや信頼性の問題を検出し、解決に役立つ洞察を提供します。これには、メトリクス、ログ、およびトレースデータの収集と分析が含まれます。

「Would you like to enable monitoring using CloudWatch Application Insights?」は、「CloudWatch Application Insightsを使用して監視を有効にしますか?」という意味です。

  • y (Yes): CloudWatch Application Insightsを有効にします。これにより、アプリケーションのメトリクスやログの監視が自動化され、問題が発生した際にアラートを受け取ったり、トラブルシューティングのためのデータを簡単に収集できるようになります。
  • N (No): CloudWatch Application Insightsを有効にしません。自分で監視を行う、または別の方法で監視を行いたい場合に選択します。
Structured Logging in JSON Formatとは

構造化ログとは、ログメッセージを一定の形式で記録する方法です。JSON形式でログを構造化することで、ログデータが読みやすく、解析しやすくなります。たとえば、以下のようなログが出力されるとします。

{
  "timestamp": "2024-09-03T13:45:00Z",
  "level": "INFO",
  "message": "User login successful",
  "user_id": "12345"
}

「Would you like to set Structured Logging in JSON format on your Lambda functions?」は、「Lambda関数で構造化ログをJSON形式で設定しますか?」という意味です。

  • y (Yes): 構造化ログをJSON形式で有効にします。これにより、ログデータが一貫した形式で記録され、CloudWatchや他のログ解析ツールで簡単に解析できるようになります。
  • N (No): 構造化ログを有効にしません。デフォルトの形式でログが記録されます。
Project name [sam-app]とは

Project name [sam-app]:」というプロンプトは、AWS SAM(Serverless Application Model)プロジェクトの名前を入力するように求めています。

  • sam-app はデフォルトのプロジェクト名です。もし特に指定がなければ、この名前がプロジェクトの名前として使われます。

プロジェクト名を変更したい場合: 自分で指定したいプロジェクト名を入力します。たとえば、「my-lambda-project」や「order-processing-service」など、プロジェクトの内容を示す名前を入力します。

デフォルトの名前で問題ない場合: 何も入力せずにそのまま Enter キーを押します。これにより、プロジェクト名は sam-app になります。

Docker Network の作成

ローカルで DynamoDB や AWS CLI コンテナとLambdaが相互に通信できるよう、Dockerネットワークを作成します。

docker network create lambda-local

ローカル DynamoDB のセットアップ

次に、ローカルの DynamoDB コンテナを起動します。以下のコマンドを実行してください。

docker run -d --network=lambda-local --name dynamodb-local -p 8000:8000 amazon/dynamodb-local

このコマンドで、dynamodb-local というコンテナがローカル環境で立ち上がり、8000 ポートで DynamoDB が使用可能になります。

ローカル DynamoDB のセットアップ(docker-compose.ymlを利用)

上記のコマンドと動作は同じですが、チーム開発の場合はdocker-compose.ymlを作成し、下記コマンドを実行するように環境構築手順をまとめた方が良い場合もあります。

docker-compose up -d
# docker-compose.yml

version: '3'
services:
  dynamodb:
    image: amazon/dynamodb-local
    command: -jar DynamoDBLocal.jar -sharedDb -dbPath . -optimizeDbBeforeStartup
    volumes:
      - dynamodb:/home/dynamodblocal
    ports:
      - 8001:8000  # DynamoDB Local に外部からアクセス可能にするためのポートマッピング
    networks:
      - lambda-local

volumes:
  dynamodb:
    driver: local  # ローカルストレージとして DynamoDB のデータを保存

networks:
  lambda-local:
    external: true  # すでに存在する外部ネットワークに接続

DynamoDB Localに接続確認

aws dynamodb list-tables --endpoint-url http://localhost:8001 などを使用して、DynamoDB Localが正しく稼働しているか、接続できているかを確認します。この時点でエラーメッセージがなければ、次のステップに進めます。

aws dynamodb list-tables --endpoint-url http://localhost:8001

# テーブルがないことを確認
{
    "TableNames": []
}

テーブル作成コマンドの実行

DynamoDB Localが正しく動作していることを確認できたら、次に紹介するcreate-tableコマンドを実行し、「Test」テーブルを作成します。このタイミングでテーブルがないことを確認してから、テーブル作成コマンドを実行するとよいでしょう。

aws dynamodb create-table \
    --table-name TestTable \
    --attribute-definitions AttributeName=test_id,AttributeType=S \
    --key-schema AttributeName=order_id,KeyType=HASH \
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --endpoint-url http://localhost:8001

テーブル作成の確認

テーブル作成コマンドが成功したかどうか、再度 aws dynamodb list-tables --endpoint-url http://localhost:8001 を実行して、「Test」テーブルがリストに表示されるか確認します。

必要に応じて、下記コマンド例を実行して適宜DBにデータをinsertすることをおすすめします。

aws dynamodb put-item \
  --table-name TestTable \
  --item '{
    "test_id": {"S": "123e4567"},
    "test_name": {"S": "テスト太郎"},
    "created_at": {"S": "2024-07-01T13:00:00Z"},
    "updated_at": {"S": "2024-07-01T13:00:00Z"}
  }' --endpoint-url http://localhost:8001

SAMプロジェクトの構成

SAMプロジェクトの template.yaml ファイルで DynamoDB テーブルと S3 バケットを定義し、Lambda 関数と連携します。

AWSTemplateFormatVersion: 2010-09-09
Description: impl-sam-app
Transform:
  - AWS::Serverless-2016-10-31

Resources:
  # DynamoDBテーブル定義
  TestTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: TestTable #任意のテーブル名とカラムを設定
      AttributeDefinitions:
        - AttributeName: test_id
          AttributeType: S
        - AttributeName: created_at
          AttributeType: S
      KeySchema:
        - AttributeName: test_id
          KeyType: HASH
        - AttributeName: created_at
          KeyType: RANGE
      BillingMode: PAY_PER_REQUEST

  # S3バケット定義
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: Local-test-s3  # 任意の一意なバケット名

  # Lambda関数の定義
  getTestsFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/get-test.gettests
      Runtime: nodejs20.x
      MemorySize: 128
      Timeout: 100
      Description: Get all tests from DynamoDB table and S3 bucket
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref TestTable
        - S3ReadPolicy:
            BucketName: !Ref MyS3Bucket
      Environment:
        Variables:
          TABLE_NAME: !Ref TestTable
          BUCKET_NAME: !Ref MyS3Bucket
      Events:
        Api:
          Type: Api
          Properties:
            Path: /tests
            Method: GET

ビルドとローカルテスト

ビルド

まず、Lambda関数やリソースをビルドします。

sam build
  • 役割:
    • Lambda 関数のコードとリソースをビルドします。
    • 必要な依存関係をインストールし、Lambda 関数のデプロイ可能な形にパッケージ化します。特に、コードが Node.js や Python などの言語で書かれている場合、パッケージのインストールを行います。
    • SAM テンプレート(template.yaml)を解析し、CloudFormation スタックで定義された Lambda 関数に必要なアーティファクトを準備します。

ローカルでのテスト

ビルド後、Lambda関数をローカルで実行して、APIをテストします。

sam local start-api

これで、ローカル環境でAPIをテストできるようになります。APIエンドポイントは http://localhost:3000/tests です。

  • 役割:
    • ローカル環境で API Gateway と Lambda 関数を起動し、API のテストをローカルで実行できます。
    • API Gateway をローカルで模倣し、ローカル DynamoDB(または LocalStack などのツール)を使用して API をテストします。
    • クラウドにデプロイする前にローカルで API を検証できます。

ローカル環境でLambda関数のテスト

ローカルでLambda関数を直接テストするために、sam local invokeコマンドを使用します。このコマンドは、指定したLambda関数をローカルで実行し、その挙動を確認する際に用います。

手順:

Lambda関数をテストするには、以下のコマンドを実行します。

sam local invoke getTestsFunction --event events/event-get-all-tests.json

具体例:

geTestsFunctionというLambda関数を、event-get-all-tests.jsonというファイルに記載されたイベントデータを使用して実行します。これにより、Lambda関数がそのデータに対してどのように反応するかをローカルで確認できます。

適用例:

  • Lambda関数のロジックを確認したい場合
  • 特定の入力に対する関数の出力やエラーハンドリングを検証する場合

SAMのローカルAPIを開始する

ローカル環境でAPI GatewayとLambda関数の連携動作を確認するためには、sam local start-apiコマンドを使用します。このコマンドは、API Gatewayの動作をローカルでエミュレートし、HTTPリクエストを通じてLambda関数をテストできるようにします。

手順:

API Gatewayのエミュレーションを開始し、ローカルでAPIを動作させるには、以下のコマンドを実行します。

sam local start-api

具体例:

sam local start-apiを実行すると、ローカルサーバーが起動し、ブラウザやcURLなどでHTTPリクエストを送信して、Lambda関数をテストできます。URLは通常 http://localhost:3000 でアクセスできます。

適用例:

  • API Gateway経由でLambda関数が正しく動作するか確認したい場合
  • 実際のHTTPリクエストとレスポンスの動作をローカルでテストしたい場合

デプロイ

全てがローカルで正常に動作することを確認した後、AWSにデプロイを行います。
(※AWS上にデプロイするため、ローカル環境の作業ではなくなります。)

S3関連の作業は適宜デプロイ後に実行してください。(ローカルで作業したい場合は、LocalStack等のサービスをご利用ください。)

デプロイの準備

AWSアクセスキーシークレットアクセスキーの設定

AWS SAMでデプロイを行う前に、AWSアクセスキーシークレットアクセスキーを設定する必要があります。

aws configure

上記コマンド実行後、以下の情報を順番に入力します。

  • AWS Access Key ID: IAMユーザー作成時に取得したアクセスキーを入力。
  • AWS Secret Access Key: IAMユーザー作成時に取得したシークレットキーを入力。
  • Default region name: 使用するリージョン(例:ap-northeast-1)。
  • Default output format: json(推奨)。

初回デプロイ時の設定

初めてのデプロイ時には、sam deploy --guided コマンドを実行し、必要な設定を入力します。

sam deploy --guided
  • 役割:
    • ビルド済みのアーティファクトを AWS クラウドにデプロイします。
    • S3 にアーティファクト(Lambda 関数、テンプレートなど)をアップロードし、CloudFormation スタックを作成または更新してデプロイを実行します。
    • API Gateway、DynamoDB、Lambda 関数などがクラウドにデプロイされ、実際の AWS 環境でアプリケーションを動作させます。
–guided:オプションについて
  • 初回のデプロイ時に使用すると、いくつかの設定(スタック名、リージョン、S3 バケットの設定、変更の確認など)を対話形式で入力できます。その後、設定が保存されるため、次回以降は簡単にデプロイができます。

デプロイ実行

デプロイ設定が完了したら、以下のコマンドでデプロイを実行します。

sam deploy

デプロイが完了すると、CloudFormation により AWS リソースが作成されます。API GatewayのURLが出力されるので、ブラウザやPostmanでアクセスして動作を確認しましょう。

まとめ

この記事では、AWS SAM、DynamoDBを使用してローカルでLambda開発環境をセットアップする手順を紹介しました。ローカル環境でAPIやリソースのテストを行い、最終的にAWSにデプロイするまでの流れをスムーズに進められるようになります。これにより、効率的にサーバーレスアプリケーションの開発が行えるようになるでしょう。