Repository navigation
add microvm-rootfs and virtio-kernel-raw packages #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
64b75c0
virtio-kernel-raw: decompress the virtio-linux kernel to a raw Image
norrietaylor d9e9f7c
minvmd-rootfs: package the minvmd guest rootfs as an ext4 image
norrietaylor 96a30e3
genericize: rename minvmd-rootfs -> microvm-rootfs, drop product refe…
norrietaylor f7025a7
virtio-kernel-raw: handle x86_64 bzImage (not just aarch64 Image.gz)
norrietaylor 7133c1e
microvm-rootfs: ship runtime closure only; harden init + prune
norrietaylor 3cd24e6
virtio-kernel-raw: add version plumbing; depend on base
norrietaylor File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| let { BuildSpec, Local, OutputData, .. } = import "minimal.ncl" in | ||
| let base = import "../base/build.ncl" in | ||
| let e2fsprogs = import "../e2fsprogs/build.ncl" in | ||
| let socat = import "../socat/build.ncl" in | ||
| { | ||
| name = "microvm-rootfs", | ||
|
|
||
| # A read-only ext4 guest rootfs for a libkrun microVM. build.sh snapshots the | ||
| # runtime userland (base + socat), drops in a small bring-up init, prunes | ||
| # build-only bulk, and packs an ext4 image to load as a virtio-blk block | ||
| # device. e2fsprogs is build-only — it provides mke2fs to pack the image — and | ||
| # its files are removed from the tree before packing, so the runtime image | ||
| # ships only the runtime closure. | ||
| runtime_deps = [ | ||
| base, | ||
| socat, | ||
| ], | ||
| build_deps = [ | ||
| { file = "build.sh" } | Local, | ||
| e2fsprogs, | ||
| ], | ||
|
|
||
| cmd = "./build.sh", | ||
|
|
||
| outputs = { | ||
| rootfs = { glob = "usr/share/microvm-rootfs/rootfs.img" } | OutputData, | ||
| }, | ||
| } | BuildSpec | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| #!/bin/bash | ||
| # Assemble a libkrun microVM guest rootfs as a read-only ext4 image. | ||
| # | ||
| # The build sandbox hardlinks this package's runtime closure (base + socat + | ||
| # their libs) and its build-only deps (e2fsprogs, for mke2fs) into the sandbox | ||
| # root at standard paths. We snapshot the userland into a staging tree, drop the | ||
| # build-only e2fsprogs files, add a small bring-up init, prune bulk, and pack an | ||
| # ext4 image with mke2fs. The image is loaded as a virtio-blk block device (e.g. | ||
| # root=/dev/vda); a block root has no overlaid init, so the kernel runs the init | ||
| # below directly. devtmpfs auto-mounts /dev, giving the init /dev/vsock. | ||
| set -euo pipefail | ||
|
|
||
| STAGE="$(pwd)/stage" | ||
| rm -rf "$STAGE" | ||
| mkdir -p "$STAGE" | ||
|
|
||
| # Snapshot the runtime userland composed into this build sandbox. | ||
| for d in usr bin sbin lib lib64 etc; do | ||
| if [ -e "/$d" ]; then | ||
| cp -a "/$d" "$STAGE/" | ||
| fi | ||
| done | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||
|
|
||
| # e2fsprogs is a build-only dependency: it provides mke2fs to pack the image | ||
| # below (invoked from the build sandbox PATH, not from $STAGE), but the guest | ||
| # never needs it at runtime. Drop its staged files so the runtime image carries | ||
| # only the runtime closure. Done before the init is created, so nothing we ship | ||
| # is at risk. The symlink guard skips a usr-merged /usr/sbin. | ||
| if [ -d "$STAGE/usr/sbin" ] && [ ! -L "$STAGE/usr/sbin" ]; then | ||
| rm -rf "$STAGE/usr/sbin" | ||
| fi | ||
| rm -f "$STAGE"/usr/bin/chattr "$STAGE"/usr/bin/lsattr "$STAGE"/usr/bin/uuidgen \ | ||
| "$STAGE"/usr/bin/compile_et "$STAGE"/usr/bin/mk_cmds | ||
| rm -f "$STAGE"/usr/lib/libext2fs*.so* "$STAGE"/usr/lib/libe2p*.so* "$STAGE"/usr/lib/libss*.so* | ||
|
|
||
| mkdir -p "$STAGE/bin" "$STAGE/sbin" "$STAGE/etc/microvm" | ||
|
|
||
| # Kernel mountpoints. devtmpfs auto-mounts on /dev at boot (CONFIG_DEVTMPFS_MOUNT) | ||
| # — without the directory it fails with "devtmpfs: error mounting -2" and the | ||
| # guest has no /dev/vsock node. /proc and /sys are conventional mountpoints. | ||
| mkdir -p "$STAGE/dev" "$STAGE/proc" "$STAGE/sys" "$STAGE/run" "$STAGE/tmp" | ||
| chmod 1777 "$STAGE/tmp" | ||
|
|
||
| # Guarantee /bin/sh for the init script's shebang. | ||
| if [ ! -e "$STAGE/bin/sh" ]; then | ||
| if [ -e "$STAGE/bin/bash" ]; then | ||
| ln -sf bash "$STAGE/bin/sh" | ||
| elif [ -e "$STAGE/usr/bin/bash" ]; then | ||
| ln -sf ../usr/bin/bash "$STAGE/bin/sh" | ||
| fi | ||
| fi | ||
|
|
||
| # Bring-up init: signal readiness by connecting out to the host (vsock CID 2) | ||
| # port 7350 and writing "READY\n", then serve an echo on vsock port 2222 for | ||
| # host<->guest connectivity checks. Retry the marker briefly in case the vsock | ||
| # device is not live the instant init starts. | ||
| cat > "$STAGE/sbin/microvm-init" <<'INIT' | ||
| #!/bin/sh | ||
| i=0 | ||
| while [ "$i" -lt 50 ]; do | ||
| printf 'READY\n' | socat -t2 - VSOCK-CONNECT:2:7350 && break | ||
| i=$((i + 1)) | ||
| sleep 0.1 | ||
| done | ||
| # Fail loudly if the READY handshake never succeeded, rather than starting the | ||
| # listener anyway and turning a boot failure into a downstream timeout. | ||
| [ "$i" -lt 50 ] || { | ||
| echo "microvm-init: failed to publish READY on vsock 7350" >&2 | ||
| exit 1 | ||
| } | ||
| exec socat VSOCK-LISTEN:2222,fork EXEC:cat | ||
| INIT | ||
| chmod +x "$STAGE/sbin/microvm-init" | ||
|
|
||
| # Machine-readable record of the bring-up contract. | ||
| cat > "$STAGE/etc/microvm/manifest" <<'MANIFEST' | ||
| # microvm guest rootfs contract | ||
| # format=ext4-block-image | ||
| # init=/sbin/microvm-init | ||
| # vsock_port_ready=7350 guest CONNECTs out (host listen=false); writes "READY\n" once | ||
| # vsock_port_echo=2222 guest LISTENs (host listen=true); echoes per connection | ||
| # net=none | ||
| MANIFEST | ||
|
|
||
| # Prune build-time-only bulk the guest never needs: headers, static libs, | ||
| # docs/man, and especially glibc's locale archive (the bulk of the closure). | ||
| # The bring-up workload is sh + socat; the C locale fallback is sufficient. | ||
| # `|| true` is scoped to `find` only — a failure in `cd` or `rm -rf` must still | ||
| # fail the build (set -euo pipefail), while `find`'s noncritical errors are ok. | ||
| ( cd "$STAGE" && \ | ||
| rm -rf usr/include usr/share/man usr/share/doc usr/share/info \ | ||
| usr/share/locale usr/share/i18n usr/lib/locale usr/lib/pkgconfig \ | ||
| usr/share/aclocal usr/share/gtk-doc usr/share/bash-completion \ | ||
| usr/share/gdb && \ | ||
| { find . \( -name '*.a' -o -name '*.la' -o -name '*.o' \) -delete 2>/dev/null || true; } ) | ||
|
|
||
| # Fail loudly (not silently with an empty output) if the image tool is absent. | ||
| command -v mke2fs >/dev/null || { | ||
| echo "ERROR: mke2fs not found on PATH ($PATH) — is e2fsprogs in build_deps?" >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| # Pack the staging tree into a raw ext4 image (mke2fs -d copies the tree). | ||
| # Size = tree + 10% + 8 MiB headroom, in 1 KiB blocks. The headroom must cover | ||
| # ext4 metadata (inode tables) that `du` does not account for, or `mke2fs -d` | ||
| # can fail to fit the tree. | ||
| OUT="$OUTPUT_DIR/usr/share/microvm-rootfs" | ||
| mkdir -p "$OUT" | ||
| KB="$(du -sk "$STAGE" | cut -f1)" | ||
| BLOCKS=$(( KB + KB / 10 + 8192 )) | ||
| # No journal (`-O ^has_journal`): the root mounts read-only, so the journal is | ||
| # pure overhead and its ~4 MiB+ reservation can overflow a tight image. | ||
| mke2fs -q -t ext4 -O ^has_journal -d "$STAGE" -b 1024 -F "$OUT/rootfs.img" "$BLOCKS" | ||
|
|
||
| # Assert the output exists so a silent mke2fs failure surfaces here rather than | ||
| # downstream as a missing materialize output. | ||
| [ -s "$OUT/rootfs.img" ] || { | ||
| echo "ERROR: mke2fs did not produce $OUT/rootfs.img" >&2 | ||
| ls -la "$OUT" >&2 || true | ||
| exit 1 | ||
| } | ||
| echo "built rootfs.img: $(wc -c < "$OUT/rootfs.img") bytes" | ||
8000
summary>
View file
Open in desktop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| let { Attrs, BuildSpec, Local, OutputData, .. } = import "minimal.ncl" in | ||
| let base = import "../base/build.ncl" in | ||
| let virtio-linux = import "../virtio-linux/build.ncl" in | ||
|
|
||
| # Tracks the virtio-linux kernel version; this package only decompresses it. | ||
| let version = "6.12.43" in | ||
| { | ||
| name = "virtio-kernel-raw", | ||
|
|
||
| # Produce a raw, directly-loadable kernel Image from the virtio-linux kernel. | ||
| # On aarch64 that is a gzip-compressed Image (Image.gz); decompress it so | ||
| # libkrun can load it via KRUN_KERNEL_FORMAT_RAW, skipping its in-VMM gzip | ||
| # decompress for a faster microVM boot. On x86_64 it is already a bzImage and | ||
| # passes through unchanged. base provides gzip + sh at build time. | ||
| build_deps = [ | ||
| { file = "build.sh" } | Local, | ||
| base, | ||
| virtio-linux, | ||
| ], | ||
|
|
||
| cmd = "./build.sh", | ||
| build_args = { | ||
| include version, | ||
| }, | ||
|
|
||
| outputs = { | ||
| image = { glob = "usr/share/virtio-linux/Image" } | OutputData, | ||
| }, | ||
|
|
||
| attrs = | ||
| { | ||
| upstream_version = version, | ||
| } | Attrs, | ||
| } | BuildSpec | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #!/bin/bash | ||
| # Produce a raw, directly-loadable kernel Image from virtio-linux. virtio-linux | ||
| # is a build_dep, so its vmlinuz output is present in the sandbox at | ||
| # /usr/share/virtio-linux/vmlinuz. On aarch64 that is a gzip-compressed Image | ||
| # (Image.gz); decompress it so libkrun can load it via KRUN_KERNEL_FORMAT_RAW | ||
| # without an in-VMM gzip step. On x86_64 it is already a bzImage (not gzip), so | ||
| # pass it through unchanged. | ||
| set -euo pipefail | ||
|
|
||
| OUT="$OUTPUT_DIR/usr/share/virtio-linux" | ||
| mkdir -p "$OUT" | ||
| if gzip -t /usr/share/virtio-linux/vmlinuz 2>/dev/null; then | ||
| gunzip -c /usr/share/virtio-linux/vmlinuz > "$OUT/Image" | ||
| else | ||
| cp /usr/share/virtio-linux/vmlinuz "$OUT/Image" | ||
| fi |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be more pure to depend on the things you need in the rootfs image as runtime_deps, as that’s kinda the vibe of runtime deps. Sounds like you probably want base, socat, core utils as runtime deps and everything else as build deps, but note in practice the union of both will show up in your rootfs.