§ Documentation
Quick Start
Run cloudemu as a server and point your real app at it in 5 minutes
cloudemu is a real cloud emulator: it speaks the actual AWS, Azure, and GCP wire protocols, so you point real SDK clients, CLIs, and apps at it and run production code unchanged.
The fastest way to integrate it is server mode: run the binary (or Docker image) and set your SDK's endpoint at the printed address. Your already-running app now talks to an in-memory cloud over the real wire — the same code path it uses in production. This is the default for integration and end-to-end work.
No mocks. No cloud accounts. No bills — just a running endpoint your code already knows how to talk to.
Install#
go install github.com/stackshy/cloudemu/v2/cmd/cloudemu@latestNo Go toolchain? Use the published Docker image instead — see Run the server.
Run the server#
cloudemu serveOn start it prints the live endpoints:
cloudemu — standalone server
────────────────────────────
AWS http://127.0.0.1:4566
Azure https://127.0.0.1:4568 (self-signed TLS)
GCP http://127.0.0.1:4569
Kubernetes http://127.0.0.1:4570Or with Docker, no Go required:
docker run --rm -p 4566:4566 -p 4568:4568 -p 4569:4569 ghcr.io/stackshy/cloudemu:latestPoint your app at it#
The only thing that changes vs. real AWS is the endpoint. Every other line of your production code stays identical. For the AWS CLI and any language's SDK, the AWS_ENDPOINT_URL env var is enough:
export AWS_ENDPOINT_URL=http://127.0.0.1:4566
aws s3 mb s3://app-deployments # your real CLI, unchanged
aws s3 cp ./config.yaml s3://app-deployments/v1.0/config.yamlIn aws-sdk-go-v2, override BaseEndpoint where your app builds its client:
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("http://127.0.0.1:4566")
o.UsePathStyle = true
})
// ↓ This is your real production code, unchanged. ↓
client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("app-deployments")})Done. Real server, real SDK, in-memory backend, ~10 ms per call.
What just happened#
The server speaks the actual AWS wire protocol (S3 REST + XML, DynamoDB JSON-RPC, EC2 query, SQS AwsJson1_0, CloudWatch Smithy CBOR, Lambda REST). The SDK can't tell the difference between this and s3.amazonaws.com.
The endpoint override, every SDK#
The endpoint override is the only change your app needs. Point your provider's client at the matching port — the tabs below stay in sync across the site, so pick your provider once.
// Any language / the CLI: set AWS_ENDPOINT_URL=http://127.0.0.1:4566
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("http://127.0.0.1:4566")
o.UsePathStyle = true
})
// Any credentials work — cloudemu doesn't validate signatures.// Served over HTTPS with a self-signed cert — point the SDK through a cloud.Configuration.
cloudCfg := cloud.Configuration{
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Endpoint: "https://127.0.0.1:4568",
Audience: "https://management.azure.com",
},
},
}
opts := &arm.ClientOptions{ClientOptions: azcore.ClientOptions{Cloud: cloudCfg}}// REST endpoint via google.golang.org/api or the cloud.google.com/go SDKs.
client, _ := storage.NewClient(ctx,
option.WithEndpoint("http://127.0.0.1:4569"),
option.WithoutAuthentication())See Standalone Server for ports, flags, cloudemu env, Testcontainers, and the /_cloudemu/reset control plane; and Integrating cloudemu to make the endpoint injectable so the same code hits real cloud in prod and cloudemu in tests.
Library mode — Go unit tests only#
If you're writing unit tests inside Go code that imports cloudemu, you can skip the separate process and stand the server up in-process with httptest. Use this only for unit tests — for integrating an existing service, prefer server mode above.
cloud := cloudemu.NewAWS()
ts := httptest.NewServer(awsserver.New(awsserver.Drivers{
S3: cloud.S3, DynamoDB: cloud.DynamoDB, EC2: cloud.EC2,
Lambda: cloud.Lambda, SQS: cloud.SQS, CloudWatch: cloud.CloudWatch,
}))
defer ts.Close()
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String(ts.URL) // same override, in-process URL
o.UsePathStyle = true
})The Portable Go API goes one step further — call the in-memory drivers directly, no HTTP at all.
SDK-compat coverage#
Every domain ships HTTP wire-format handlers across all 3 providers:
| Domain | AWS | Azure | GCP |
|---|---|---|---|
| Storage | S3 | Blob | GCS |
| Compute | EC2 + full VPC stack | Virtual Machines + Disks/Snapshots/Images | Compute Engine + Disks/Snapshots/Images |
| Database (NoSQL) | DynamoDB | Cosmos DB | Firestore |
| Relational DB | RDS + Redshift | SQL + Postgres/MySQL Flex | Cloud SQL |
| Networking | (in EC2) | VNet | VPC + Firewalls |
| Monitoring | CloudWatch | Azure Monitor | Cloud Monitoring |
| Serverless | Lambda | Functions | Cloud Functions |
| Kubernetes | EKS | AKS | GKE |
| Message Queue | SQS | Service Bus | Pub/Sub |
| Logging | CloudWatch Logs | Log Analytics | Cloud Logging |
| DNS | Route 53 | Azure DNS | Cloud DNS |
| Load Balancer | ELBv2 | Load Balancer | Cloud Load Balancing |
| Cache | ElastiCache | Azure Cache | Memorystore |
| Secrets | Secrets Manager | Key Vault | Secret Manager |
| Notification | SNS | Notification Hubs | FCM |
| Event Bus | EventBridge | Event Grid | Eventarc |
| IAM | IAM | IAM | IAM |
| Container Registry | ECR | ACR | Artifact Registry |
| Resource Discovery | Resource Explorer + Tagging | Resource Graph | Cloud Asset Inventory |
Plus provider-specific Generative AI (Bedrock + SageMaker on AWS, Vertex AI on GCP) and Databricks (Azure). Kubernetes also ships a shared in-memory data plane that client-go / kubectl drive end-to-end.
Everything is equally reachable through the Portable Go API when you'd rather skip HTTP.
Next steps#
- Standalone Server — ports, flags,
cloudemu env, Testcontainers, reset - Integrating cloudemu — make the endpoint injectable so prod hits real cloud, tests hit cloudemu
- SDK-Compatible Server — full coverage tables, protocol detection, registration ordering
- Chaos Engineering — inject failures while real SDKs are talking to cloudemu