How to run Docker Compose integration tests in a cloud sandbox
Upload the repo, run sudo enable-docker, then docker compose up --wait and docker compose run your test service; copy the reports out.
On Runtime, a Compose stack gets a whole microVM, not a shared Docker
host. Every sandbox is a Firecracker machine with its own kernel and its own
Docker daemon, so parallel CI jobs never collide on ports, volumes or
container names, and root inside one cannot touch another. A stack that idles
between requests pays mostly for memory: $0.03125 an hour for 2 vCPU and
4 GiB at rest and $0.08 at full load (pricing). On
25 September 2026, Ubuntu 24.04's updates carried Docker 29.1.3 and Compose
2.40.3, the archive enable-docker installs from.
Run the suite
The pattern: start the services the tests depend on, wait until their health checks pass, run the test container once, keep its exit code.
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ diskMiB: 10_240, timeoutSeconds: 3600 });const long = { timeoutMs: 1_800_000, cwd: "/workspace/app" } as const;await sbx.files.upload("./", "/workspace/app");await sbx.exec("sudo enable-docker", { check: true, timeoutMs: 600_000 });await sbx.exec("docker compose up -d --build --wait --wait-timeout 300 db cache api", { ...long, check: true,});const tests = await sbx.exec("docker compose run --rm tests", { ...long, onStdout: (text) => process.stdout.write(text),});if (tests.exitCode !== 0) { const logs = await sbx.exec("docker compose logs --no-color --tail 200 api db", long); console.error(logs.stdout);}await sbx.files.download("/workspace/app/reports", "./reports");process.exitCode = tests.exitCode ?? 1;Pythonimport sysfrom withruntime import Sandboxwith Sandbox.create(disk_mib=10_240, timeout_seconds=3600) as sbx: sbx.files.upload(".", "/workspace/app") sbx.exec("sudo enable-docker", check=True, timeout_ms=600_000) sbx.exec("docker compose up -d --build --wait --wait-timeout 300 db cache api", cwd="/workspace/app", check=True, timeout_ms=1_800_000) tests = sbx.exec("docker compose run --rm tests", cwd="/workspace/app", timeout_ms=1_800_000, on_stdout=sys.stdout.write) if tests.exit_code != 0: print(sbx.exec("docker compose logs --no-color --tail 200 api db", cwd="/workspace/app").stdout, file=sys.stderr) sbx.files.download("/workspace/app/reports", "reports") sys.exit(tests.exit_code or 0)For the reports to reach the sandbox's disk, the tests service mounts the
folder, for example volumes: ["./reports:/app/reports"] in the Compose file.
Output streams while the suite runs, and a failed run brings the last 200 log
lines of the services it talked to.
The Compose flags that matter in CI
From Docker's reference for docker compose up, read 25 September 2026:
| Flag | What it does |
|---|---|
--wait |
Waits for services to be running or healthy; implies detached mode |
--wait-timeout 300 |
Gives up after that many seconds |
--build |
Builds images before starting containers |
--exit-code-from tests |
Returns that service's exit code; implies --abort-on-container-exit |
--abort-on-container-exit |
Stops every container when one stops; cannot be combined with -d |
--wait is only as good as the health checks: a service with no
healthcheck counts as ready once it is running. up --exit-code-from tests
is the one-command alternative to run --rm tests when the test service is
part of the default stack.
Shard the suite across copies of a warm stack
Building images and seeding a database is the slow part. Do it once, then fork the sandbox: each copy starts with the same files, memory and running processes, containers included, and runs a different slice of the tests.
TypeScriptimport { Sandbox } from "withruntime";await using base = await Sandbox.create({ diskMiB: 10_240, timeoutSeconds: 3600 });const app = { cwd: "/workspace/app", check: true, timeoutMs: 1_800_000 } as const;await base.files.upload("./", "/workspace/app");await base.exec("sudo enable-docker", { check: true, timeoutMs: 600_000 });await base.exec("docker compose up -d --build --wait db cache api", app);await base.exec("docker compose run --rm tests npm run seed", app);const shards = await base.fork({ count: 4 });const results = await Promise.all( shards.map((copy, i) => copy.exec(`docker compose run --rm tests npx jest --shard=${i + 1}/4`, { cwd: "/workspace/app", timeoutMs: 1_800_000, }), ),);await Promise.all(shards.map((copy) => copy.stop()));process.exitCode = results.some((r) => r.exitCode !== 0) ? 1 : 0;A fork pauses the source for about a second on a fresh sandbox, longer the more memory it holds, and each copy is billed as its own sandbox. A trial account runs eight sandboxes at once and a paid one starts at 100.
Look inside a stack from your machine
Leave the sandbox running and forward the ports Compose published, several in one command:
Terminalruntime sandbox port-forward <id> 8080 15432:5432 6379Now localhost:8080 is the API, localhost:15432 its Postgres, and
localhost:6379 its Redis, all over Runtime's authenticated API with nothing
opened to the internet (forward ports). To show
the app to someone else, share the port as a private HTTPS
preview instead.
If you step away mid-debug, runtime sandbox pause <id> keeps the containers
exactly as they are, memory included, and the next command wakes the sandbox
(pause and resume).
Sizing and limits
- Disk. Images and volumes live on the sandbox's disk. The samples ask for 10 GiB, the free trial's largest; paid sandboxes can ask for more.
- Service-to-service calls. Clients that honour
HTTP_PROXYneed the other services' names inNO_PROXY; the Docker how-to shows the two lines to add. - Outbound ports. Pulls go through
mirror.gcr.iofirst and reach the web on 443. A trial sandbox reaches ports 80 and 443 only; a paid one reaches any port, such as a staging database outside the stack. - Startup. Put Docker in a custom image with
enable-docker --no-startand every sandbox skips the install.
For agents that build and run multi-service apps, see preview agent-built apps and a coding agent sandbox.
Sources
- Docker,
docker compose upreference, https://docs.docker.com/reference/cli/docker/compose/up/, read 25 September 2026 - Launchpad, published sources for docker.io-app and docker-compose-v2 in Ubuntu 24.04, https://launchpad.net/ubuntu/noble, read 25 September 2026
Facts on this page were checked on 25 September 2026.