AWSを使った開発では、
- ちょっとした修正でもdev環境へデプロイが必要
- S3イベントを試したいだけなのに時間がかかる
- Lambdaとの連携を気軽に確認したい
という場面がよくあります。
そんなときに便利だったのが LocalStack でした。
この記事では、実際によくある
S3 → Lambda
の構成をローカルで動かす手順を紹介します。
LocalStackを使う理由
通常の開発フローはこんな感じです。
コード修正
↓
AWSへデプロイ
↓
動作確認
ちょっとした修正でも数分待つことがあり、繰り返していると意外と時間を使います。
LocalStackを使うと、
コード修正
↓
ローカルで動作確認
という流れになるため、試行錯誤のサイクルをかなり短縮できます。
個人的には次のようなケースで特に便利だと感じました。
- S3イベント
- Lambda実行
- SQS連携
- Parameter Store(SSM)を使った検証
LocalStackを起動する
まずはDocker ComposeでLocalStackを起動します。
version: "3.8"
services:
localstack:
image: localstack/localstack:latest
container_name: localstack
ports:
- "4566:4566"
environment:
- SERVICES=s3,lambda
- DEBUG=1
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
起動します。
docker compose up -d
LocalStackへ入る
公式イメージには awslocal が入っているので、そのまま利用できます。
docker exec -it localstack bash
以降の操作はコンテナ内で行います。
S3バケットを作成する
awslocal s3 mb s3://my-bucket
確認します。
awslocal s3 ls
Lambdaを作成する
今回は動作確認用にシンプルなLambdaを用意します。
exports.handler = async (event) => {
console.log("Event:", JSON.stringify(event));
return {
statusCode: 200,
};
};
ZIP化します。
zip function.zip index.js
続いてLambdaを登録します。
awslocal lambda create-function \
--function-name my-function \
--runtime nodejs18.x \
--handler index.handler \
--zip-file fileb://function.zip \
--role arn:aws:iam::000000000000:role/lambda-role
S3イベントを設定する
S3へファイルがアップロードされたらLambdaを呼び出すよう設定します。
awslocal s3api put-bucket-notification-configuration \
--bucket my-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [{
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:my-function",
"Events": ["s3:ObjectCreated:*"]
}]
}'
動作確認
適当なファイルをアップロードします。
echo "test" > test.txt
awslocal s3 cp test.txt s3://my-bucket/
ログを確認します。
awslocal logs describe-log-groups
イベントが正しく設定されていれば、Lambdaが実行されます。
Laravelから接続する場合
.env
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=my-bucket
AWS_ENDPOINT=http://localstack:4566
AWS_USE_PATH_STYLE_ENDPOINT=true
config/filesystems.php
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => true,
],
use_path_style_endpoint はLocalStackを利用する場合に設定しておくと安心です。
ハマりやすかった点
endpointを指定し忘れる
AWS SDKやAWS CLIでエンドポイントを指定しないと、本物のAWSへ接続してしまいます。
LocalStackを利用する場合は、エンドポイントの指定を忘れないようにします。
localhost問題
Dockerコンテナ同士で通信する場合は
http://localstack:4566
を利用します。
コンテナ内から localhost を指定しても接続できません。
IAMの挙動が本番と異なる
LocalStackは便利ですが、IAMの検証は実AWSほど厳密ではありません。
ローカルでは問題なく動いても、本番AWSでは権限不足になるケースもあります。
そのため、最終確認は実際のAWS環境で行うようにしています。
LocalStackを使って感じたこと
LocalStackは「AWSを完全に再現するツール」というより、
AWSを使った開発を効率化するためのツール
という印象でした。
ローカルで何度も試行錯誤できるため、実装スピードはかなり上がります。
一方で、本番との差異がゼロではないため、最後は実AWSで確認する運用が安心です。
私の中では、
- ローカル:LocalStack
- CI・検証環境:実AWS
という使い分けが一番しっくりきています。
まとめ
LocalStackを使うことで、
- S3
- Lambda
- SQS
- Parameter Store
などの連携をローカルで素早く確認できるようになります。
毎回AWSへデプロイして動作確認していると、少しずつ待ち時間が積み重なります。
ローカルで完結できる部分はLocalStackを活用し、最終確認だけ実AWSで行うようにすると、開発効率を上げつつ安全性も確保しやすいと感じました。