Skip to content

[upstream issue #512] Sandbox backends: which agent sandboxes can replace LayerFS's Docker container? Local stand-ins first #11

Open

Description

@mengmengmengqiang

[upstream issue Ephemeral-AI-Lab#512] Sandbox backends: which agent sandboxes can replace LayerFS's Docker container? Local stand-ins first

Original body (excerpt)

Status (2026-10-30)

Every environment hosted real LayerFS. Route A (no Docker at all) passed end to end in Apple Container, Microsandbox and Firecracker. The proposed backend is in draft PR Ephemeral-AI-Lab#515.

Environment FUSE + privilege split Store Real LayerFS Comments
Microsandbox pass per-VM ext4 disk; survives VM deletion route B pass; route A pass results, route A
Daytona OSS (local) pass loop ext4 inside the sandbox route B pass (arm64 runner patched locally) iteration 1, iteration 2
Apple Container pass with --cap-add SYS_ADMIN named ext4 volume, one VM per project route B pass; route A pass iteration 1, iteration 2, route A
Lima VM (EC2 stand-in) pass ext4 route B pass results
Firecracker guest (E2B/Vercel stand-in) pass second ext4 drive route A pass; route B probe only probes, route A

What holds everywhere:

  1. One VM (or one privileged sandbox) per project, not per Sandbox. VMs don't share a kernel, so the Store goes on the project VM's own ext4 disk, and its daemons run inside it, each in its own mount namespace.
  2. Commands through setpriv (uid:gid, no capabilities, no-new-privileges). Unmount is denied.
  3. User namespaces must be blocked by the backend. No platform blocks them by default. Use user.max_user_namespaces=0 in a per-project VM, or a seccomp filter in the command launcher where the kernel is shared, as on Daytona.
  4. The daemon endpoint can be reached privately on each platform: a loopback port forward, the SSH gateway, an exec stdio bridge, or vsock.

Open: hosted providers' own kernels and policies; a real backend in place of the test-only stand-in (provider adapter, persistence of backend state, seccomp and cgroups); the SDK outside the VM (the worker route).

Goal

LayerFS should be able to run on more than one Sandbox backend. Today it has one, Docker (core/crates/layerfs-sandbox/src/backend/docker/). This experiment finds out which agent-sandbox platforms could become a backend that replaces the Docker container and does every SDK operation the Docker backend does today. Start with environments that run on a developer Mac, then move to the hosted providers they stand in for.

(Revised 2026-10-30, same day: the first version asked mainly whether LayerFS's current Docker containers could run nested inside a provider. That is now a secondary route.)

Background

Today, for each Sandbox LayerFS starts one Docker container. Its daemon mounts the Workspace inside it and the agent's commands run there too. The container gives LayerFS:

  • a real Linux kernel with FUSE: the daemon opens /dev/fuse and calls mount(2) itself (core/crates/layerfs-fuse/src/session/startup.rs);
  • a privilege split: the daemon runs as root with CAP_SYS_ADMIN and mounts with allow_other, while commands run as a separate nonroot uid:gid with no capabilities, no-new-privileges, and a seccomp filter that denies user namespaces. So a command cannot unmount the Workspace or copy the mount into a namespace of its own (container.rs, topology.rs, core/docs/architecture/76-native-mount-session.md);
  • the Store on a local ext4, xfs or btrfs volume, shared by the project's daemons on one kernel. On Linux, SDK Store calls also run in the caller's own process.

Two routes per platform

  • Route A, a new backend (the main question): the platform's sandbox is the Sandbox. The daemon mounts directly in it and there is no Docker. This needs new backend code, and the platform must provide the privilege split and every operation in the contract below.
  • Route B, nested Docker (secondary): LayerFS runs unchanged and starts its usual container inside the platform's VM. No code changes, but the platform must allow Docker inside with these flags.

Desk research (2026-10-30)

Provider Finding
EC2 the only confirmed fit
E2B, Vercel Sandbox, Modal VM runtime, Daytona Linux VM likely fits: microVMs with root and documented FUSE
Fargate, Lambda, Azure Container Apps, Modal's default gVisor runtime not viable

The Mirage project (strukto-ai/mirage) needs the same --cap-add SYS_ADMIN --device /dev/fuse for container mounts.

The backend contract (what the Docker backend does at HEAD)

SDK call Backend steps
sandbox.create B1 create, B2 attach Store volume, B3 upload, B4 start, B5 startup log, B6 endpoint
workspace.mount / commit / status / unmount daemon calls over B6's TCP endpoint (no backend step)
workspace.exec B7 exec
sandbox.get_log B5 log tail
SDK restart, sandbox.reclaim B8 reopen by ID, B10 discover
sandbox.close B9 stop then delete, Store volume kept
Store calls (fs, branch, project) S1: open the Store file directly from a Linux process on the same kernel

Each platform is checked item by item:

  • B1 Create from a pinned image (Docker uses sha256: digest) or an
    equivalent pinned template, with labels; one acknowledged full unique ID; no
    adoption by name.
  • B2 Shared Store volume: one persistent local ext4/xfs/btrfs volume,
    read-write at a fixed path (/layerfs-store), attached to several sandboxes
    of one project at the same time on ONE Linux kernel (SQLite locking plus a
    Linux directory lock). Record the filesystem type and whether two sandboxes
    can share it. If each sandbox is its own VM, they cannot share a kernel:
    record that, and whether several daemons can run inside one VM instead.
  • B3 Upload the daemon executable (0755) and private config (0600) before
    start (Docker: archive into the stopped container). A file upload API, or a
    pinned image that already contains them.
  • B4 Start the daemon as root with CAP_SYS_ADMIN and /dev/fuse, an init
    that reaps orphans, and the privilege split in lfs-route-a-probe.sh.
  • B5 Startup log: read the daemon's stdout stream to see its listener
    marker; a bounded tail of its log after a failed start.
  • B6 Endpoint: the daemon's TCP port reachable from the SDK host. Docker
    publishes it on host

…(正文截断;完整内容见上游链接)

Sync note

这是只读镜像,不是上游仓库的替代。上游 issue/PR 仍是唯一真源;本镜像不复制评论、不复制代码分支。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    upstream-issueMirrored upstream issueupstream-syncMirror of Ephemeral-AI-Lab/layerfs upstream

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions