diff --git a/Dockerfile b/Dockerfile index fd305791..a8e2c73e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -259,6 +259,7 @@ RUN go install github.com/go-delve/delve/cmd/dlv@latest FROM "${RUST_IMAGE}" AS libkrun-build ARG LIBKRUN_VERSION=v1.17.4 +ARG KERNEL_ARCH="x86_64" RUN --mount=type=cache,sharing=locked,id=libkrun-aptlib,target=/var/lib/apt \ --mount=type=cache,sharing=locked,id=libkrun-aptcache,target=/var/cache/apt \ @@ -266,14 +267,17 @@ RUN --mount=type=cache,sharing=locked,id=libkrun-aptlib,target=/var/lib/apt \ RUN git clone --depth 1 --branch ${LIBKRUN_VERSION} https://github.com/containers/libkrun.git && \ cd libkrun && \ - make -j$(nproc) BLK=1 NET=1 + make -j$(nproc) BLK=1 NET=1 && \ + cp /libkrun/target/release/libkrun.so /libkrun/target/release/libkrun-nerdbox-${KERNEL_ARCH}.so FROM scratch AS libkrun -COPY --from=libkrun-build /libkrun/target/release/libkrun.so /libkrun.so +ARG KERNEL_ARCH="x86_64" +COPY --from=libkrun-build /libkrun/target/release/libkrun-nerdbox-${KERNEL_ARCH}.so /libkrun-nerdbox-${KERNEL_ARCH}.so FROM ${GOLANG_IMAGE} AS dev ARG CONTAINERD_VERSION=2.1.4 ARG TARGETARCH +ARG KERNEL_ARCH="x86_64" ENV PATH=/go/src/github.com/containerd/nerdbox/_output:$PATH WORKDIR /go/src/github.com/containerd/nerdbox @@ -291,7 +295,7 @@ COPY --from=docker-cli /usr/local/libexec/docker/cli-plugins/docker-buildx /usr/ COPY --from=dlv /go/bin/dlv /usr/local/bin/dlv -COPY --from=libkrun /libkrun.so /usr/local/lib64/libkrun.so +COPY --from=libkrun /libkrun-nerdbox-${KERNEL_ARCH}.so /usr/local/lib64/libkrun-nerdbox-${KERNEL_ARCH}.so ENV LIBKRUN_PATH=/go/src/github.com/containerd/nerdbox/_output VOLUME /var/lib/containerd diff --git a/internal/vm/libkrun/instance.go b/internal/vm/libkrun/instance.go index edb4edd1..9e3b65b8 100644 --- a/internal/vm/libkrun/instance.go +++ b/internal/vm/libkrun/instance.go @@ -73,39 +73,76 @@ func (*vmManager) NewInstance(ctx context.Context, state string) (vm.Instance, e p2 = []string{"/usr/local/lib", "/usr/local/lib64", "/usr/lib", "/lib"} } arch := kernelArch() - sharedNames := []string{fmt.Sprintf("libkrun-%s.so", arch), "libkrun.so"} + + // variants lists distinct library families in priority order. Each family + // represents a different patchset / ABI, so we exhaust all search paths + // for one variant before falling back to the next. Within a variant, the + // arch-tagged name is preferred over the generic name. + // + // Priority: libkrun-nerdbox (custom patches) > libkrun (stock upstream) + variants := [][]string{ + {fmt.Sprintf("libkrun-nerdbox-%s.so", arch), "libkrun-nerdbox.so"}, + {fmt.Sprintf("libkrun-%s.so", arch), "libkrun.so"}, + } switch runtime.GOOS { case "darwin": - sharedNames = []string{fmt.Sprintf("libkrun-%s.dylib", arch), "libkrun.dylib", fmt.Sprintf("libkrun-efi-%s.dylib", arch), "libkrun-efi.dylib"} + variants = [][]string{ + {fmt.Sprintf("libkrun-nerdbox-%s.dylib", arch), "libkrun-nerdbox.dylib"}, + {fmt.Sprintf("libkrun-%s.dylib", arch), "libkrun.dylib"}, + {fmt.Sprintf("libkrun-efi-%s.dylib", arch), "libkrun-efi.dylib"}, + } p2 = append(p2, "/opt/homebrew/lib") case "windows": - sharedNames = []string{"krun.dll"} + variants = [][]string{{"krun.dll"}} } - for _, dir := range append(p1, p2...) { - if dir == "" { - // Unix shell semantics: path element "" means "." - dir = "." + dirs := append(p1, p2...) + + // Search: variant → name → directory. All paths are checked for a given + // name before moving to the next name, and all names in a variant are + // exhausted before trying the next variant. + var sharedNames []string // flattened, for use in the error message + for _, variant := range variants { + sharedNames = append(sharedNames, variant...) + } + for _, variant := range variants { + if krunPath != "" { + break } - var path string - if krunPath == "" { - for _, sharedName := range sharedNames { - path = filepath.Join(dir, sharedName) + for _, name := range variant { + if krunPath != "" { + break + } + for _, dir := range dirs { + if dir == "" { + // Unix shell semantics: path element "" means "." + dir = "." + } + path := filepath.Join(dir, name) if _, err := os.Stat(path); err == nil { krunPath = path break } } } + } + + // Kernel and initrd use a single name variant each; still search all dirs. + kernelName := fmt.Sprintf("nerdbox-kernel-%s", arch) + initrdNames := []string{fmt.Sprintf("nerdbox-initrd-%s", arch), "nerdbox-initrd"} + for _, dir := range dirs { + if dir == "" { + dir = "." + } if kernelPath == "" { - path = filepath.Join(dir, fmt.Sprintf("nerdbox-kernel-%s", kernelArch())) + path := filepath.Join(dir, kernelName) if _, err := os.Stat(path); err == nil { kernelPath = path } } if initrdPath == "" { - for _, name := range []string{fmt.Sprintf("nerdbox-initrd-%s", arch), "nerdbox-initrd"} { - path = filepath.Join(dir, name) + for _, name := range initrdNames { + path := filepath.Join(dir, name) if _, err := os.Stat(path); err == nil { initrdPath = path break