From 4e4dd8896ff017a81d352c844559d13d4ae94d61 Mon Sep 17 00:00:00 2001 From: Wanjohi Date: Wed, 7 Oct 2026 15:43:31 +0000 Subject: [PATCH] build: ship the guest kernel inside the image, publish from the build box (#361) A `kernel-build` stage runs `kernel-build.sh` and puts the result at `/boot/vmlinux`; host onboarding takes it out beside the root image, so kernel and image (and their shared NVGPU_REF) always ship as one pair. `make push` publishes `:latest` and a commit tag from the build box. Built on the build box: `/boot/vmlinux` is 24 MB, and `vmlinux.nvgpu-rev` is beside it. --- build/Containerfile | 33 +++++++++++++++++++++++++++++++++ build/Makefile | 14 +++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/build/Containerfile b/build/Containerfile index 8031fd3a..b2958de0 100644 --- a/build/Containerfile +++ b/build/Containerfile @@ -202,6 +202,36 @@ RUN --mount=type=cache,target=/root/.cargo/registry \ find /artifacts/nvgpu -type f -printf '/%P\n' > /artifacts/nvgpu/.manifest +# ─────────────────────────────────────────────────────────── +# The guest kernel — shipped inside the image it boots +# +# A host takes it back out as a file beside the root image when it unpacks +# this one (the host agent's onboarding), because the VMM loads a kernel from the host +# and never from the guest's disk. Shipping the two as one image is what +# keeps them a pair: the driver built into this kernel and the Vulkan layer +# above come from the same NVGPU_REF, and a host can only ever have the +# kernel that matches its root. +# +# The same script `make kernel` runs, on a fresh clone every time: an image +# build has no warm tree to reuse, and the layer cache already skips this +# stage while its pins and its inputs are unchanged. +# ─────────────────────────────────────────────────────────── +FROM builder AS kernel-build +ARG KERNEL_GIT=https://github.com/CachyOS/linux.git +ARG KERNEL_REF=cachyos-7.2.6-1 +ARG KERNEL_MARCH=x86-64-v3 +ARG NVGPU_GIT=https://github.com/nestrilabs/virtio-nvgpu.git +ARG NVGPU_REF=dev +RUN pacman -S --noconfirm --needed lld bc cpio perl && pacman -Scc --noconfirm +COPY build/kernel /kernel-build/kernel +COPY build/scripts/kernel-build.sh /kernel-build/scripts/kernel-build.sh +RUN KERNEL_GIT="${KERNEL_GIT}" KERNEL_REF="${KERNEL_REF}" KERNEL_MARCH="${KERNEL_MARCH}" \ + KERNEL_SRC=/build/kernel KERNEL_OUTPUT=/artifacts/kernel/boot/vmlinux \ + NVGPU_GIT="${NVGPU_GIT}" NVGPU_REF="${NVGPU_REF}" NVGPU_WORK=/build/nvgpu \ + bash /kernel-build/scripts/kernel-build.sh && \ + rm -rf /build/kernel /build/nvgpu + + # ─────────────────────────────────────────────────────────── # umu-launcher — built here, not installed from the distribution # @@ -443,6 +473,9 @@ COPY --from=mesa-build /artifacts/mesa / COPY --from=nestri-build /artifacts/nestri / COPY --from=nvgpu-layer-build /artifacts/nvgpu / COPY --from=umu-build /artifacts/umu / +# The kernel this image is booted with, for the host to take out. See the +# kernel-build stage. +COPY --from=kernel-build /artifacts/kernel / # **No Proton here.** It is attached to a box at run time, mounted at # /nestri/compat, so this image has no Proton path for a launch to fall back to diff --git a/build/Makefile b/build/Makefile index e17b777c..d167742b 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,5 +1,5 @@ SHELL := /bin/bash -.PHONY: build build-debug image image-debug kernel kernel-clean kernel-objclean proton-image proton-push clean help +.PHONY: build push build-debug image image-debug kernel kernel-clean kernel-objclean proton-image proton-push clean help CONTAINER_RT := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null) ifeq ($(CONTAINER_RT),) @@ -103,11 +103,23 @@ endif build: DOCKER_BUILDKIT=1 $(CONTAINER_RT) build $(if $(FORCE_REBUILD),--no-cache,) \ --build-arg NVGPU_GIT=$(NVGPU_GIT) --build-arg NVGPU_REF=$(NVGPU_REF) \ + --build-arg KERNEL_GIT=$(KERNEL_GIT) --build-arg KERNEL_REF=$(KERNEL_REF) \ + --build-arg KERNEL_MARCH=$(KERNEL_MARCH) \ -f Containerfile -t $(IMAGE_NAME):latest --target runtime_prod $(CONTEXT) +# Publishing the image hosts onboard from. Run on the build box, not in CI: a +# full build there takes hours. Pushes the moving tag and one named for the +# commit, so a host can be pinned to exactly what it was tested on. +push: build + $(CONTAINER_RT) tag $(IMAGE_NAME):latest $(IMAGE_NAME):$(shell git rev-parse --short=12 HEAD) + $(CONTAINER_RT) push $(IMAGE_NAME):$(shell git rev-parse --short=12 HEAD) + $(CONTAINER_RT) push $(IMAGE_NAME):latest + build-debug: DOCKER_BUILDKIT=1 $(CONTAINER_RT) build $(if $(FORCE_REBUILD),--no-cache,) \ --build-arg NVGPU_GIT=$(NVGPU_GIT) --build-arg NVGPU_REF=$(NVGPU_REF) \ + --build-arg KERNEL_GIT=$(KERNEL_GIT) --build-arg KERNEL_REF=$(KERNEL_REF) \ + --build-arg KERNEL_MARCH=$(KERNEL_MARCH) \ -f Containerfile -t $(IMAGE_NAME):debug --target runtime_debug $(CONTEXT) # Hours, and only when PROTON_TAG moves. Its context is this directory rather