Skip to content

perf(computer): boot disks with their image mounted into the launcher, no copy for each launcher - #536

Merged
earakely-scale merged 3 commits into
mainfrom
edgararakelyan/disk-image-mounts
Nov 8, 2026
Merged

earakely-scale merged 3 commits into
mainfrom
edgararakelyan/disk-image-mounts

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

What this does

Part of FD-5328 (W8 part 3). When local Docker boots a computer's disk, it now mounts the disk image's disk/ folder read-only into the QEMU launcher, instead of copying the disk into an image of the launcher. This applies where Docker can mount images: Docker 28 and later, on the containerd image store. Elsewhere, the copy (machine_image) stays as the fallback.

  • machine_for(disk) returns a Machine: the image to run, plus its arguments.
    • Where Docker can mount images: the launcher itself, with --mount type=image,source=<disk>,target=/disk,image-subpath=disk.
    • Elsewhere: the machine image, as before.
  • mounts_images() reads docker info once per process: a server version of 28 or later, and the containerd snapshotter.
  • Deploys and gate 3 (LocalSandboxProvider._boot_disk) boot this way. So do Windows composes (windows_disk.compose), including the qemu-img convert against the mounted base.
  • The disk's files sit at /disk either way, so the launcher and the backing-file paths are unchanged.

Why. Every launcher change copied each disk into a new launcher image. Any agent-env upgrade that touches the launcher makes such a change. For Windows that meant copying the 11.6 GB base again for each base, and every composed disk got a machine image of its own.

Note. A mounted Windows image shows /disk/admin.key (root-only, mode 600) inside the launcher container; the copy left it out. Only the launcher and QEMU run in that container, and the key is already on this machine, inside the pulled image.

Measured

Box 1: EC2 c8i.4xlarge, Docker 29.9 with the containerd image store.

Before (copy) This PR (mount)
A launcher change (any agent-env upgrade that touches it), for each composed Windows disk 356 s to copy the disk into a new machine image no copy; the new launcher image builds in 1 s
The Windows base, for each launcher about 8 min to copy it into a machine image of its own (FD-5328) no copy
A Windows compose with a new key, plus gate 3, with the base on this machine 3 min 2 s, and 3 min 13 s in a second run
A Windows deploy 25 to 30 s 25 to 28 s
Machine images built one for each disk and launcher none

The Linux disk desktop's deploy, probe, reset and second probe took 148 s on the mount path. The first install with nothing stored, and a fresh machine pulling what it stored, are measured in a comment below.

Tested

  • Unit tests:
    • machine_for mounts or copies;
    • mounts_images across Docker versions and image stores (28 and 29 on containerd, 27, overlay2, Podman);
    • a local disk boot with the mount arguments;
    • qemu-img convert with the mount arguments.
  • E2E on box 1 (EC2 c8i.4xlarge, Docker 29.9 with the containerd image store), all on the mount path, with no machine image built:
    • a Windows compose with a new key: the base booted through the mount, the layer converted against the mounted base, then pushed;
    • Windows probe and reset;
    • the Linux disk desktop: deploy, probe, reset, probe again.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no new actionable issues were found.

Summary

Local Docker can mount disk images into the QEMU launcher instead of copying each disk into a launcher image. Unsupported hosts keep the copy path.

  • Local Docker mounts computer disks into launchers when its image store supports it.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Deploy or Windows compose] --> B[machine_for]
  B --> C{Cached Docker support answer?}
  C -->|No| D[Query Docker with 30-second timeout]
  D -->|Query fails| E[Copy disk into machine image]
  D -->|Answer received| F[Cache answer]
  C -->|Yes| G{Image mounts supported?}
  F --> G
  G -->|Yes| H[Run launcher with disk image mounted]
  G -->|No| E
Loading

Reviews (3) · Last reviewed commit: "fix(computer): ask Docker again after it..." · Reviewed by Greptile

…where Docker mounts images

Docker 28 and later, on the containerd image store, mounts the disk image's folder read-only where the launcher
finds it, so no copy of a disk, nor of a Windows disk's base, is made for each launcher. Elsewhere the machine image
copy stays. Deploys, gate 3 and Windows composes boot this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale requested a review from a team as a code owner November 8, 2026 04:06
…h take image mounts, asked with a timeout

An older client on a 28 server would refuse the option, and a Docker that doesn't answer would hold the boot; both
get the copy instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale

Copy link
Copy Markdown
Collaborator Author

First runs, measured (W8 part 4)

Box 1 (EC2 c8i.4xlarge, Docker 29.9 with the containerd image store), running agent-env run tst/integration/computer/windows --task probe from this branch.

Run Before (copy) This PR (mount)
A fresh machine on a store that holds the disk (empty state and cache, no Windows image in Docker) 252 s; compose check and gate 3 took 3 min 4 s 114 s; compose check and gate 3 took 58 s
A first install with nothing stored: ISO fetch, Windows setup, pack and push the base, compose and push the disk, gate 3 35.5 min in all; gate 3 was ready at 34 min 29 s
The deploy step in either run 25 to 30 s 25 to 27 s

The "before" row is the fresh-machine run from #531's e2e, on the same box, earlier today.

How the first install was set up:

  • A bundle's @local envs push to the local registry on :5000 whatever [stores.image] names (namespace routing), so I put an empty registry on :5000 for that run and restored the original after.
  • Most of its time is Windows setup itself (about 13 min) and the ISO fetch.

Measured against W8's done-when:

  • A fresh machine's first run is under 20 minutes: 114 s on a store that holds the disk.
  • An upgrade no longer copies the base: a launcher change copies nothing.

…nts images; keep only an answer

A daemon busy for a moment no longer leaves a long-lived process copying disks until it restarts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit d5a7cb4 into main Nov 8, 2026
34 checks passed
@earakely-scale
earakely-scale deleted the edgararakelyan/disk-image-mounts branch November 8, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant