Skip to content

Speed up guest cold boot - #3020

Merged
bchalios merged 3 commits into
mainfrom
feat/fs-only-fast-boot
Jun 17, 2026
Merged

bchalios merged 3 commits into
mainfrom
feat/fs-only-fast-boot

Conversation

@bchalios

Copy link
Copy Markdown
Contributor

What

Trims guest boot time so a filesystem-only (reboot) resume comes up fast. Applies to newly built templates only. Locally ~9.5 s → ~0.5 s on a 1-vCPU sandbox (warm cache).

  • envd.service: start envd as early as possible — DefaultDependencies=no, ordered only after systemd-journald.socket + systemd-remount-fs (was After=multi-user.target); seed the /etc/ssl/certs tmpfs from a build-time tar (one sequential read instead of ~150 scattered ones); exec envd directly instead of via bash -l -c.
  • provision.sh: mask chrony-wait (the ~8 s multi-user.target gate), systemd-binfmt (~1 s early-boot CPU + bimodal tail on 1 vCPU), and e2scrub_reap (LVM-only); pre-pack the CA certs into the tar consumed by envd.service; add makestep 1.0 3 to chrony.

Why

For fs-only snapshots, resume cold-boots a fresh VM from the rootfs, so guest boot time is the resume latency. The original boot was dominated by envd.service waiting on multi-user.target, which chrony-wait held for ~8 s on the first clock sync; systemd-binfmt and the scattered cert reads added more. Starting envd off the critical path and dropping
the boot-time clock gate removes most of it. Since chrony-wait no longer blocks boot, makestep 1.0 3 ensures the clock is still hard-corrected fast in the background (TLS validation depends on a correct clock) without jumping it backward under a running workload.

How

envd starts off multi-user.target and only orders after journald's socket + a writable rootfs (networking is configured by the kernel ip= before userspace); shutdown ordering is preserved explicitly (Conflicts/Before=shutdown.target). The cert tmpfs is seeded from /usr/local/share/e2b/ssl-certs.tar packed during provisioning, with fallbacks to copying
the cert dir and then regenerating the bundle. The masked units are inert in the sandbox. chrony still syncs in the background; makestep only steps (vs slews) when the offset exceeds 1 s, for the first 3 updates after each boot.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@cursor

cursor Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Boot ordering, TLS trust-store, and time-sync behavior change for all new templates; mitigations rely on early envd plus /init CA install and chrony makestep, with a documented gap for TLS egress before /init.

Overview
Shortens filesystem-only cold boot by starting envd much earlier and avoiding slow boot gates and scattered cert I/O on newly built templates.

envd.service no longer waits on multi-user.target; it uses DefaultDependencies=no and starts after journald’s socket and a writable rootfs. ExecStartPre bind-mounts a tmpfs at /etc/ssl/certs and seeds it from /usr/local/share/e2b/ssl-certs.tar (with copy/regenerate fallbacks) so cold boot skips update-ca-certificates. ExecStart runs /usr/bin/envd directly instead of via login shell.

provision.sh masks chrony-wait, systemd-binfmt, and e2scrub_reap, and adds makestep 1.0 3 to chrony so the clock can jump quickly after boot without blocking on first sync.

Template finalize runs a new packCertBundle guest step after configure/start/ready: regenerate the trust store and write ssl-certs.tar. Finalize layer cache hashing now includes that command (and configure script content).

envd cacerts docs clarify that tar-seeded boot does not merge persisted egress-proxy CAs; POST /init reinstalls the current proxy CA before the sandbox is routable.

Reviewed by Cursor Bugbot for commit e5d0901. Bugbot is set up for automated code reviews on this repo. Configure here.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

In packages/orchestrator/pkg/template/build/phases/base/provision.sh, packing /etc/ssl/certs with tar without the -h flag preserves symlinks pointing to /usr/share/ca-certificates/. When extracted into the tmpfs, these symlinks will still point back to the lazily-fetched rootfs, triggering scattered reads and defeating the purpose of the tmpfs optimization. Using the -h flag ensures the actual certificate contents are packed, keeping all certificate reads entirely within the tmpfs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/orchestrator/pkg/template/build/phases/base/provision.sh Outdated
@codecov

codecov Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 29 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...or/pkg/template/build/phases/finalize/configure.go 0.00% 20 Missing ⚠️
...ator/pkg/template/build/phases/finalize/builder.go 0.00% 9 Missing ⚠️

📢 Thoughts on this report? Let us know!

@bchalios
bchalios force-pushed the feat/fs-only-fast-boot branch from 4881d1c to e7072e8 Compare June 16, 2026 15:05
@bchalios
bchalios force-pushed the feat/fs-only-fast-boot branch from e7072e8 to 67e59d3 Compare June 16, 2026 15:40
# cert contents are packed: /etc/ssl/certs is mostly hash-named symlinks into
# /usr/share/ca-certificates, which would otherwise still fault the rootfs.
mkdir -p /usr/local/share/e2b
tar -C /etc/ssl/certs -chf /usr/local/share/e2b/ssl-certs.tar .

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude is telling me that we generate the bundle too early (in base phase). If a user adds some certificates in later stages, they aren't going to be included as update-ca-certificates is skipped then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I've moved this to the finalize step, so that the tar includes all the certs from base and user installed)

@djeebus djeebus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, nice finds!

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c0aa844. Configure here.

Comment thread packages/orchestrator/pkg/template/build/phases/finalize/configure.sh Outdated
Comment thread packages/orchestrator/pkg/template/build/phases/finalize/builder.go Outdated
bchalios and others added 3 commits June 17, 2026 12:21
Speeds up the guest cold boot, which is the resume latency for filesystem-only
(reboot) snapshots. Locally ~9.5s -> ~0.5s avg on a 1-vCPU sandbox (warm cache).

envd.service:
- Start envd early instead of After=multi-user.target: DefaultDependencies=no,
  ordered only after journald's socket and systemd-remount-fs. The old ordering
  transitively waited on chrony-wait (~8s).
- Seed the /etc/ssl/certs tmpfs from a build-time tar (one sequential rootfs
  read instead of ~150 scattered ones), with cp/update-ca-certificates fallbacks.
- Exec envd directly instead of via `bash -l -c`.

provision.sh:
- Mask chrony-wait (the ~8s multi-user.target gate; chrony still syncs in the
  background), systemd-binfmt (~1s early-boot CPU, bimodal tail on 1 vCPU), and
  e2scrub_reap (LVM-only).
- Pre-pack /etc/ssl/certs into the tar consumed by envd.service.

Applies to newly built templates only. In dev the base-layer cache keys on the
provision.sh content, so new builds pick it up automatically; in prod the
BuildProvisionVersion LaunchDarkly flag must be bumped to force a base-layer
rebuild. Existing templates are not retroactively rebuilt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Add `makestep 1.0 3` to the guest chrony.conf. With chrony-wait masked, boot
no longer blocks on the first clock sync, so the clock must be corrected fast
in the background — TLS validation depends on a correct CLOCK_REALTIME. Without
makestep, chrony only slews, which corrects a large offset very slowly.

makestep steps (jumps) the clock when the offset exceeds 1s, but only for the
first 3 updates after chronyd starts. chronyd restarts on every cold boot, so
this hard-corrects a large boot-time offset while never jumping the clock
backward under a running workload (which would break timers/monotonic
assumptions). Matches the chrony default the minimal conf had dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
The cold-boot fast path bind-mounts a tmpfs over /etc/ssl/certs seeded
from ssl-certs.tar and skips update-ca-certificates. Before this PR the
boot bind-mounted an *empty* dir and ran update-ca-certificates on every
boot, so the trust store was always regenerated from the rootfs source
dirs. Pre-baking the tar trades that regen for speed, so correctness now
depends on the tar matching what the boot-time regen would have produced.

Packing it in the base phase (original) or even in configure.sh froze
the cert set too early:
- certs a user dropped under /usr/local/share/ca-certificates without
  running update-ca-certificates were never merged (boot used to do it);
- configure.sh runs before start_cmd/ready_cmd, so trust-store changes
  there were missed.

Pack the tar as the build's last guest step instead: run
update-ca-certificates first, then tar, in the finalize post-processing
defer — after the configuration script, start_cmd, and ready_cmd, right
before the disk sync. The tar now equals the trust store the guest would
regenerate at boot, including user-layer and start/ready certs whether or
not they were registered. The regen's scattered reads move to build time;
the one-sequential-read boot win is unchanged.

Also hash the configure script and the cert command into the finalize
layer key so changes to either bust the cache (mirroring base/provision.sh).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
@bchalios
bchalios force-pushed the feat/fs-only-fast-boot branch from c0aa844 to e5d0901 Compare June 17, 2026 10:22
@bchalios
bchalios enabled auto-merge (squash) June 17, 2026 10:34
@bchalios
bchalios merged commit f05ccea into main Jun 17, 2026
53 checks passed
@bchalios
bchalios deleted the feat/fs-only-fast-boot branch June 17, 2026 10:45
bchalios added a commit that referenced this pull request Jun 17, 2026
## What

Adds TestCACertFromBuildSurvivesInBakedBundle — an integration test that
builds a template injecting a self-signed CA two ways and asserts the
build-time cert tar (/usr/local/share/e2b/ssl-certs.tar) contains it:

1. RUN step, without running update-ca-certificates (the common case —
dropping a cert under /usr/local/share/ca-certificates and expecting it
picked up later).
2. start command, which runs after configure.sh.

## Why

The cold-boot fast path (#3020) seeds /etc/ssl/certs from that tar and
skips update-ca-certificates, so the tar must already contain every CA
the template produced. The fix in #3020 packs the tar — after running
update-ca-certificates — as the build's last guest step, so both cases
above are captured. This test locks that in: packing the tar earlier (in
base,
or before start/ready) would drop these certs and silently break TLS,
and this guard catches that regression.

## Scope

Validates the tar artifact only. The boot-time seeding that consumes it
runs solely on a cold boot, which no runtime path triggers today (every
resume is a memory resume that skips ExecStartPre). That seeding becomes
live with filesystem-only reboot resume and will get its own end-to-end
test then.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

3 participants