10分钟用Floci搭建零成本本地AWS开发环境
告别付费测试与Mock Bean!本文手把手教你用开源工具Floci在本地一键跑起完整AWS模拟器。学完后你能独立配置SDK指向本地端点,完成S3+DynamoDB+SQS的集成调试,断网开发、CI验证效率翻倍。

还在为本地测试 AWS 服务掏钱?教你免费搭建全量本地云环境
写业务代码时,你一定碰到过这种场景:
团队微服务依赖 S3 存文件、DynamoDB 记状态、SQS 削峰,但开发阶段总得连真实的 AWS 账号——不仅费钱,断网调试、CI 流水线跑起来都麻烦。有人用 Mock Bean 糊过去,但 mock 和真实行为总有差异,上了生产才发现问题。
今天我来教你用一个叫 Floci 的开源工具,在本地一键跑起完整的 AWS 模拟器。不需要 AWS 账号,不需要 Token,不需要付费,只要你有 Docker。整个环境占内存不到 20MB,启动只要几十毫秒。跟着这篇走一遍,你就能把 S3、DynamoDB、SQS 等数十个服务搬到 localhost:4566,开发测试效率直接翻倍。
前置条件
- Docker(推荐 Docker Compose V2):Floci 本身就是容器化运行,Docker 是硬性要求
- JDK 17+:本文 Java 示例基于 AWS SDK v2
- AWS CLI(可选):方便快速验证服务连通性
- 基础认知:了解 AWS SDK 的基本使用即可
为什么强调 Docker? 因为 Floci 的 Lambda、RDS、ECS 等服务直接跑真实的 Docker 容器,而不是浅层 mock,保证了和本地真实 AWS 服务的高度一致性。这也是它比早年各种 Mock Bean 方案靠谱的核心原因。
第一步:启动 Floci
最推荐的方式是 Docker Compose,配置清晰、容易管理。在你项目根目录创建 compose.yaml:
yaml
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
environment:
- FLOCI_STORAGE_MODE=hybrid # 重启不丢数据,推荐开发用
这里 FLOCI_STORAGE_MODE=hybrid 的意思是:数据主要驻留内存以保证读写速度,同时每 5 秒异步刷盘。这样即使容器重启,你的 Bucket 和表还在,不用每次重新建。如果你跑的是 CI 流水线,改成 memory 即可。
启动:
bash
docker compose up -d
等几秒后,Floci 会在后台监听 localhost:4566。你可以先验证一下:
bash
curl http://localhost:4566/_floci/ui
返回非空说明服务已就绪。如果浏览器访问 http://localhost:4566/_floci/ui,还能看到 Floci 自带的 Web Console,可视化查看所有本地资源。
端口说明:
4566是 Floci 统一的入口端口,所有 AWS 服务的 API 请求都走这里,由 Floci 内部路由分发到对应的服务处理器。这比早年每个服务占一个端口方便太多了。
第二步:配置 AWS 客户端指向本地
无论是 CLI、SDK 还是 Terraform,核心思路都一样:把 endpoint 指向本地,并提供一组合法的(但不需要真实的)凭证。
手动配置方式:
bash
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_DEFAULT_REGION=us-east-1
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
为什么凭证可以随便填? 据 Floci README 与 多账号文档:默认不校验 SigV4 签名,Access Key / Secret 填任意非空值即可(例如
test/test);若要严格验签,可设环境变量FLOCI_AUTH_VALIDATE_SIGNATURES=true。本地开发用默认即可。
配置完成后,用 CLI 创建一个 S3 Bucket 试试:
bash
aws --endpoint-url http://localhost:4566 s3 mb s3://my-dev-bucket
aws --endpoint-url http://localhost:4566 s3 ls
## 输出应包含 my-dev-bucket
能正常输出,说明你的本地环境已经通畅。
第三步:Java SDK 实战演练
光跑 CLI 不过瘾,下面用一个完整的 Java 示例,同时操作 S3、DynamoDB、SQS,模拟一个「用户上传图片 → 生成缩略图任务入队 → 任务状态入库」的流程。
最关键的点:Java SDK 要同时满足 endpointOverride 和 credentials。很多新手踩坑就在这里——忘了覆盖 endpoint 导致 SDK 还是去请求真正的 AWS。
java
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import software.amazon.awssdk.services.sqs.model.*;
import java.net.URI;
import java.util.Map;
public class FlociDemo {
private static final String ENDPOINT = "http://localhost:4566";
private static final String REGION = "us-east-1";
private static final StaticCredentialsProvider CRED =
StaticCredentialsProvider.create(
AwsBasicCredentials.create("test", "test"));
public static void main(String[] args) {
// 1. 创建 DynamoDB 客户端并建表(状态表)
var dynamo = DynamoDbClient.builder()
.endpointOverride(URI.create(ENDPOINT))
.region(Region.of(REGION))
.credentialsProvider(CRED)
.build();
dynamo.createTable(CreateTableRequest.builder()
.tableName("thumbnail-tasks")
.billingMode(BillingMode.PAY_PER_REQUEST)
.attributeDefinitions(
AttributeDefinition.builder()
.attributeName("taskId").attributeType(ScalarAttributeType.S).build())
.keySchema(
KeySchemaElement.builder()
.attributeName("taskId").keyType(KeyType.HASH).build())
.build());
// 2. 创建 SQS 队列(任务队列)
var sqs = SqsClient.builder()
.endpointOverride(URI.create(ENDPOINT))
.region(Region.of(REGION))
.credentialsProvider(CRED)
.build();
var queueUrl = sqs.createQueue(
CreateQueueRequest.builder().queueName("thumbnail-jobs").build() ).queueUrl();
// 3. 模拟:上传文件描述 + 任务入队 + 状态落库
String taskId = "task-001";
String fileName = "photo.jpg";
sqs.sendMessage(SendMessageRequest.builder()
.queueUrl(queueUrl)
.messageBody(fileName).build());
dynamo.putItem(PutItemRequest.builder()
.tableName("thumbnail-tasks")
.item(Map.of("taskId", AttributeValue.builder().s(taskId).build(),
"status", AttributeValue.builder().s("PENDING").build(),
"file", AttributeValue.builder().s(fileName).build()))
.build());
// 4. 验证:查表和消息
var scanResult = dynamo.scan(ScanRequest.builder().tableName("thumbnail-tasks").build());
System.out.println("[DynamoDB] 记录数: " + scanResult.count());
var msgResult = sqs.receiveMessage(ReceiveMessageRequest.builder()
.queueUrl(queueUrl).maxNumberOfMessages(1).build());
msgResult.messages().forEach(m -> System.out.println("[SQS] 收到消息: " + m.body()));
System.out.println("[OK] Floci 本地环境验证完成");
}
}
POM中需要引入software.amazon.awssdk:aws-sdk-java-bom管理版本。代码里的endpointOverride(...)是所有 SDK 客户端共用的关键步骤,不能漏。Floci 完全兼容 AWS SDK v2 的调用协议,你的线上代码改个 endpoint 就能直接跑本地。
常见问题与踩坑提醒
1. 启动报端口占用
4566 是 Floci 默认端口。如果你之前跑过 LocalStack,很可能它还在占着这个端口。docker ps 检查一下,停掉旧容器即可。Floci 设计为 LocalStack 的平滑替代品,镜像名直接换过来就能用。
2. 多项目并行时资源隔离
如果你的本地 Floci 环境同时跑多个项目,可以用多账号隔离能力。当 AWS_ACCESS_KEY_ID 是 12 位纯数字时(如 111111111111),Floci 会把它当做独立账号 ID,不同账号的资源完全隔离。项目 A 用 111111111111、项目 B 用 222222222222 即可互不干扰。
3. Spring Boot 集成测试
推荐使用 Testcontainers 官方模块 io.floci:testcontainers-floci(Testcontainers 1.x 用 1.14.0,2.x / Spring Boot 4.x 用 2.15.0),可以自动在测试方法级别拉起隔离的 Floci 实例,避免共享状态和端口冲突:
java
@Testcontainers
class S3IntegrationTest {
@Container static FlociContainer floci = new FlociContainer();
// floci.getEndpoint() / floci.getRegion() / floci.getAccessKey()... 直接取用
}
总结
这篇带你走完了从零搭建本地 AWS 开发环境的完整流程:
- Docker Compose 一键拉起 Floci,内存不到 20MB
- 手动导出环境变量,让 CLI/SDK 指向
localhost:4566 - Java SDK 示例演示 S3+DynamoDB+SQS 联动,核心只是加一个
endpointOverride - 掌握了持久化模式选择、多账号隔离、Testcontainers 集成三大实用技巧
你可以拿这套环境做:断网调试、本地 CI 验证、学习 AWS 服务 API 行为。GitHub 上 floci-io/floci 已经有 2.7w Star,完全 MIT 开源,没有任何付费锁或 Token 门槛。
下一步建议:打开 http://localhost:4566/_floci/ui 把玩 Web Console,尝试用 Terraform 本地编排资源,或者把你的 Spring Boot 集成测试从 Mock 全部换成 Testcontainers + Floci,感受真实 API 带来的测试信心提升。如果你有本地开发 AWS 应用的经验想分享,欢迎一起交流。