背景
普段Lambdaの実装を行う際に、このLambdaは本番環境にデプロイ後、正しく動作するのか?と疑問に思うことはあると思います。
そういった場合、動作を保証するためにローカルでテストを行いますが、このテストも本番に近い状態で行うことが出来れば、安心して開発を進めることができると思います。
今回はLocalStackを利用して、ローカル環境にAWSをエミュレートし、開発やテストを本番環境に近い状態で進める方法を紹介します。
- これからLocalStackを使いたいと考えている方
- LocalStackを使った開発・テストの流れを知りたい方
LocalStackとは?
LocalStackはローカル環境でAWSのクラウドサービスをエミュレートするためのオープンソースのフレームワークです。
ローカルに本番環境と同じような環境を作成することで、開発やテストをより本番に近い形で進めることができます。
またローカルで開発を進める為、AWSリソースの使用量が減り、コスト削減にもつながります。
料金
LocalStackは現時点で、4つの料金プランが用意されています。
- Community(無料)
- Pro
- Teams
- Enterprise
Community版であれば無料で使うことが出来ますが、エミュレートできるAWSサービスに制限があるので、どのサービスが無料範囲なのかは、以下の公式ページから確認してみて下さい。
Community版でもLambda・S3・DynamoDB・API Gatewayなどのサービスは無料で使うことができるようです。
実際にLocalStackを試してみる
では実際にLocalStackを使ってローカル開発をしていきます。
今回はS3からデータを取得するLambda関数を元に、LocalStackの基本的な使い方を紹介します。
事前準備・バージョン確認
LocalStack環境を構築するにはDockerが必要です。
今回はDocker Composeを使った方法でLocalStackを立ち上げます。
Docker | 25.0.3 |
Docker Compose | 2.24.5 |
Node | 20.11.0 |
TypeScript | 5.3.2 |
Jest | 29.7.0 |
@aws-sdk/client-s3 | 3.507.0 |
docker-compose.ymlの作成
Docker Composeを使った設定は公式ドキュメントを参考にしています。
またdocker compose以外にも構築方法があるようです。
作成後、docker-compose upで起動します。
起動が完了するとLocalStackにアクセスできます。
version: "3.8"
services:
localstack:
container_name: "LOCALSTACK-NODE-PJ"
image: localstack/localstack
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
environment:
- DEBUG=1
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
LocalStackのS3にバケットとサンプルオブジェクトを用意する
LocalStackにアクセスする準備は用意できたので、LocalStackにS3のバケットとサンプルオブジェクトを設置します。
今回はawslocalというパッケージを利用して、CLIからを作ります。
awslocalはAWS CLI
をLocalStack向けにラップしたパッケージです。
インストール後、sample.txtという適当なファイルをディレクトリに用意し、以下のコマンドをターミナルで実行します。
# S3バケット作成
awslocal s3 mb s3://localstack-bucket
# S3用のサンプルデータをセットする
awslocal s3 cp sample.txt s3://localstack-bucket/
これでLocalStack上に、localstack-bucketバケットとバケット内にsample.txtが設置されます。
今回はCLIを使って作成しましたが、AWS SDKを使ってLocalStackにデータを用意することも可能です。
LocalStackのS3からデータを取得
LocalStackのS3に設置されたデータを取得するLambdaを実装します。
- S3のConfig設定ファイル
import { S3ClientConfig } from "@aws-sdk/client-s3";
export const s3Config: S3ClientConfig = {
region: 'ap-northeast-1'
}
- Lambdaコード
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { s3Config } from "./config";
const client = new S3Client(s3Config);
export const handler = async () => {
try {
const objectResponse = await getObject(client);
return objectResponse;
} catch (error) {
throw error
}
}
export const getObject = async (client: S3Client) => {
const command = new GetObjectCommand({
Bucket: 'localstack-bucket', // awslocalで作成したバケット名
Key: "sample.txt",
});
try {
const response = await client.send(command);
if(!response.Body) return;
const str = await response.Body.transformToString();
return str
} catch (err) {
console.error(err);
}
};
- Jestを使ったテストコード
import { handler } from "../src/sampleLocalstack"
// テスト時にconfigをモックしてLocalStackに接続
jest.mock('../src/config.ts', () => ({
s3Config: {
endpoint: "https://s3.localhost.localstack.cloud:4566",
region: 'ap-northeast-1',
credentials: {
accessKeyId: "",
secretAccessKey: ""
},
}
}))
describe("get s3 object", () => {
test("LocalStackのS3バケットからS3データの中身を取得", async () => {
const response = await handler();
expect(response).toEqual("sample s3");
});
})
ポイントはS3Clientに渡すConfig部分です。
テストコードでJest.mockを使い、endpointをLocalStackのエンドポイントに、credentialsを仮のものに置き換えています。
この設定により、ローカルの単体テストでLocalStackのS3にアクセスすることが出来ます。
コンソールから確認する
LocalStackには公式サイトでサインアップ後、以下のように画面上からもデータの動きを確認することができます。
↓ LocalStack上のS3がRunning状態
↓S3をクリックすると、作成したバケットがあることが確認できる
まとめ
今回LocalStackを試してみて、ローカルでの開発・テストがより安定すると思いました。
無料の範囲でも多くのAWSサービスをローカル環境で再現できるので、とても便利だと思います。