ローカル環境でLambda+S3のテストをする

ローカル環境でLambda+S3のテストをする:


概要

sam local & localstack を使ってローカルでLambdaのテストする環境を構築したときの手順とハマったところをまとめたものです。おもに参考文献[2]を参考にして構築しました。

SAMのリソースの作成方法についてはここではあまり触れていません。


構築の要件

  • Lambda Function の中で S3 を参照している部分をローカル環境でテストしたい

    • テストサイクルが早くなることを期待


Stack

  • AWS SAM

    • SAM CLI, version 0.10.0
  • localstack


手順


必要な資材のインストール

公式ページの説明にしたがってインストールします。

  • aws-sam-cli
  • docker for Mac


localstack の起動

docker-compose.yml
version: '3' 
services: 
  localstack: 
    image: localstack/localstack 
    ports: 
      - 4567-4578:4567-4578 
      - 8080:8080 
dockerコンテナの起動

docker-compose up -d 


profileの設定

locastack の場合も、aws-cli を呼び出すときに profile の設定がないとコケます[1]

~/.aws/credentials
[localstack] 
aws_access_key_id = dummy 
aws_secret_access_key = dummy 
~/.aws/config
[profile localstack] 
region = us-east-1 
output = text 


Localstack上の S3 に Bucket/Object を作成する

message.txt
Hi, there! 
# bucket作成 
aws s3 --endpoint-url=http://localhost:4572 s3api create-bucket --bucket test-bucket --profile=localstack 
 
# オブジェクト作成 
aws s3 --endpoint-url=http://localhost:4572 cp message.txt s3://test-bucket --profile=localstack 


docker networkの確認

sam local 実行時に docker network を指定しないと、SAM Local => localstackに疎通ができません。 [2]

docker network ls                                                 (sam-app/script) 18:49:45 
NETWORK ID          NAME                 DRIVER              SCOPE 
... 
b2fbba06747a        localstack_default   bridge              local 
... 


環境変数をSAMのテンプレートで指定する

sam local 実行時に --env-vars で環境変数を指定しても、 SAMテンプレートに環境変数が指定されていないと有効になりません。

env.json
{ 
  "S3ReadFunction": { 
    "IS_LOCAL_STACK": "true", 
    "S3_BUCKET": "test-bucket" 
  } 
} 
template.yaml
Globals: 
  Function: 
    Environment: 
      Variables: 
        IS_LOCAL_STACK: false 
        S3_BUCKET: 'production-bucket' 


S3のエンドポイントに localstack のエンドポイントを指定する

環境変数によってS3の参照先を切り分けるロジックをアプリケーションのコードに実装します。

app.js
const AWS = require('aws-sdk'); 
 
// localstack 
const config = { 
  endpoint: (process.env.IS_LOCAL_STACK === "true"? "http://localstack:4572": undefined), 
  s3ForcePathStyle: process.env.IS_LOCAL_STACK === "true", 
} 
const s3 = new AWS.S3(config); 
const { S3_BUCKET_MAIL_BOX } = process.env; 
 
// handlerのコード 
exports.lambdaHandler = async (event, context) => { 
  try { 
    const params = { 
      Bucket: S3_BUCKET, 
      Key: event.Key 
    }; 
    const ret = await s3.getObject(params).promise(); 
    const message = ret.Body.toString(); 
    console.log(message); 
  } catch (err) { 
    console.log(err); 
    return err; 
  } 
}; 


ビルド

sam build --use-container 


sam local 実行

sam local 上に起動した lambda function を起動します

sam local invoke S3ReadFunction --docker-network b2fbba06747a --env-vars env.json --profile=localstack 
手動で次のように入力します

標準入力
{"Key": "message.txt"}<Enter> 
<Ctrl-D> 
出力結果
... 
2019-02-01T09:34:34.903Z    3d01ad34-1760-1c18-4042-4088ba5fffa1    Hi, there! 
... 


終わりに

SAM Local と localstack を使って Docker Container 上に起動した lambda function から local stack 上に起動した S3 に疎通することができました。

ただ、結局のところ以下のような手順を毎回実行するので、開発サイクルの高速化はさほどのぞめませんでした(AWSコンソール上でソースコード修正 => テスト実行のほうがむしろ早いかも)。

  1. docker image のビルド (sam build --use-container)
  2. docker container の起動 (sam local invoke)
CI化したときにS3などの外部リソースを含むテストをテスト環境で一貫して行えるのは良いと思いました。


参考

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)