Fast, Reliable CI for AWS Services: How to Build a KUMO-based Integration Test Pipeline
Hands‑on walkthrough: replace slow AWS integration tests with KUMO—local setup, Docker Compose, persistence, parallelization, and measuring savings.
Integration tests that hit real AWS services are reliable but often slow and costly. KUMO is a lightweight AWS emulator written in Go that lets engineering teams run hundreds of cloud integration tests locally or in CI without hitting AWS. This hands‑on walkthrough shows how to replace slow cloud integration tests with KUMO: local setup, Docker Compose, persisting test state, parallelizing tests, and measuring time/cost savings versus real AWS.
Why use KUMO?
KUMO is designed as a small, fast alternative to full-service emulators like LocalStack. Its main selling points for CI/CD pipelines:
- Single binary and Docker image for easy distribution
- No authentication required (great for CI agents)
- Lightweight with fast startup time
- AWS SDK v2 compatible (works with Go AWS SDK v2)
- Optional data persistence so test state can survive restarts via
KUMO_DATA_DIR
Supported services cover the common set you’ll need for most integration tests: S3, DynamoDB, SQS, SNS, Lambda, ECS, RDS, and many more.
Overview of the pipeline
We’ll build a pipeline that:
- Starts KUMO via Docker Compose
- Runs Go integration tests configured to talk to the emulator (Go AWS SDK v2)
- Persists data for repeatable runs and local debugging
- Parallellizes tests for scale and speed
- Measures time and cost savings relative to real AWS runs
Local setup: run KUMO with Docker Compose
Create a minimal Docker Compose file that starts KUMO and mounts a host path for persistent data. KUMO exposes a single port (compatible with common AWS emulator conventions) so your SDK clients can point to it via an endpoint override.
# docker-compose.yml
version: '3.8'
services:
kumo:
image: sivchari/kumo:latest
ports:
- "4566:4566" # Emulator endpoint
environment:
- KUMO_DATA_DIR=/data
volumes:
- ./kumo-data:/data
restart: no
Start KUMO:
docker-compose up -d kumo
# verify
docker-compose logs -f kumo
Notes:
- Map
KUMO_DATA_DIRto a host directory for persistence. - Expose the emulator on a stable port (4566 is commonly used by similar tools).
- In CI, you can use the same Compose file or a simpler docker run command.
Configure Go tests to use KUMO (Go AWS SDK v2)
Point the AWS SDK at the local emulator using an endpoint resolver. Because KUMO does not require authentication, use simple dummy credentials or an anonymous provider if your code requires credentials.
import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
awscreds "github.com/aws/aws-sdk-go-v2/credentials"
)
func TestS3PutGet(t *testing.T) {
// Load default config but override endpoint and credentials
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion("us-east-1"),
config.WithEndpointResolver(aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
return aws.Endpoint{URL: "http://localhost:4566"}, nil
})),
config.WithCredentialsProvider(awscreds.NewStaticCredentialsProvider("test","test","")),
)
if err != nil {
t.Fatal(err)
}
s3Client := s3.NewFromConfig(cfg)
// run test flow against emulator
}
Tip: Keep your production code configurable so tests can inject an endpoint and credentials without touching app logic.
Persisting test state with KUMO_DATA_DIR
Persisting the emulator's data directory is essential for two workflows:
- Faster debugging — keep the same state across restarts
- Snapshotting — capture a known-good fixture data set that many CI runs can reuse
Use volumes in Docker Compose (see earlier snippet). In CI, you can populate kumo-data on the runner or mount an S3-backed cache. Be mindful of test isolation—if you persist state across concurrent runs, you must ensure tests use unique prefixes or separate data directories (see test isolation below).
Test isolation strategies
Even with a local emulator, tests must be isolated to avoid flaky failures. Use one or more of these patterns:
- Resource prefixes: prefix buckets, table names, and ARNs with a run-specific UUID.
- Per-run data directory: start a fresh KUMO instance with its own
KUMO_DATA_DIRper CI job. - Per-service instances: run separate KUMO instances for separate test suites when strong isolation is needed.
- Automated cleanup: include teardown steps that remove resources or delete the
kumo-datadirectory.
Example of a unique prefix in Go:
prefix := fmt.Sprintf("test-%s-", uuid.New().String())
bucket := prefix + "my-bucket"
Parallelizing tests in CI
To speed up large test suites, run tests in parallel both within a test process and across multiple CI agents or containers. Here are practical approaches:
- Go-level parallelism
Use
go test -pand subtests witht.Parallel()for intra-process parallelism:func TestSomething(t *testing.T) { t.Run("case1", func(t *testing.T) { t.Parallel(); /* ... */ }) t.Run("case2", func(t *testing.T) { t.Parallel(); /* ... */ }) } - Shard test suites across multiple KUMO instances
Start several KUMO containers on different ports and mount distinct data dirs. Then run disjoint test subsets against each emulator. Example Docker Compose fragments:
services: kumo-a: image: sivchari/kumo:latest ports: - "4566:4566" environment: [KUMO_DATA_DIR=/data] volumes: [./kumo-data-a:/data] kumo-b: image: sivchari/kumo:latest ports: - "4567:4566" # map host 4567 to container 4566 environment: [KUMO_DATA_DIR=/data] volumes: [./kumo-data-b:/data]Then configure different test jobs to target
http://localhost:4566andhttp://localhost:4567. - CI matrix or job-level parallelism
In GitHub Actions, GitLab CI, or CircleCI, use a matrix to split tests across runners. Each runner can start a dedicated KUMO instance with its own data dir.
Measuring time and cost savings
To justify adopting KUMO-based local integration testing, measure both time and cost differences between running tests against real AWS and against KUMO.
What to measure
- Total CI pipeline wall time
- Per-test execution time distribution
- Number of AWS API requests performed by tests
- Direct AWS request costs (optional, usually small) and indirect costs (CI minutes billed)
Example measurement workflow
- Baseline: run your integration test suite pointing at an AWS test account. Collect pipeline duration and CI billable minutes (e.g., GitHub Actions). Note the number of runs per week.
- KUMO run: change configuration to use the KUMO endpoint and run the exact same test suite. Record pipeline duration and CI minutes again.
- Compare: compute per-run time savings and annualize.
Example numbers (illustrative):
- Real AWS run time: 18 minutes
- KUMO run time: 3 minutes
- Savings per run: 15 minutes
- Runs per week: 50
- Weekly saved minutes: 750 (12.5 hours)
- Annual saved hours: ~650 hours
If your CI provider bills $0.02 per runner-minute, the saved CI cost per year would be approximately 650 * 60 * 0.02 = $780. Even if AWS request costs were only a few dollars, removing live network latency and cross‑account failures provides much larger developer productivity gains.
Key tip: measure actual pipeline durations and CI billable metrics. Use the CI provider’s API to collect accurate data over several runs before committing to a change.
Putting it together in GitHub Actions (example)
A compact GitHub Actions job that starts KUMO and runs a Go test suite:
jobs:
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Start KUMO
run: |
docker run -d --name kumo -p 4566:4566 -v ${{ github.workspace }}/kumo-data:/data sivchari/kumo:latest
- name: Run tests
env:
AWS_REGION: us-east-1
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
AWS_ENDPOINT: http://localhost:4566
run: |
go test ./... -run Integration -v
Common pitfalls and how to avoid them
- SDK credential errors: if your SDK insists on credentials, set dummy static credentials in CI.
- Port collisions when parallelizing: map different host ports to the container port or use separate runners.
- State leakage across runs: either wipe
kumo-dataat the start of each run or spin a new instance per job. - Differences from AWS: KUMO implements many services but not every subtle behavior of AWS. Keep a small smoke test suite against real AWS for production-critical differences.
When to still run tests against real AWS
Use KUMO for the bulk of integration tests to get speed and determinism, but retain a small, fast smoke test suite against real AWS in a gated pipeline prior to production deploys. This hybrid approach balances speed and real-world validation.
Next steps and resources
Try converting a failing/flaky integration test to run with KUMO and measure the before/after runtime. If you need inspiration for developer productivity improvements in CI/CD, check out this guide on mastering developer tooling and agents: Mastering AI Agents.
KUMO gives teams a pragmatic, fast path to reliable integration testing without the cost and latency of live AWS calls. With Docker Compose for local development, CI integration, persistent data dirs for reproducibility, and simple parallelization strategies, you can expect drastically faster feedback loops and lower CI costs.
Checklist to adopt KUMO in your pipeline
- Create Docker Compose and mount
KUMO_DATA_DIR - Make SDK endpoints configurable and wire tests to the emulator
- Implement resource prefixing or per-run data dirs for isolation
- Parallelize using multiple emulator instances or CI matrix
- Measure baseline and emulator runs to quantify savings
Ready to get started? Clone the KUMO repo, build the image if you need a custom binary, and swap out one or two integration tests to validate the flow before converting your entire suite.
Related Topics
Alex Mercer
Senior DevOps Editor
Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.
Up Next
More stories handpicked for you
From AWS Controls to Executable Tests: Building a Local Security Validation Pipeline with an AWS Emulator
How to Access and Utilize Azure Logs in Hytale for Enhanced Gameplay
How to Build a Fast, Deterministic AWS Mock Layer for CI Without Paying for Cloud Emulators
The Subscription Model's Impact on App Economy: A Developer's Perspective
How to Simulate AWS Dependencies in CI Without Slowing Down Your Test Pipeline
From Our Network
Trending stories across our publication group