build: build NVRC from a pinned git ref

Add a Kata static-build component for NVRC (tools/packaging/static-build/nvrc)
that clones the NVRC repository at a pinned git reference and builds a static
musl binary, mirroring the coco-guest-components build. This lets the
composable-image work track NVRC changes from source instead of depending on a
signed upstream release.

  - versions.yaml: add repo/ref/toolchain to externals.nvrc (and bump the
    version); the existing url is kept for the signed-release path.
  - lib.sh: add get_nvrc_image_name for the builder image.
  - kata-deploy-binaries.sh: add the nvrc build target, install_nvrc and its
    tarball path; get_latest_nvidia_nvrc_version now tracks ref+toolchain so
    the dependent NVIDIA images rebuild when the ref changes.
  - nvidia_rootfs.sh: consume kata-static-nvrc.tar.zst instead of downloading
    and cosign-verifying the release; the Sigstore .cert/.sig are now copied
    only when present (i.e. the signed-release path), since a source build
    emits just the binary.

Signed-off-by: Fabiano Fidêncio <fidencio@nvidia.com>
Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com>
This commit is contained in:
Fabiano Fidêncio
2026-06-10 23:52:27 +02:00
parent cada9c18d4
commit b1b8ce0cd3
7 changed files with 206 additions and 31 deletions

View File

@@ -40,27 +40,14 @@ fi
readonly stage_one="${BUILD_DIR:?}/rootfs-${BUILD_VARIANT:?}-stage-one"
setup_nvidia-nvrc() {
local url ver
local nvrc=NVRC-${machine_arch}-unknown-linux-musl
url=$(get_package_version_from_kata_yaml "externals.nvrc.url")
ver=$(get_package_version_from_kata_yaml "externals.nvrc.version")
local dl="${url}/${ver}"
curl -fsSL -o "${BUILD_DIR}/${nvrc}.tar.xz" "${dl}/${nvrc}.tar.xz"
curl -fsSL -o "${BUILD_DIR}/${nvrc}.tar.xz.sig" "${dl}/${nvrc}.tar.xz.sig"
curl -fsSL -o "${BUILD_DIR}/${nvrc}.tar.xz.cert" "${dl}/${nvrc}.tar.xz.cert"
local id="^https://github.com/NVIDIA/nvrc/.github/workflows/.+@refs/heads/main$"
local oidc="https://token.actions.githubusercontent.com"
# Only allow releases from the NVIDIA/nvrc main branch and build by github actions
cosign verify-blob \
--rekor-url https://rekor.sigstore.dev \
--certificate "${BUILD_DIR}/${nvrc}.tar.xz.cert" \
--signature "${BUILD_DIR}/${nvrc}.tar.xz.sig" \
--certificate-identity-regexp "${id}" \
--certificate-oidc-issuer "${oidc}" \
"${BUILD_DIR}/${nvrc}.tar.xz"
# NVRC is built from a pinned git ref by the Kata "nvrc" static-build
# target (tools/packaging/static-build/nvrc), which produces
# kata-static-nvrc.tar.zst with the init binary under bin/. Unpack it
# verbatim into the rootfs (./bin/NVRC-<arch>-unknown-linux-musl).
local nvrc_tarball="${BUILD_DIR}/kata-static-nvrc.tar.zst"
[[ -e "${nvrc_tarball}" ]] || \
die "NVRC tarball not found: ${nvrc_tarball} (build the 'nvrc' target first)"
tar --zstd -xvf "${nvrc_tarball}" -C .
}
setup_nvidia_gpu_rootfs_stage_one() {
@@ -78,11 +65,7 @@ setup_nvidia_gpu_rootfs_stage_one() {
chmod +x ./nvidia_chroot.sh
local nvrc=NVRC-${machine_arch}-unknown-linux-musl
if [[ ! -e "${BUILD_DIR}/${nvrc}.tar.xz" ]]; then
setup_nvidia-nvrc
fi
tar -xvf "${BUILD_DIR}/${nvrc}.tar.xz" -C ./bin/
setup_nvidia-nvrc
local appendix=""
if echo "${NVIDIA_GPU_STACK}" | grep -q '\<dragonball\>'; then
@@ -269,9 +252,12 @@ chisseled_init() {
local nvrc="NVRC-${machine_arch}-unknown-linux-musl"
cp -a "${stage_one}/bin/${nvrc}" bin/.
cp -a "${stage_one}/bin/${nvrc}".cert bin/.
cp -a "${stage_one}/bin/${nvrc}".sig bin/.
cp -a "${stage_one}/bin/${nvrc}" bin/.
# Sigstore signature/certificate only exist when NVRC is pulled from the
# official signed release; a source build (the composable-image path)
# produces just the binary.
[[ -e "${stage_one}/bin/${nvrc}.cert" ]] && cp -a "${stage_one}/bin/${nvrc}".cert bin/.
[[ -e "${stage_one}/bin/${nvrc}.sig" ]] && cp -a "${stage_one}/bin/${nvrc}".sig bin/.
setup_nvrc_init_symlinks

View File

@@ -30,6 +30,7 @@ readonly versions_yaml="${repo_root_dir}/versions.yaml"
readonly busybox_builder="${static_build_dir}/busybox/build.sh"
readonly agent_builder="${static_build_dir}/agent/build.sh"
readonly coco_guest_components_builder="${static_build_dir}/coco-guest-components/build.sh"
readonly nvrc_builder="${static_build_dir}/nvrc/build.sh"
readonly clh_builder="${static_build_dir}/cloud-hypervisor/build-static-clh.sh"
readonly firecracker_builder="${static_build_dir}/firecracker/build-static-firecracker.sh"
readonly kernel_builder="${static_build_dir}/kernel/build.sh"
@@ -411,7 +412,21 @@ get_latest_nvidia_ctk_version() {
}
get_latest_nvidia_nvrc_version() {
get_from_kata_deps ".externals.nvrc.version"
# NVRC is built from source at a pinned git ref, so the cache key tracks
# the ref and toolchain (not just the release version) to invalidate the
# dependent images whenever any of them change.
local version ref toolchain
version="$(get_from_kata_deps ".externals.nvrc.version")"
ref="$(get_from_kata_deps ".externals.nvrc.ref")"
toolchain="$(get_from_kata_deps ".externals.nvrc.toolchain")"
echo "${version}-${ref}-${toolchain}"
}
get_nvrc_tarball_path() {
nvrc_local_build_dir="${repo_root_dir}/tools/packaging/kata-deploy/local-build/build"
nvrc_tarball_name="kata-static-nvrc.tar.zst"
echo "${nvrc_local_build_dir}/${nvrc_tarball_name}"
}
get_latest_nvidia_nvat_version() {
@@ -1400,6 +1415,23 @@ install_coco_guest_components() {
DESTDIR="${destdir}" "${coco_guest_components_builder}"
}
install_nvrc() {
latest_artefact="$(get_latest_nvidia_nvrc_version)"
artefact_tag="$(get_from_kata_deps ".externals.nvrc.version")"
latest_builder_image="$(get_nvrc_image_name)"
install_cached_tarball_component \
"${build_target}" \
"${latest_artefact}" \
"${latest_builder_image}" \
"${final_tarball_name}" \
"${final_tarball_path}" \
&& return 0
info "build static nvrc"
DESTDIR="${destdir}" "${nvrc_builder}"
}
install_pause_image() {
latest_artefact="$(get_from_kata_deps ".externals.pause.repo")-$(get_from_kata_deps ".externals.pause.version")"
artefact_tag=${latest_artefact}
@@ -1614,6 +1646,8 @@ handle_build() {
coco-guest-components) install_coco_guest_components ;;
nvrc) install_nvrc ;;
cloud-hypervisor) install_clh ;;
firecracker) install_firecracker ;;

View File

@@ -257,3 +257,8 @@ get_pause_image_name() {
pause_image_script_dir="${repo_root_dir}/tools/packaging/static-build/pause-image"
echo "${BUILDER_REGISTRY}:pause-image-$(get_last_modification "${pause_image_script_dir}")-$(uname -m)"
}
get_nvrc_image_name() {
nvrc_script_dir="${repo_root_dir}/tools/packaging/static-build/nvrc"
echo "${BUILDER_REGISTRY}:nvrc-$(get_from_kata_deps ".externals.nvrc.toolchain")-$(get_last_modification "${nvrc_script_dir}")-$(uname -m)"
}

View File

@@ -0,0 +1,42 @@
# Copyright (c) 2024 NVIDIA Corporation
#
# SPDX-License-Identifier: Apache-2.0
FROM ubuntu:24.04
ARG RUST_TOOLCHAIN
ENV DEBIAN_FRONTEND=noninteractive
ENV RUSTUP_HOME="/opt/rustup"
ENV CARGO_HOME="/opt/cargo"
ENV PATH="/opt/cargo/bin/:${PATH}"
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN mkdir ${RUSTUP_HOME} ${CARGO_HOME}
RUN apt-get update && \
apt-get --no-install-recommends install -y \
ca-certificates \
curl \
binutils \
gcc \
git \
make \
musl-tools && \
apt-get clean && rm -rf /var/lib/apt/lists/ && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_TOOLCHAIN}
# NVRC is shipped as a fully static musl binary so it can serve as init in the
# minimal GPU guest regardless of the rootfs libc.
RUN ARCH=$(uname -m); \
rust_arch=""; \
case "${ARCH}" in \
"aarch64") rust_arch="${ARCH}" ;; \
"x86_64") rust_arch="${ARCH}" ;; \
*) echo "Unsupported architecture: ${ARCH}" && exit 1 ;; \
esac; \
echo "RUST_ARCH=${rust_arch}" > /etc/profile.d/rust.sh; \
rustup target add "${rust_arch}-unknown-linux-musl"
RUN chmod -R a+rwX ${RUSTUP_HOME} ${CARGO_HOME}

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
#
# Copyright (c) 2024 NVIDIA Corporation
#
# SPDX-License-Identifier: Apache-2.0
set -o errexit
set -o nounset
set -o pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "${script_dir}/../../scripts/lib.sh"
# shellcheck disable=SC2154
[[ -n "${nvrc_repo}" ]] || die "failed to get nvrc repo"
# shellcheck disable=SC2154
[[ -n "${nvrc_ref}" ]] || die "failed to get nvrc git ref"
[[ -d "nvrc" ]] && rm -rf nvrc
build_nvrc_from_source() {
echo "build nvrc from source"
# shellcheck source=/dev/null
. /etc/profile.d/rust.sh
# `ref` may be a branch, tag or commit, so clone then fetch the exact ref.
git clone "${nvrc_repo}" nvrc
pushd nvrc
git fetch origin "${nvrc_ref}"
git checkout FETCH_HEAD
# shellcheck disable=SC2154
local target="${RUST_ARCH}-unknown-linux-musl"
cargo build --release --target "${target}"
strip "target/${target}/release/NVRC"
# Mirror the NVRC release tarball layout: the init binary lands in /bin
# named for its target triple. nvidia_rootfs.sh extracts this tarball
# verbatim into the guest rootfs.
local nvrc_name="NVRC-${target}"
install -D -m0755 "target/${target}/release/NVRC" "${DESTDIR}/bin/${nvrc_name}"
popd
}
build_nvrc_from_source "$@"

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
#
# Copyright (c) 2024 NVIDIA Corporation
#
# SPDX-License-Identifier: Apache-2.0
set -o errexit
set -o nounset
set -o pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly nvrc_builder="${script_dir}/build-static-nvrc.sh"
# shellcheck source=/dev/null
source "${script_dir}/../../scripts/lib.sh"
DESTDIR=${DESTDIR:-${PWD}}
nvrc_repo="${nvrc_repo:-}"
nvrc_ref="${nvrc_ref:-}"
nvrc_toolchain="${nvrc_toolchain:-}"
[[ -n "${nvrc_repo}" ]] || nvrc_repo=$(get_from_kata_deps ".externals.nvrc.repo")
[[ -n "${nvrc_ref}" ]] || nvrc_ref=$(get_from_kata_deps ".externals.nvrc.ref")
[[ -n "${nvrc_toolchain}" ]] || nvrc_toolchain=$(get_from_kata_deps ".externals.nvrc.toolchain")
[[ -n "${nvrc_repo}" ]] || die "Failed to get nvrc repo"
[[ -n "${nvrc_ref}" ]] || die "Failed to get nvrc git ref"
[[ -n "${nvrc_toolchain}" ]] || die "Failed to get the rust toolchain to build nvrc"
container_image="${NVRC_CONTAINER_BUILDER:-$(get_nvrc_image_name)}"
# shellcheck disable=SC2154
[[ "${CROSS_BUILD}" == "true" ]] && container_image="${container_image}-cross-build"
# shellcheck disable=SC2154,SC2086
docker pull "${container_image}" || \
(docker ${BUILDX} build ${PLATFORM} \
--build-arg RUST_TOOLCHAIN="${nvrc_toolchain}" \
-t "${container_image}" "${script_dir}" && \
# No-op unless PUSH_TO_REGISTRY is exported as "yes"
push_to_registry "${container_image}")
# shellcheck disable=SC2154
docker run --rm -i -v "${repo_root_dir}:${repo_root_dir}" \
-w "${PWD}" \
--env DESTDIR="${DESTDIR}" \
--env nvrc_repo="${nvrc_repo}" \
--env nvrc_ref="${nvrc_ref}" \
--user "$(id -u)":"$(id -g)" \
"${container_image}" \
bash -c "${nvrc_builder}"

View File

@@ -234,8 +234,15 @@ externals:
nvrc:
# yamllint disable-line rule:line-length
desc: "The NVRC project provides a Rust binary that implements a simple init system for microVMs"
version: "v0.1.4"
version: "v0.1.5"
url: "https://github.com/NVIDIA/nvrc/releases/download/"
# While the composable-image work is in flight NVRC is built from source at
# a pinned git reference (tools/packaging/static-build/nvrc) instead of
# downloading the signed release from `url` above. `ref` may be a commit,
# tag or branch; pin to a commit for reproducible builds.
repo: "https://github.com/fidencio/nvrc.git"
ref: "db3fd70ca9fe791c8e722990f8c8ff69ca3d0454"
toolchain: "1.90.0"
nvidia:
desc: "NVIDIA compute stack"