Floci でローカル AWS を動かしてみた - LocalStack 代替ツール
背景
iOS アプリのプッシュ通知を SQS + Lambda でバッチ処理する構成を組んでいて、実機に上げる前にローカルで同じフローを動かしたかった話です。
SQS にメッセージが溜まって Event Source Mapping 経由で Lambda がまとめて起動し、APNs に投げる。これを丸ごとローカルで動かせるツールを探しました。
検証ツール探し
最終的に Floci に落ち着くまで、何種類か試しました。
vercel-labs/emulate
Inspector の Web UI は良かったのですが、SQS が旧来のクエリ API (XML) のみ対応で、AWS SDK v3 の JSON プロトコルと噛み合わず見送りました。
LocalStack
コミュニティ版が 2026 年 3 月にサンセットし、アカウント必須になっていたので候補から外しました。
floci-io/floci
最終的にたどり着いたのが floci-io/floci です。LocalStack の代替として登場したツールです。
Floci とは
MIT ライセンスでアカウント不要。Docker イメージ 90MB、起動 24ms 程度と軽快です。
SQS、Lambda、S3、DynamoDB、CloudWatch Logs、Event Source Mapping をネイティブサポートしています。Lambda は実 Docker コンテナとして起動する方式で、ESM も期待通り動きます。
Docker Compose の構成
services:
floci:
image: hectorvent/floci:latest
container_name: floci
ports:
- "4566:4566"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
environment:
- FLOCI_DEFAULT_REGION=ap-northeast-1
- FLOCI_SERVICES_LAMBDA_DOCKER_NETWORK=floci-net
user: root
networks:
- floci-net
networks:
floci-net:
external: true
/var/run/docker.sock をマウントして Lambda コンテナを起動できるようにし、FLOCI_SERVICES_LAMBDA_DOCKER_NETWORK で Lambda コンテナを同じネットワークに置くと、Runtime API へのコールバックが通ります。
SQS + Lambda + ESM
AWS SDK v3 を endpoint だけ差し替えて使えます。本番コードとの差分は URL だけです。
import { readFileSync } from "node:fs";
import { SQSClient, CreateQueueCommand } from "@aws-sdk/client-sqs";
import { LambdaClient, CreateFunctionCommand, CreateEventSourceMappingCommand } from "@aws-sdk/client-lambda";
const common = {
endpoint: "http://localhost:4566",
region: "ap-northeast-1",
credentials: { accessKeyId: "test", secretAccessKey: "test" },
};
const sqs = new SQSClient(common);
const lambda = new LambdaClient(common);
const { QueueUrl } = await sqs.send(new CreateQueueCommand({ QueueName: "notif-q" }));
await lambda.send(new CreateFunctionCommand({
FunctionName: "notif-handler",
Runtime: "nodejs20.x",
Role: "arn:aws:iam::000000000000:role/lambda-role",
Handler: "index.handler",
Code: { ZipFile: readFileSync("./function.zip") },
Timeout: 30,
}));
await lambda.send(new CreateEventSourceMappingCommand({
FunctionName: "notif-handler",
EventSourceArn: "arn:aws:sqs:ap-northeast-1:000000000000:notif-q",
BatchSize: 10,
MaximumBatchingWindowInSeconds: 15,
}));
バッチ処理の検証
メッセージを 5 件連続で送ると、15 秒のウィンドウで集約されて 1 回の Lambda 起動にまとまりました。
ESM f37d2ce1-...: received 5 message(s), invoking notif-std-handler
Launching container for function: notif-std-handler
Created log group: /aws/lambda/notif-std-handler in region ap-northeast-1
[Lambda] Received 5 SQS messages
[Lambda] User kusumoto: 5 件のノートが更新されました
Lambda が実 Docker コンテナで起動し、CloudWatch Logs 相当のロググループにもログが流れています。
実機への APNs 配信
Lambda ハンドラ内で APNs の HTTP/2 呼び出しを行うと、実機の iPhone にバッチ通知が届きました。Lambda コンテナは外部インターネットに出られるので、APNs Sandbox にそのまま送れます。
まとめ
AWS SDK v3 を endpoint 差し替えだけで使え、Lambda が実 Docker コンテナで動き SQS の ESM も効く。ローカル検証したい構成がそのまま動く感覚で、LocalStack の代替を探している方にはおすすめです。