Skip to content

runablehq/e2b-filesystem-problem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sandbox Filesystem Migration

The problem: we run work inside E2B sandboxes. When a sandbox goes bad, we need to migrate it to a fresh one — and that means moving the entire /home/user home directory (source code, node_modules, Postgres data, build artifacts) from the old sandbox into a brand-new sandbox as fast as possible.

This repo is a reproducible benchmark of that migration. It builds one realistic, "heavy" sandbox template, then implements the home-directory transfer three different ways so the approaches can be compared head-to-head. Each approach prints the byte sizes of source vs. target home directories so you can confirm the migration was complete, and solutions/utils.ts times every step.

The test fixture

A migration is only meaningful against a realistically large filesystem, so the template (template.ts) bakes one in. On top of a Node 24 image it:

  • installs a full dev toolchain (build-essential, docker.io, git, gcsfuse, zip/unzip, etc.);
  • clones the vercel/next.js repo and installs the blog-starter example's dependencies — i.e. a large, many-small-files node_modules (the classic worst case for filesystem copies);
  • on start (start.sh) launches a Postgres 16 container and seeds a big_home_data table with 100k rows, with its data dir living under /home/user/postgres-data — i.e. a few large files.

So /home/user ends up containing both pathologies at once: a deep tree of many tiny files and a handful of big ones. That's what each approach has to move.

The three approaches

All three live in solutions/ and follow the same shape: spin up a source sandbox (from the template), get its home directory out, spin up a target sandbox, get the home directory in, then measure both sides.

1. Zip — solutions/zip.ts

The straightforward path, going through the host:

  1. zip -qr /tmp/home.zip . the source home directory.
  2. Read the zip bytes down to the host via the E2B SDK (files.read).
  3. Write those bytes up into the target sandbox (files.write).
  4. Clear the target home, unzip, and chown it back to user.

Simple and dependency-free, but the whole archive round-trips through the host machine and pays compression + transfer cost on a single stream.

2. GCSFuse — solutions/gcsfuse.ts

Use a Google Cloud Storage bucket mounted into both sandboxes via gcsfuse as the transfer medium — no bytes flow through the host:

  1. Mount the bucket at /mnt/gcs-home in the source, mv the home dir into it.
  2. Mount the same bucket in a fresh target, copy the contents into /home/user, chown.

Needs GOOGLE_APPLICATION_CREDENTIALS (a service-account key) and GCS_BUCKET_NAME. Use scripts/setup-bucket.sh to provision a throwaway bucket (it applies a 1-day lifecycle delete and grants the service account roles/storage.objectUser).

3. E2B Volume — solutions/volume.ts

Use a native E2B Volume as a portable disk that detaches from one sandbox and re-attaches to another:

  1. Create a volume, mount it at /mnt/home in the source, mv the home dir onto it.
  2. Mount the same volume at /home/user in a fresh target — the data is just there, no copy step.

The least data-shuffling of the three: the home directory rides along on the volume rather than being streamed or re-copied.

Running it

Prereqs: Bun and an E2B account.

bun install

Environment (Bun auto-loads .env — no dotenv needed):

  • E2B_API_KEY — required for every approach.
  • GOOGLE_APPLICATION_CREDENTIALS — path to a service-account JSON key; gcsfuse only.
  • GCS_BUCKET_NAME — target bucket; gcsfuse only.

Build the sandbox template once (defaults to the dev env → sandbox-filesystem:dev):

bun build.ts            # or: bun build.ts --env prod

Then run any approach and read the timing logs + the final size table it prints:

bun solutions/zip.ts
bun solutions/gcsfuse.ts
bun solutions/volume.ts

For the gcsfuse approach, provision a bucket first:

# emits export lines for GCS_BUCKET_NAME etc.
PROJECT_ID=your-project SERVICE_ACCOUNT_EMAIL=sa@your-project.iam.gserviceaccount.com \
  ./scripts/setup-bucket.sh

Layout

template.ts            # E2B template: heavy Node + Next.js + Postgres fixture
build.ts               # builds the template (bun build.ts [--env dev|prod])
start.sh               # template start cmd: boots Postgres, seeds 100k rows
solutions/
  zip.ts               # approach 1 — zip through the host
  gcsfuse.ts           # approach 2 — GCS bucket via gcsfuse
  volume.ts            # approach 3 — E2B volume re-mount
  utils.ts             # log() — per-step timing wrapper
scripts/
  setup-bucket.sh      # provisions a throwaway GCS bucket for the gcsfuse run

About

e2b file system problem

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors