Clouds On A Laptop
Cloud services can be emulated well enough for a laptop: Moto, DynamoDB Local, Azurite, the Google emulators - with SDK endpoint overrides, one record per resource, and every emulator placed inside the same failure domains as the rest. Only S3 is built.
👋 Hi, I'm Anton - a software engineer. These days I work on a platform: contracts, generated code, data paths and the tooling around them. Running notes live on my GitHub: github.com/brilliant-almazov.
Everything here except S3 is a proposal - none of it is built on our stand. Every claim about a tool was checked against its own documentation for this article.
This is part 7 of the series on testing cross-zone, cross-datacenter and cross-provider behaviour on a laptop. Maybe you already do it better, maybe you'd do it another way - this is how it is going, and where it stops.
The only cloud we touch
Part 6, Every Verdict Carries A Trace, was about how a result is checked. This part asks what a laptop can stand in for when the thing being called is a cloud service.
For us the honest answer starts small. The platform touches the cloud through exactly one API: S3. The stand already emulates it with a small S3-compatible server, versitygw, Apache-2.0. Because the platform speaks only the S3 API, any S3-compatible endpoint would do.
That is all that is built. No queue emulator, no function emulator, no document database emulator - no service of ours depends on one yet. The rest of this part is how it can be done when one does, with forms that are proposals, each marked "not built".
What exists to emulate the rest
The landscape, checked against primary sources:
| Tool | Emulates | Licence and status | Source |
|---|---|---|---|
| Moto (server mode) | S3, DynamoDB, SQS, SNS, Lambda, API Gateway and more, on one endpoint | Apache-2.0, active | Moto, server mode |
| DynamoDB Local | DynamoDB | a free download from AWS | AWS |
| ElasticMQ | a queue with an SQS-compatible interface | open source | ElasticMQ |
| Azurite | Azure Blob, Queue and Table (Table in preview) | MIT, active | Azurite, Microsoft Learn |
| gcloud emulators | Pub/Sub, Bigtable, Firestore, Spanner | ship with the gcloud CLI | Pub/Sub, Bigtable, gcloud |
| fake-gcs-server | Google Cloud Storage | BSD-2-Clause | fake-gcs-server |
| LocalStack | a wide AWS surface | needs an auth token; free plan non-commercial only | auth token, pricing |
One correction from reading the sources: an earlier analysis said Lambda in Moto is only mocked. The Moto documentation says otherwise - by default it runs the function code inside a Docker container, and only without Docker does it return a canned response (Moto Lambda).
Two that changed
Two well-known names have changed status, and both were checked at the source:
- LocalStack - the community repository was archived on 23 March 2026 as the project consolidated into a single image (GitHub). An auth token is now a mandatory credential to start the container, with a dedicated token for CI (docs). The free Hobby plan is for non-commercial use; commercial development needs a paid plan (pricing).
- MinIO - the repository was archived on 25 April 2026 and says it is no longer maintained (GitHub). We do not use it; the S3 server above is a different one.
Neither is a judgement of the tools. Both are reasons to check the source before a dependency goes into a stand.
Pointing a service at an emulator
The cheapest part is the one that needs no code. Every major cloud SDK already has a way to change where it sends requests. For AWS it is a standard variable, global or per service, with a defined order of precedence (AWS SDKs). A proposal for the stand, not built:
# not built - a proposal AWS_ENDPOINT_URL=http://cloud-aws.internal:5000 AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_REGION=eu-central-1 AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=<azurite well-known dev key>;BlobEndpoint=http://cloud-azure.internal:10000/devstoreaccount1; PUBSUB_EMULATOR_HOST=cloud-gcp.internal:8085 STORAGE_EMULATOR_HOST=http://cloud-gcp-gcs.internal:4443 Services keep production-shaped names (*.internal), and credentials are dummies - the emulators do not check them. LocalStack's token is the one exception. For Pub/Sub, setting PUBSUB_EMULATOR_HOST is enough for most client libraries; Java, C# and Rust need a code change (Pub/Sub emulator).
One record per resource
On the stand every resource is one record, the same shape as the S3 one. The cloud emulators would be records too, each behind its own optional profile:
# cloud-aws (PROPOSAL, not built) resource: true kind: cloud-aws image: motoserver/moto:<pin> profiles: [cloud-aws] port: 5000 # one endpoint for all mocked AWS services mem: <measured when added> # cloud-aws-dynamodb (only if real DynamoDB semantics are needed): amazon/dynamodb-local, port 8000 # cloud-azure: mcr.microsoft.com/azure-storage/azurite, profiles [cloud-azure], ports 10000 / 10001 / 10002 # cloud-gcp: the google-cloud-cli emulators image, `gcloud beta emulators pubsub start --host-port=0.0.0.0:8085` # cloud-aws-localstack (paid, the owner's decision only): localstack/localstack, port 4566, secrets [LOCALSTACK_AUTH_TOKEN] The recommendation behind it: not now, because nothing depends on it. When the first integration appears, three optional profiles - cloud-aws on Moto, cloud-azure on Azurite, cloud-gcp on the CLI emulators plus fake-gcs-server - and LocalStack only if the owner decides it is needed and pays for it.
Clouds inside the failure domains
This is the idea of the part. An emulator is a container like any other, so it can be placed on the planet of part 3 - in a zone of "its" provider:
# not built - a proposal placement: cloud-aws: [dc-a1-z1] # prov-a cloud-azure: [dc-b1-z1] # prov-b cloud-gcp: [dc-a2-z1] Then the chaos of part 3 applies to the cloud as well. provider-down prov-a takes the AWS emulator down together with every site of prov-a - and, in this placement, the Google emulator too, since dc-a2 is a prov-a site. link-degrade dc-a1~dc-b2 rtt_ms=200 adds latency between a service on the US side and the AWS emulator. Nothing new is needed - the same netem and iptables rules as any placed container.
A cloud outage stops being a special case to mock. It becomes "the provider's sites went down", which the stand already knows how to do.
One command
All of it would hang off the same tool and the same profiles:
# not built - a proposal ./env up --profile dev --profile cloud-aws ./env up --profile ha --profile cloud-aws --profile cloud-azure --latency declared ./env scenario provider-down --latency declared Limits
An emulator is not a cloud, and the gaps are known:
- one emulator is one more container; its memory is to be measured when it is added;
- IAM, quotas, cold starts, service limits and regional differences are not emulated, or are simplified - the Pub/Sub emulator, for one, supports no IAM operations (Pub/Sub emulator);
- full fidelity for functions and API gateways is what LocalStack sells; Moto runs function code in Docker, but it is still Moto's model of the service;
- every cloud has its own API, so "one function on three providers" is three integrations in code, not one.
A comparison of event runners - Lambda event source mappings, Knative, OpenFaaS, Temporal, KEDA - is planned, not written.
One way to check it
How would anyone know an emulator is good enough? QA has one way to check it - their idea, not approved by the owner yet. An emulated queue or function is checked as if it were the real one:
- contract - status codes and error classes match the declared API;
- semantics - at-least-once delivery, order, dead-letter, visibility timeout;
- failure - the same daemon × queue matrix as part 6;
- observability - a trace passes through the emulator, queue metrics reach the metrics store;
- isolation - zero outbound connections;
- and a separate row, emulator vs cloud, that names every known difference.
The last row is the honest one. An emulator that passes everything else still differs somewhere, and the row is where that is written down instead of discovered.
What I do not claim
- Not that any cloud emulator except S3 runs on our stand. Everything else is a proposal.
- Not that emulators are clouds. IAM, quotas, cold starts and limits are not there.
- Not that the check is agreed. It is QA's proposal.
- Not a recommendation for or against any vendor. The status lines are what their own pages say.
What of this is method
- Check the source before the dependency. Two well-known tools changed status this year.
- Point, do not patch. SDK endpoint variables move a service to an emulator without code.
- Place the cloud on the planet. An emulator in a zone falls under the same chaos as everything else.
Cross-anything on a laptop - Part 7. Next: Providers On A Laptop.
If you emulate AWS locally, which tool, and what did it get wrong? If you dropped LocalStack or MinIO this year, what replaced it? If you have tested a cloud outage, how did you fake it? Which cloud service would you emulate first?










