diff --git a/tools/osbuilder/rootfs-builder/nvidia/nvidia_rootfs.sh b/tools/osbuilder/rootfs-builder/nvidia/nvidia_rootfs.sh index 3d1f98a025..36b4d175aa 100644 --- a/tools/osbuilder/rootfs-builder/nvidia/nvidia_rootfs.sh +++ b/tools/osbuilder/rootfs-builder/nvidia/nvidia_rootfs.sh @@ -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--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 '\'; 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 diff --git a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh index 8747ab8b79..40f5e2af18 100755 --- a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh +++ b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh @@ -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" @@ -416,7 +417,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() { @@ -1436,6 +1451,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} @@ -1650,6 +1682,8 @@ handle_build() { coco-guest-components) install_coco_guest_components ;; + nvrc) install_nvrc ;; + cloud-hypervisor) install_clh ;; firecracker) install_firecracker ;; diff --git a/tools/packaging/scripts/lib.sh b/tools/packaging/scripts/lib.sh index fa519847de..5ceefe5691 100644 --- a/tools/packaging/scripts/lib.sh +++ b/tools/packaging/scripts/lib.sh @@ -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)" +} diff --git a/tools/packaging/static-build/nvrc/Dockerfile b/tools/packaging/static-build/nvrc/Dockerfile new file mode 100644 index 0000000000..1007bd4bc6 --- /dev/null +++ b/tools/packaging/static-build/nvrc/Dockerfile @@ -0,0 +1,43 @@ +# 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 \ + libc6-dev \ + 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} diff --git a/tools/packaging/static-build/nvrc/build-static-nvrc.sh b/tools/packaging/static-build/nvrc/build-static-nvrc.sh new file mode 100755 index 0000000000..2338ca31a2 --- /dev/null +++ b/tools/packaging/static-build/nvrc/build-static-nvrc.sh @@ -0,0 +1,59 @@ +#!/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" +# shellcheck disable=SC2154 +[[ -n "${nvrc_toolchain}" ]] || die "failed to get nvrc rust toolchain" + +# The NVRC checkout lives inside the kata-containers tree, whose root carries a +# rust-toolchain.toml. rustup walks parent directories and would honour that pin +# (a different channel than the one baked into this builder image, which is the +# only toolchain with the musl target installed). Force our toolchain so the +# build is decoupled from kata's root pin and the musl std is always found. +export RUSTUP_TOOLCHAIN="${nvrc_toolchain}" + +[[ -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 "$@" diff --git a/tools/packaging/static-build/nvrc/build.sh b/tools/packaging/static-build/nvrc/build.sh new file mode 100755 index 0000000000..cc0411bfa3 --- /dev/null +++ b/tools/packaging/static-build/nvrc/build.sh @@ -0,0 +1,52 @@ +#!/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}" \ + --env nvrc_toolchain="${nvrc_toolchain}" \ + --user "$(id -u)":"$(id -g)" \ + "${container_image}" \ + bash -c "${nvrc_builder}" diff --git a/versions.yaml b/versions.yaml index 22af6490a7..939485c4b0 100644 --- a/versions.yaml +++ b/versions.yaml @@ -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: "20d38ea9c310c323718515bbaa3df9e3156f224c" + toolchain: "1.90.0" nvidia: desc: "NVIDIA compute stack"