From 710169b26635710ed6bf22e08807a0abe2a9d242 Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Thu, 11 Dec 2025 20:36:49 -0600 Subject: [PATCH 1/3] ci: add integration tests Signed-off-by: Austin Vazquez --- .github/.tool-versions | 1 + .github/actions/install-go/action.yml | 16 --------- .github/workflows/ci.yml | 48 +++++++++++++++++++++++++-- Dockerfile | 2 +- 4 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 .github/.tool-versions delete mode 100644 .github/actions/install-go/action.yml diff --git a/.github/.tool-versions b/.github/.tool-versions new file mode 100644 index 0000000..1e470a2 --- /dev/null +++ b/.github/.tool-versions @@ -0,0 +1 @@ +golang 1.25.8 \ No newline at end of file diff --git a/.github/actions/install-go/action.yml b/.github/actions/install-go/action.yml deleted file mode 100644 index 561abc4..0000000 --- a/.github/actions/install-go/action.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: "Setup Go" -description: "Reusable action to install Go, so there is one place to bump Go versions" -inputs: - go-version: - required: true - default: "stable" - description: "Go version to install" - -runs: - using: composite - steps: - - name: "Setup Go" - uses: actions/setup-go@v5 - with: - go-version: ${{ inputs.go-version }} - cache: false # see actions/setup-go#368 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cb8c88..423b070 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,9 @@ jobs: path: src/github.com/containerd/nerdbox fetch-depth: 100 - - uses: ./src/github.com/containerd/nerdbox/.github/actions/install-go + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + with: + go-version-file: 'src/github.com/containerd/nerdbox/.github/.tool-versions' - uses: containerd/project-checks@d7751f3c375b8fe4a84c02a068184ee4c1f59bc4 # v1.2.2 if: github.repository == 'containerd/nerdbox' @@ -73,7 +75,9 @@ jobs: repository: containerd/containerd path: src/github.com/containerd/containerd - - uses: ./src/github.com/containerd/nerdbox/.github/actions/install-go + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + with: + go-version-file: 'src/github.com/containerd/nerdbox/.github/.tool-versions' - name: Set env shell: bash @@ -86,3 +90,43 @@ jobs: - run: script/install-proto-tools - run: make proto-fmt - run: make check-protos check-api-descriptors + + # + # Integration tests + # + integration: + name: Integration Tests + runs-on: ${{ matrix.os }} + timeout-minutes: 20 + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + arch: x86_64 + + steps: + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + sudo usermod -aG kvm $USER + + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + with: + go-version-file: '.github/.tool-versions' + + - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + - name: Build project + run: make all + + - name: Add _output to PATH + run: echo "$(pwd)/_output" >> $GITHUB_PATH + + - name: Run integration tests + run: go test -v ./integration/... diff --git a/Dockerfile b/Dockerfile index 3aa04f8..4d51a7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ # Build the Linux kernel, initrd ,and containerd shim for running nerbox ARG XX_VERSION=1.9.0 -ARG GO_VERSION=1.25.5 +ARG GO_VERSION=1.25.8 ARG BASE_DEBIAN_DISTRO="bookworm" ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}" ARG GOLANGCI_LINT_VERSION=2.7.2 From b9169c68a96bce593e4824b81953c4c2a25b3b07 Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Fri, 12 Dec 2025 16:33:54 -0600 Subject: [PATCH 2/3] ci: add build kernel workflow Signed-off-by: Austin Vazquez --- .github/.tool-versions | 3 +- .github/actions/build-kernel/action.yml | 120 ++++++++++++++++++++++++ .github/workflows/build-kernel.yml | 40 ++++++++ .github/workflows/ci.yml | 107 ++++++++++++++++++++- 4 files changed, 265 insertions(+), 5 deletions(-) create mode 100644 .github/actions/build-kernel/action.yml create mode 100644 .github/workflows/build-kernel.yml diff --git a/.github/.tool-versions b/.github/.tool-versions index 1e470a2..fb1c9ce 100644 --- a/.github/.tool-versions +++ b/.github/.tool-versions @@ -1 +1,2 @@ -golang 1.25.8 \ No newline at end of file +golang 1.25.8 +kernel 6.12.44 diff --git a/.github/actions/build-kernel/action.yml b/.github/actions/build-kernel/action.yml new file mode 100644 index 0000000..b9e363c --- /dev/null +++ b/.github/actions/build-kernel/action.yml @@ -0,0 +1,120 @@ +name: "Build Kernel" +description: "Composite action to build Linux kernels" +inputs: + kernel_version: + description: 'Kernel version to build' + required: true + default: '6.12.44' + kernel_arch: + description: 'Kernel architecture to build' + required: true + default: 'x86_64' + kernel_nproc: + description: 'Number of parallel build processes' + required: false + # Public runners provide 4 cores; default to that to avoid overloading + # https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for-public-repositories + default: '4' + +runs: + using: composite + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + - name: Calculate kernel cache key + id: cache-key + shell: bash + run: | + # Hash the kernel config and patches to create a unique cache key + CONFIG_FILE="kernel/config-${{ inputs.kernel_version }}-${{ inputs.kernel_arch }}" + + if [ ! -f "$CONFIG_FILE" ]; then + echo "Error: Kernel config file $CONFIG_FILE not found" + exit 1 + fi + + # Calculate hash of config file and all patches + CONFIG_HASH=$(sha256sum "$CONFIG_FILE" | cut -d' ' -f1) + PATCHES_HASH=$(find kernel/patches -type f -name "*.patch" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) + + # Combine version, arch, config hash, and patches hash + CACHE_KEY="kernel-${{ inputs.kernel_version }}-${{ inputs.kernel_arch }}-${CONFIG_HASH:0:8}-${PATCHES_HASH:0:8}" + + echo "cache-key=${CACHE_KEY}" >> $GITHUB_OUTPUT + echo "config-hash=${CONFIG_HASH:0:8}" >> $GITHUB_OUTPUT + echo "patches-hash=${PATCHES_HASH:0:8}" >> $GITHUB_OUTPUT + + echo "Kernel cache key: ${CACHE_KEY}" + echo "Config hash: ${CONFIG_HASH:0:8}" + echo "Patches hash: ${PATCHES_HASH:0:8}" + + - name: Check cache for existing kernel + id: cache-kernel + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + with: + path: _output/nerdbox-kernel-${{ inputs.kernel_arch }} + key: ${{ steps.cache-key.outputs.cache-key }} + lookup-only: true + + - name: Build kernel + if: steps.cache-kernel.outputs.cache-hit != 'true' + shell: bash + run: | + docker buildx bake kernel \ + --set kernel.args.KERNEL_VERSION=${{ inputs.kernel_version }} \ + --set kernel.args.KERNEL_ARCH=${{ inputs.kernel_arch }} \ + --set kernel.args.KERNEL_NPROC=${{ inputs.kernel_nproc }} + + - name: Verify kernel artifact + if: steps.cache-kernel.outputs.cache-hit != 'true' + shell: bash + run: | + kernel_file="_output/nerdbox-kernel-${{ inputs.kernel_arch }}" + if [ ! -f "$kernel_file" ]; then + echo "Error: Kernel file $kernel_file not found after build" + exit 1 + fi + + echo "Kernel built successfully:" + ls -lh "$kernel_file" + file "$kernel_file" + + - name: Save kernel to cache + if: steps.cache-kernel.outputs.cache-hit != 'true' + uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + with: + path: _output/nerdbox-kernel-${{ inputs.kernel_arch }} + key: ${{ steps.cache-key.outputs.cache-key }} + + - name: Upload kernel artifact + if: steps.cache-kernel.outputs.cache-hit != 'true' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: nerdbox-kernel-${{ inputs.kernel_version }}-${{ inputs.kernel_arch }} + path: _output/nerdbox-kernel-${{ inputs.kernel_arch }} + retention-days: 90 + if-no-files-found: error + + - name: Cache summary + shell: bash + run: | + echo "## Kernel Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: ${{ inputs.kernel_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Architecture**: ${{ inputs.kernel_arch }}" >> $GITHUB_STEP_SUMMARY + echo "- **Cache Key**: \`${{ steps.cache-key.outputs.cache-key }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Config Hash**: ${{ steps.cache-key.outputs.config-hash }}" >> $GITHUB_STEP_SUMMARY + echo "- **Patches Hash**: ${{ steps.cache-key.outputs.patches-hash }}" >> $GITHUB_STEP_SUMMARY + echo "- **Cache Hit**: ${{ steps.cache-kernel.outputs.cache-hit == 'true' && '✅ Yes (reused existing)' || '❌ No (built from scratch)' }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f "_output/nerdbox-kernel-${{ inputs.kernel_arch }}" ]; then + echo "### Kernel Details" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + ls -lh "_output/nerdbox-kernel-${{ inputs.kernel_arch }}" >> $GITHUB_STEP_SUMMARY + file "_output/nerdbox-kernel-${{ inputs.kernel_arch }}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/build-kernel.yml b/.github/workflows/build-kernel.yml new file mode 100644 index 0000000..591fb8c --- /dev/null +++ b/.github/workflows/build-kernel.yml @@ -0,0 +1,40 @@ +name: Build Kernel + +on: + workflow_dispatch: + inputs: + kernel_version: + description: 'Kernel version to build' + required: true + default: '6.12.44' + kernel_nproc: + description: 'Number of parallel build processes' + required: false + # Public runners provide 4 cores; default to that to avoid overloading + # https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for-public-repositories + default: '4' + +permissions: + contents: read + +jobs: + build-kernel: + name: Build Kernel ${{ inputs.kernel_version }}-${{ matrix.kernel_arch }} + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + kernel_arch: x86_64 + + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - uses: ./.github/actions/build-kernel + with: + kernel_version: ${{ inputs.kernel_version }} + kernel_arch: ${{ matrix.kernel_arch }} + kernel_nproc: ${{ inputs.kernel_nproc }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 423b070..487e4e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,23 @@ permissions: # added using https://github.com/step-security/secure-workflows contents: read jobs: + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + kernel-version: ${{ steps.set-vars.outputs.kernel-version }} + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + sparse-checkout: | + .github/.tool-versions + + - name: Set variables + id: set-vars + run: | + kernel_version=$(grep -E '^kernel [0-9.]+$' .github/.tool-versions | sed -E 's/^kernel ([0-9.]+)$/\1/') + echo "kernel-version=${kernel_version}" >> $GITHUB_OUTPUT + linters: permissions: contents: read # for actions/checkout to fetch code @@ -91,11 +108,38 @@ jobs: - run: make proto-fmt - run: make check-protos check-api-descriptors + # + # Build kernels on cache miss + # + build-kernels: + name: Build Kernels (if needed) + runs-on: ${{ matrix.os }} + needs: setup + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + arch: x86_64 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: ./.github/actions/build-kernel + with: + kernel_version: ${{ needs.setup.outputs.kernel-version }} + kernel_arch: ${{ matrix.arch }} + # # Integration tests # integration: name: Integration Tests + needs: [setup, build-kernels] + # Always run after kernel builds complete (whether they were cached or not) + if: | + always() && + (needs.build-kernels.result == 'success' || needs.build-kernels.result == 'skipped') runs-on: ${{ matrix.os }} timeout-minutes: 20 @@ -116,17 +160,72 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + - name: Calculate kernel cache key + id: cache-key + run: | + # Hash the kernel config and patches to create a unique cache key + CONFIG_FILE="kernel/config-${{ needs.setup.outputs.kernel-version }}-${{ matrix.arch }}" + + if [ ! -f "$CONFIG_FILE" ]; then + echo "Error: Kernel config file $CONFIG_FILE not found" + exit 1 + fi + + # Calculate hash of config file and all patches + CONFIG_HASH=$(sha256sum "$CONFIG_FILE" | cut -d' ' -f1) + PATCHES_HASH=$(find kernel/patches -type f -name "*.patch" -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1) + + # Combine version, arch, config hash, and patches hash + CACHE_KEY="kernel-${{ needs.setup.outputs.kernel-version }}-${{ matrix.arch }}-${CONFIG_HASH:0:8}-${PATCHES_HASH:0:8}" + + echo "cache-key=${CACHE_KEY}" >> $GITHUB_OUTPUT + echo "Kernel cache key: ${CACHE_KEY}" + + - name: Restore cached kernel + id: cache-kernel + uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 with: - go-version-file: '.github/.tool-versions' + path: _output/nerdbox-kernel-${{ matrix.arch }} + key: ${{ steps.cache-key.outputs.cache-key }} + + - name: Verify kernel from cache + run: | + if [ "${{ steps.cache-kernel.outputs.cache-hit }}" = "true" ]; then + echo "✅ Kernel restored from cache" + else + echo "❌ Kernel not in cache - this should not happen after build-kernels-on-demand" + exit 1 + fi + ls -lh _output/nerdbox-kernel-${{ matrix.arch }} + file _output/nerdbox-kernel-${{ matrix.arch }} - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - - name: Build project - run: make all + - name: Build remaining artifacts (initrd and shim) + run: | + echo "Building shim, initrd and libkrun..." + docker buildx bake shim initrd libkrun + + - name: Verify all artifacts + run: | + echo "Verifying build artifacts:" + ls -lh _output/ + echo "" + echo "Kernel:" + file _output/nerdbox-kernel-${{ matrix.arch }} + echo "" + echo "Initrd:" + file _output/nerdbox-initrd + echo "" + echo "Shim:" + file _output/containerd-shim-nerdbox-v1 - name: Add _output to PATH run: echo "$(pwd)/_output" >> $GITHUB_PATH + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + with: + go-version-file: '.github/.tool-versions' + - name: Run integration tests run: go test -v ./integration/... From a4eb9d77f112a70cbc3d22316f4ba72e87d5a0f9 Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Mon, 15 Dec 2025 17:19:41 -0600 Subject: [PATCH 3/3] Build developers local platform by default Signed-off-by: Austin Vazquez --- .github/workflows/ci.yml | 4 ++-- Makefile | 10 +++++++--- docker-bake.hcl | 42 ++++++++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 487e4e4..fe71cd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -203,8 +203,8 @@ jobs: - name: Build remaining artifacts (initrd and shim) run: | - echo "Building shim, initrd and libkrun..." - docker buildx bake shim initrd libkrun + echo "Building host and guest binaries:" + docker buildx bake host-binaries guest-binaries - name: Verify all artifacts run: | diff --git a/Makefile b/Makefile index f6f287d..5fc1239 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ ONI = "👹" ARCH = $(shell uname -m) OS = $(shell uname -s) + LDFLAGS_x86_64_Linux = -lkrun LDFLAGS_aarch64_Linux = -lkrun LDFLAGS_arm64_Darwin = -L/opt/homebrew/lib -lkrun @@ -52,10 +53,13 @@ GO_STATIC_LDFLAGS := -ldflags '-extldflags "-static" $(LDFLAGS) $(EXTRA_LDFLAGS) MODULE_NAME=$(shell go list -m) API_PACKAGES=$(shell ($(GO) list ${GO_TAGS} ./... | grep /api/ )) -.PHONY: clean all validate lint generate protos check-protos check-api-descriptors proto-fmt shell +.PHONY: clean all build validate lint generate protos check-protos check-api-descriptors proto-fmt shell + +all: build -all: - $(BUILDX) bake +build: + @echo "$(WHALE) $@" + HOST_OS=$(shell uname -s | tr '[:upper:]' '[:lower:]') KERNEL_ARCH=$(ARCH) $(BUILDX) bake _output/containerd-shim-nerdbox-v1: cmd/containerd-shim-nerdbox-v1 FORCE @echo "$(WHALE) $@" diff --git a/docker-bake.hcl b/docker-bake.hcl index 382348e..4fa8bd3 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,3 +1,7 @@ +variable "HOST_OS" { + default = "linux" +} + variable "KERNEL_VERSION" { default = "6.12.44" } @@ -47,10 +51,36 @@ target "_common" { } } +target "_host_common" { + inherits = ["_common"] + args = { + TARGETOS = HOST_OS + } +} + +target "_guest_common" { + inherits = ["_common"] + args = { + TARGETOS = "linux" + } +} + variable "DESTDIR" { default = "_output" } +group "default" { + targets = ["host-binaries", "guest-binaries", "kernel"] +} + +group "host-binaries" { + targets = ["shim", "libkrun"] +} + +group "guest-binaries" { + targets = ["initrd"] +} + target "menuconfig" { inherits = ["_common"] target = "kernel-build-base" @@ -58,33 +88,29 @@ target "menuconfig" { } target "kernel" { - inherits = ["_common"] + inherits = ["_guest_common"] target = "kernel" output = ["${DESTDIR}"] } target "initrd" { - inherits = ["_common"] + inherits = ["_guest_common"] target = "initrd" output = ["${DESTDIR}"] } target "shim" { - inherits = ["_common"] + inherits = ["_host_common"] target = "shim" output = ["${DESTDIR}"] } target "libkrun" { - inherits = ["_common"] + inherits = ["_host_common"] target = "libkrun" output = ["${DESTDIR}"] } -group "default" { - targets = ["kernel", "initrd", "shim"] -} - target "dev" { inherits = ["_common"] target = "dev"