Why
smolvm create (no preset) on QEMU still hits cloud-images.ubuntu.com to download Ubuntu's official cloud qcow2 (~227 MB), even though we now build and publish our own Ubuntu 24.04 base rootfs for the layered presets (codex / claude-code / hermes / pi).
Two costs:
- External CDN dependency — adds reliability/latency surface we control nothing about. (Earlier session: a slow
cloud-images.ubuntu.com first-byte was the exact reason we built our own base in the first place.)
- Inconsistent UX —
smolvm create produces a Ubuntu cloud image with cloud-init bring-up; smolvm <preset> start produces our stripped Ubuntu base with our /init. Different OS state for the same advertised distro.
What
-
Publish base rootfs as a release asset. The CI Build Published Images workflow currently uploads base-rootfs-<arch>.ext4 only as a transient actions/upload-artifact for inter-job hand-off. Add a step that also zstd -19 compresses + uploads it to the GitHub Release at IMAGES_RELEASE_TAG as base-<arch>-rootfs.ext4.zst.
-
Bake /init into the base. Today scripts/ci/build-preset.sh installs preset-init.sh to /init after the base copy. Move that step into Dockerfile.base-rootfs (COPY preset-init.sh /init) so the base alone is bootable. Layered preset builds inherit it.
-
Wire _build_auto_config Ubuntu branch. Replace the cloud-images.ubuntu.com fetch with ensure_rootfs_only(url=<base-rootfs-asset-url>, sha256=<pinned>) from IMAGES_RELEASE_TAG. Drop the cloud-init seed ISO build (our /init reads smolvm.authorized_key_b64 directly). Drop the qcow2-resize path (ext4 resize is much simpler if we even need disk-bump for the auto-config flow).
-
Drop _QEMU_UBUNTU_AUTO_IMAGES + _UBUNTU_CURRENT_RELEASE_DATE once the new path is wired.
Wins
- No external CDN — base ships from our release page, ~150 MB compressed (vs 227 MB Ubuntu).
- No cloud-init wait at boot — our
/init does SSH bring-up synchronously (~2s vs ~10–15s).
- Single source of truth for "what is a SmolVM Ubuntu rootfs" — same bytes for
create and presets, modulo the preset's tooling layer.
- Deterministic SHA pinning on the auto-config rootfs (today the registry has zero hash check — silent CDN drift would never be detected).
Risks
- Loss of Ubuntu cloud-init's user-data customization for users who relied on it. None advertised in the SmolVM CLI, but worth checking SDK callers.
- The base rootfs is stripped (
/usr/include removed, /usr/share/doc removed, etc). Users running smolvm create for "a real Ubuntu sandbox" might miss those. Document the difference.
- New constant + SHA in
MANIFEST (or a separate BASE_ROOTFS registry next to BASE_KERNELS) — bump cadence couples to image rebuilds.
Acceptance
smolvm create (no preset) on the QEMU+Ubuntu path boots without ever resolving DNS for cloud-images.ubuntu.com. (The Firecracker+Alpine path of smolvm create doesn't hit cloud-images.ubuntu.com today; this criterion captures the actual change surface.)
- Cold-cache
time smolvm create is faster than current main (target: <15s end-to-end).
- Existing tests adapted; new test asserts the base URL is at
IMAGES_RELEASE_TAG.
Related
- SmolVM#263 — layered build infrastructure.
- SmolVM#264 — Alpine flavor (independent).
- SmolVM#282 — moved
IMAGES_RELEASE_TAG to images-v0.0.14; this issue's "publish base to <IMAGES_RELEASE_TAG>" target now points at that tag.
Why
smolvm create(no preset) on QEMU still hitscloud-images.ubuntu.comto download Ubuntu's official cloud qcow2 (~227 MB), even though we now build and publish our own Ubuntu 24.04 base rootfs for the layered presets (codex / claude-code / hermes / pi).Two costs:
cloud-images.ubuntu.comfirst-byte was the exact reason we built our own base in the first place.)smolvm createproduces a Ubuntu cloud image with cloud-init bring-up;smolvm <preset> startproduces our stripped Ubuntu base with our/init. Different OS state for the same advertised distro.What
Publish base rootfs as a release asset. The CI
Build Published Imagesworkflow currently uploadsbase-rootfs-<arch>.ext4only as a transientactions/upload-artifactfor inter-job hand-off. Add a step that alsozstd -19compresses + uploads it to the GitHub Release atIMAGES_RELEASE_TAGasbase-<arch>-rootfs.ext4.zst.Bake
/initinto the base. Todayscripts/ci/build-preset.shinstallspreset-init.shto/initafter the base copy. Move that step intoDockerfile.base-rootfs(COPY preset-init.sh /init) so the base alone is bootable. Layered preset builds inherit it.Wire
_build_auto_configUbuntu branch. Replace thecloud-images.ubuntu.comfetch withensure_rootfs_only(url=<base-rootfs-asset-url>, sha256=<pinned>)fromIMAGES_RELEASE_TAG. Drop the cloud-init seed ISO build (our/initreadssmolvm.authorized_key_b64directly). Drop the qcow2-resize path (ext4 resize is much simpler if we even need disk-bump for the auto-config flow).Drop
_QEMU_UBUNTU_AUTO_IMAGES+_UBUNTU_CURRENT_RELEASE_DATEonce the new path is wired.Wins
/initdoes SSH bring-up synchronously (~2s vs ~10–15s).createand presets, modulo the preset's tooling layer.Risks
/usr/includeremoved,/usr/share/docremoved, etc). Users runningsmolvm createfor "a real Ubuntu sandbox" might miss those. Document the difference.MANIFEST(or a separateBASE_ROOTFSregistry next toBASE_KERNELS) — bump cadence couples to image rebuilds.Acceptance
smolvm create(no preset) on the QEMU+Ubuntu path boots without ever resolving DNS forcloud-images.ubuntu.com. (The Firecracker+Alpine path ofsmolvm createdoesn't hitcloud-images.ubuntu.comtoday; this criterion captures the actual change surface.)time smolvm createis faster than current main (target: <15s end-to-end).IMAGES_RELEASE_TAG.Related
IMAGES_RELEASE_TAGtoimages-v0.0.14; this issue's "publish base to<IMAGES_RELEASE_TAG>" target now points at that tag.