mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-20 01:35:19 +03:00
Three places where build/ said something the tree does not do. - fstab mounted `/` as `rw`. A box is started with `ro` on the kernel command line and `is_read_only: true` on the root device (every config in nesbox's tree agrees: examples/vm.json, test.json, run.local.json), so the virtio-blk device rejects writes whatever fstab asks for. `rw` here only made OpenRC's `root` service attempt a remount that has to fail. The Dockerfile already depended on the truth — it pre-creates /nestri/* at build time precisely because a runtime mkdir gets EROFS — so this makes fstab agree with the comment that was already right. - build/README.md said nesbox's jail image "extracts Mesa and virglrenderer" from this base. It extracts only Mesa. virglrenderer is the host half of the native-context protocol and nesbox builds its own, patched, from nesbox/patches/; nothing in this image carries it at all. - conf.d/nestri-user-env called the zink driver-forcing block "load-bearing" directly above three exports that are commented out, here and in the profile.d copy. Whether they should come back is a separate question; a comment insisting disabled lines are load-bearing tells the next reader the opposite of what the file does. The reasoning is kept, because it is still the reason to re-enable them, along with why both copies have to move together. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
94 lines
4.8 KiB
Markdown
94 lines
4.8 KiB
Markdown
# build/ — the guest rootfs
|
|
|
|
Builds a bootable Artix/OpenRC image for the box's virtio-blk root: Mesa
|
|
(virtio-gpu native context) plus the four open guest components —
|
|
[`nescope`](../apps/nescope), [`neshub`](../apps/neshub),
|
|
[`neswire`](../apps/neswire), [`nescapture`](../apps/nescapture) — laid out
|
|
the way [borealis](https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/main/project-borealis)
|
|
lays out its `build/`: one big multi-stage `Dockerfile`, `--target` picks the
|
|
flavor, `etc/` holds the files that get overlaid onto the image verbatim.
|
|
|
|
```
|
|
build/
|
|
├── Dockerfile everything, in stages: mesa-build, nestri-build,
|
|
│ os-base, runtime, runtime_prod, runtime_debug
|
|
├── etc/ overlaid onto the image's /etc as-is
|
|
├── scripts/
|
|
│ └── mkimage.sh docker export → raw ext4, for nesbox's virtio-blk
|
|
├── Makefile
|
|
└── output/ `make image` writes here (gitignored)
|
|
```
|
|
|
|
```sh
|
|
make build # docker build --target runtime_prod → ghcr.io/nestrilabs/nestri/base:latest
|
|
make build-debug # docker build --target runtime_debug → ghcr.io/nestrilabs/nestri/base:debug
|
|
make image # + pack into output/rootfs.ext4
|
|
make image-debug # + pack into output/rootfs-debug.ext4
|
|
```
|
|
|
|
## Design notes
|
|
|
|
Three things worth knowing about how this is put together:
|
|
|
|
1. **No privileged host chroot.** A bare `chroot` into a hand-extracted
|
|
rootfs needs `/proc`, `/sys`, `/dev` bind-mounted in first — they don't
|
|
exist inside a chroot target until something puts them there. `os-base`
|
|
here is `FROM artixlinux/artixlinux:base-openrc` directly, with
|
|
`pacman -S` as plain `RUN` steps — a Docker build step already runs
|
|
inside a real container with its own `/proc`, `/sys`, `/dev`, so that
|
|
whole bind-mount mechanism has nothing to do.
|
|
|
|
2. **No host-side ownership bug to guard against.** `COPY --from=` runs as
|
|
root inside the build with no host user in the loop, so there's no
|
|
invoking-user uid getting stamped onto `/`, `/usr/bin`, or anywhere else
|
|
a build step touches — a failure mode some overlay approaches need an
|
|
explicit sanity check for doesn't exist here to check for.
|
|
|
|
3. **One `cargo build --release --workspace`, not one stage per binary.**
|
|
`nescope`, `neshub`, `neswire` and `nescapture` share one Cargo workspace
|
|
and one `Cargo.lock` — a BuildKit cache mount on `target/` gives cargo's
|
|
own incremental compiler per-crate isolation without needing a separate
|
|
Docker stage (and a separate full rebuild of `nesprotocol`) per binary.
|
|
|
|
**What is deliberately not here: Proton, and Valve's `steamclient.so`.**
|
|
`nestri/CLAUDE.md` is explicit — *"Nothing closed may enter this repo. Not
|
|
source, not a dependency, not a directory that 'looked convenient'."* Both
|
|
are closed. `runtime_prod` from this Dockerfile — tagged
|
|
`ghcr.io/nestrilabs/nestri/base:latest` — is a complete, bootable, Steam-less guest image,
|
|
and also the shared foundation other builds start from: nesbox's jail image
|
|
(see `nesbox/build/`) extracts **Mesa** from it so the guest and host sides of
|
|
the virtio-gpu native-context protocol never drift apart. Only Mesa —
|
|
`virglrenderer` is the host half of that protocol and nesbox builds its own,
|
|
patched, from `nesbox/patches/`; nothing in this image carries it.
|
|
|
|
Whatever layers Proton and the Steam client on top of it is a closed build
|
|
outside this repo, by design — not something this repo names, links to, or
|
|
depends on.
|
|
|
|
## The nesinit gap
|
|
|
|
Nothing in this image starts a payload. The old `nestri-guest-hub` did that
|
|
— per its own commit message, the open `neshub` *"loses `--proton`,
|
|
`--steamclient-so`, `--root` and the game uid/gid, and no longer ends by
|
|
handing the process to a controller... Deciding when the box is finished
|
|
belongs to `nesinit`."* `nesinit` — the guest init/session-supervisor that
|
|
would actually launch `nescope -- <payload>` and power the box down — is
|
|
referenced in commit messages and `nesbox/PROGRESS.md` but does not exist as
|
|
open code in either repo.
|
|
|
|
So `/etc/init.d/nescope` here starts nescope in **plain-compositor mode**
|
|
(no command after `--`): it comes up, provides the Wayland/X11 environment,
|
|
and waits for something to connect. That makes the image genuinely bootable
|
|
and testable — `neshub`, `neswire`, `nescope` all come up under OpenRC and
|
|
you get a real Wayland socket to point a client at — but running an actual
|
|
game is still nesinit's job, and nesinit isn't part of this build. Whoever
|
|
picks that up next should read `apps/neshub/README.md`'s "What it does not
|
|
do" section first.
|
|
|
|
## Network defaults
|
|
|
|
`/etc/init.d/guest-net` reads `nestri.ip=`/`nestri.gw=` off the kernel
|
|
command line, falling back to `172.30.0.2/24` via `172.30.0.1` if neither is
|
|
set — nesbox's own default tap addressing. Keep these in step if that
|
|
changes on the nesbox side.
|