host/build.sh produces Ubuntu-installable debs (linux-image,
linux-headers) whose release string ends in -pvm. The PVM switcher is
core-kernel code — it cannot ship as a DKMS module, so PVM hosts run this
kernel wholesale.
configs/host-base.config, a pinned linux-gcp config carrying the
distro’s GCP driver coverage (virtio, gVNIC, NVMe), so the debs work on any
GCP instance type. It is vendored rather than pulled from apt at build time:
the newest linux-gcp in the archive tracks a later release than
kernel.pin, and olddefconfig resolves that version gap silently — a
green build shipping a subtly different kernel each run. Pinning the base
makes a pinned source reproducible.configs/host-pvm.config: CONFIG_KVM=m, CONFIG_KVM_PVM=m. That is
the entire PVM delta; upstream’s host reference config shows no other
requirement (KASLR, PTI and 5-level paging all stay at distro defaults).SYSTEM_TRUSTED_KEYS, DEBUG_INFO*) — they cannot build
outside Canonical’s packaging and a PVM node does not need them.olddefconfig the build asserts the PVM, GCP-driver and
container-networking symbols survive, so a base refresh cannot silently
drop one (e.g. gVNIC) behind a green build.Refresh configs/host-base.config deliberately when bumping kernel.pin, so
GCP driver coverage keeps pace with the distro. On an up-to-date Ubuntu build
host, extract the matching linux-gcp config and re-vendor it:
pkg=$(apt-cache search --names-only '^linux-modules-[0-9].*-gcp$' \
| awk '{print $1}' | sort -V | tail -1)
apt-get download "$pkg"
dpkg-deb --fsys-tarfile "$pkg"*.deb \
| tar -xO --wildcards './boot/config-*' > configs/host-base.config
Then run host/build.sh and confirm the assertion loop passes. BASE_CONFIG
points the build at an alternate base without editing the tree.
host/install.sh is deliberately two-phase:
sudo ./install.sh . # dpkg -i + one-shot grub-reboot into -pvm
sudo reboot
uname -r && lsmod | grep kvm_pvm && ls /dev/kvm
sudo ./install.sh --commit . # make it the default only after validation
A broken kernel therefore costs one reboot, never a dead node. Secure Boot must be off (the kernel is unsigned); the script refuses to install otherwise.
scripts/gcp-host-e2e.sh runs the whole loop against a fresh GCP e2
instance: install → reboot → kvm_pvm loaded → guest smoke boot → teardown.