- 栗田真
- Programming
- 約 2,900 文字
- 1,500 View
目次
サーバレス連載 の第1弾です。
はじめに
こんにちは、TIG/DXチームの栗田です。AWSのLambdaに代表されるサーバレスアプリは実行時のみ稼働するため、サーバー稼働によるあらゆるコストから解放され、システム開発の工数を減らすことができます。例えば何らかのAPIを提供する場合でも、API GatewayとLambdaを組み合わせることで提供可能です。
一方で、サーバーレスアプリを開発するとき、ローカルでのテストが課題となります。例えばLambda + DynamoDBであれば、先の連載の手法を参考に、テストコードを書くことで解決します。一方で…
- API GatewayからLambdaの着火もテストした上でDynamoDBまで書き込ませたい
- なんならAPI Gaweway自体もLambdaで叩きたい
となると、少々ハードルがあがります。この問題を解決してくれるのが、AWS Serverless Application Model(AWS SAM)です。SAMはローカルにLambda実行用のdockerを立ち上げ、127.0.0.1:3000を叩くと指定した実行ファイルをdocker上で動作させることができるツールです。今回はSAMを使って API Gateway + Lambda (Go) + DynamoDBのローカルテストをする手法を紹介します。
なお、今回ターゲットとする構成は、Lambda→AWS Gateway→Lambda→DynamoDBのような構成です。例えばKinesisやS3から非同期な入力をトリガーにLambdaを着火し、特定のAPIを叩くようなケースです。便宜上、API Gatewayを叩くのをLambda A、API Gatewayから呼び出されるのをLambda Bとします。
これをSAMとDynamoDB localを使ってテストしますが、想定する最終的なテスト環境としては以下のような形になります。青で示したlambda_b.goから127.0.0.1:8000を叩くのが、前述した先の連載の手法です。lambda_a.goから127.0.0.1:3000を叩くのもGoから特定のAPIを叩く処理になるので、ここでは割愛します。つまり、今回記述するのは127.0.0.1:3000を叩いたらLambdaが着火し、DynamoDBに書き込むまでの部分になります。
環境とターゲット
今回は、下記の環境で動かしました。
| 項目 | バージョン等 | 入手方法 |
|---|---|---|
| OS | macOS Mojave 10.15.5 | |
| awscli | 1.16.209 | $ pip install awscli。テストだけなら無くても動くかも。 |
| aws-sam-cli | 0.43.0 | $ pip install aws-sam-cli |
| Docker | 19.03.5 build 633a0ea | |
| go | 1.13.5 |
Web APIのリターンとして、下記を期待することにします(ただし処理はベタ書きです)
{"Company": "Future", "Year": "1989"} |
構築
ディレクトリ構成
次のような構成とします。最初に宣言したとおり、今回APIを叩くLambdaについては触れません。
apigw |
AWS SAMプロジェクトの用意
SAMのコマンドを使用して、Templatesを用意します。独自のテンプレートを用意してくることも可能ですが、今回は簡単かつシンプルにということでAWS Quick Start Templatesを使用します。
先の構成のディレクトリ内で、作業を進めます。
sam init --runtime go1.x --name apigw |
色々とできましたが、同梱されているREADME.mdに必要なことは記載してあります。そこから抜粋しますが、例えばファイル構造は以下のようになっています。
(前略) |
Lambda(Go)の記述
最初に必要なパッケージをインストールします。
go get -u github.com/aws/aws-lambda-go/lambda |
続いて、必要なパス構成にしていきます。sam initで自動生成された実行ファイルはhello-world以下に入っています。
せっかくなので、これをオリジナルな名前にします。
cd apigw |
パス構造が変わったので、Makefileとtemplate.yamlに変更を加えます。
PHONY: deps clean build |
template.yamlへの変更において、
AWSTemplateFormatVersion: '2010-09-09' |
template.yamlの内容について補足すると、これはCloudFormationの形式になっています。
このままsamのみでdeployも可能ですが、今回はテストのみなので、注記がいれてある場所のみ変更しました。
この設定で sam を立ち上げると、 http://127.0.0.1:3000/apigw にGETすると、./lambdab/lambdab が実行されることを示しています。
それではmain.go に変更を加えます。今回は、 events.APIGatewayProxyResponse のBodyと、それに応じて少しだけコードをいじっただけでほぼほぼ自動生成されたものになります。
package main |
build
諸々設定ができたら、buildして準備は完了です。
make build |
ローカルでAPIを動かしてテスト
コマンドを叩けばOKです。動き出したAPI(今回の場合 http://127.0.0.1:3000/apigw)にアクセスすると、コンテナイメージが呼び出され、実行結果が帰ってきます。
sam local start-api |
ブラウザでAPI叩くと、ちゃんと返ってきているのがわかります。
AWS SAMを利用することで、ローカルでもAPI Gatewayを意識したLambda を動作させることができました。数が少ないなら1つずつ試しても良いですし、APIを適宜叩くツールを用意すれば、自動にテストを行うこともできます。
DynamoDB localとの連携
続いて、SAM上で動かすLambdaからDynamoDB localにアクセスします。
注意事項として、DynamoDB localはdocker上で動くので、SAMとDynamoDB localを同じdocker-networkにする必要があります。
DynamoDB localの準備
AWS profile(初回のみ) |
これでテスト用のdynamoDBができました。ここにテスト用のテーブルを切ります。テーブルはaws-cliを使います。
{ |
テーブルを切ります。
$ aws dynamodb --profile local --endpoint-url http://localhost:8000 create-table --cli-input-json file://./testdata/db_local.json |
Goのコード修正
先程はAPIアクセスに対してレスポンスを返すだけでしたが、今度は同じ内容をDynamoDBに書き込むように修正します。
package main |
SAMによるテスト
SAMを実行するとき、docker-networkを指定します。これで、SAMで起動したdockerとDynamoDB localが同じネットワーク上に入ります。
make build |
もう1つターミナルを立ち上げてコマンドを打ちます。
先程作ったテーブルは未だ空です。これからここに書き込みます。 |
確かに、テーブルの中に値が格納されました。
まとめ
今回SAMを使ったテストができました。あとは必要に応じてAPIを叩くLambdaを作ったり、あるいはAPI Gatewayから呼び出されるLambdaを適宜増やしていくことで、目的とするシステムの開発が行なえます。
関連した記事にサーバレス連載やGo Cloud 連載がありますので、オススメです。