Fast, Reliable CI for AWS Services: How to Build a KUMO-based Integration Test Pipeline
CI/CDAWSTestingDevOps

Fast, Reliable CI for AWS Services: How to Build a KUMO-based Integration Test Pipeline

AAlex Mercer
2026-04-08
8 min read
Advertisement

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:

  1. Starts KUMO via Docker Compose
  2. Runs Go integration tests configured to talk to the emulator (Go AWS SDK v2)
  3. Persists data for repeatable runs and local debugging
  4. Parallellizes tests for scale and speed
  5. 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_DIR to 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_DIR per 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-data directory.

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:

  1. Go-level parallelism

    Use go test -p and subtests with t.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(); /* ... */ })
    }
    
  2. 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:4566 and http://localhost:4567.

  3. 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

  1. 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.
  2. KUMO run: change configuration to use the KUMO endpoint and run the exact same test suite. Record pipeline duration and CI minutes again.
  3. 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-data at 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.

Advertisement

Related Topics

#CI/CD#AWS#Testing#DevOps
A

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.

Advertisement
2026-04-20T09:37:00.208Z