|
| 1 | +# BUILDER_IMAGE MUST be Debian-family (xx-apt-get requires apt-get). |
| 2 | +# Project's Makefile pins it to golang:1.26-trixie (matches go.mod |
| 3 | +# minimum Go version) which satisfies this. Override with a non-Debian |
| 4 | +# image only if you also swap xx-apt-get for the matching package manager. |
| 5 | +# |
| 6 | +# tonistiigi/xx is pinned by sha256 digest below. Minimum acceptable |
| 7 | +# version is 1.5.0 (arm/v7 + $TARGETVARIANT handling). To update: |
| 8 | +# docker pull tonistiigi/xx:1.x.y |
| 9 | +# docker inspect --format='{{index .RepoDigests 0}}' tonistiigi/xx:1.x.y |
| 10 | +# Track in Renovate / Dependabot alongside the runtime base-image pins. |
1 | 11 | ARG BUILDER_IMAGE |
2 | 12 | ARG BASE_IMAGE_FULL |
3 | 13 | ARG BASE_IMAGE_MINIMAL |
| 14 | +ARG XX_IMAGE=tonistiigi/xx@sha256:010d4b66aed389848b0694f91c7aaee9df59a6f20be7f5d12e53663a37bd14e2 |
4 | 15 |
|
5 | | -# Build node feature discovery |
6 | | -FROM ${BUILDER_IMAGE:-golang} AS builder |
| 16 | +# Cross-build helper (host arch; never shipped) |
| 17 | +FROM --platform=$BUILDPLATFORM ${XX_IMAGE} AS xx |
7 | 18 |
|
8 | | -# Get (cache) deps in a separate layer |
| 19 | +# Build node-feature-discovery on the build host, cross-compile to TARGET. |
| 20 | +# Running here on $BUILDPLATFORM avoids the QEMU translation-cache instability |
| 21 | +# that crashed go mod download under emulation (see PR commit body for the |
| 22 | +# crash signatures). |
| 23 | +FROM --platform=$BUILDPLATFORM ${BUILDER_IMAGE:-golang} AS builder |
| 24 | +COPY --from=xx / / |
| 25 | + |
| 26 | +ARG TARGETPLATFORM |
| 27 | +ARG TARGETARCH |
| 28 | +# Cross-toolchain packages (gcc, libc6-dev) are intentionally unpinned — |
| 29 | +# Debian point releases shift these frequently and the build-stage is |
| 30 | +# discarded; pinning would create frequent CI churn for no security gain. |
| 31 | +# hadolint ignore=DL3008 |
| 32 | +RUN xx-apt-get update && \ |
| 33 | + xx-apt-get install -y --no-install-recommends gcc libc6-dev && \ |
| 34 | + rm -rf /var/lib/apt/lists/* |
| 35 | + |
| 36 | +# Module cache fetched on $BUILDPLATFORM. Modules are arch-independent; |
| 37 | +# no QEMU involvement here. |
9 | 38 | COPY go.mod go.sum /go/node-feature-discovery/ |
10 | 39 | COPY api/nfd/go.mod api/nfd/go.sum /go/node-feature-discovery/api/nfd/ |
11 | | - |
12 | 40 | WORKDIR /go/node-feature-discovery |
13 | 41 |
|
14 | 42 | RUN --mount=type=cache,target=/go/pkg/mod/ \ |
15 | 43 | go mod download |
16 | 44 |
|
17 | | -# Do actual build |
| 45 | +# Force CGO on. xx-go --wrap defaults CGO_ENABLED=0 for cross-compile |
| 46 | +# targets, which would build-tag-filter out source/cpu/cpuid_linux_*.go |
| 47 | +# (which use #include <sys/auxv.h>) and silently fall back to the |
| 48 | +# cpuid_stub.go no-op variant. |
| 49 | +ENV CGO_ENABLED=1 |
| 50 | + |
| 51 | +# Cross-compile via xx-go --wrap. After --wrap, /usr/local/go/bin/go is a |
| 52 | +# shim that sets CC, GOOS, GOARCH, GOARM from $TARGETPLATFORM for every |
| 53 | +# subsequent invocation in this stage. Use explicit per-binary go build |
| 54 | +# -o to bypass go install's $GOPATH/bin/$GOOS_$GOARCH/<name> redirect for |
| 55 | +# cross-targets (Go refuses GOBIN override on cross-compile). |
18 | 56 | ARG VERSION |
19 | 57 | ARG HOSTMOUNT_PREFIX |
20 | 58 |
|
21 | 59 | RUN --mount=type=cache,target=/go/pkg/mod/ \ |
22 | 60 | --mount=src=.,target=. \ |
23 | | - make install VERSION=$VERSION HOSTMOUNT_PREFIX=$HOSTMOUNT_PREFIX |
| 61 | + xx-go --wrap && \ |
| 62 | + # Silent-CGO-disable guard: source/cpu/cpuid_linux_{arm,arm64,ppc64le,s390x}.go |
| 63 | + # each `import "C"` and wrap glibc's getauxval() via a small inline C |
| 64 | + # function called gethwcap(). If xx-apt-get install silently failed |
| 65 | + # or xx-go --wrap unset CGO_ENABLED, those files get build-tag-filtered |
| 66 | + # out and the binary would ship with empty CPU feature labels at |
| 67 | + # runtime with no build error. |
| 68 | + # |
| 69 | + # We probe by building an UNSTRIPPED nfd-worker (the production build |
| 70 | + # below uses -s -w which destroys the symbol table) and grepping for |
| 71 | + # the CGO-emitted wrapper symbol that can only exist if the linux |
| 72 | + # cpuid file was compiled+linked. The Go package object is then |
| 73 | + # cached, so the production -s -w link is cheap. |
| 74 | + # |
| 75 | + # amd64 is excluded: source/cpu/cpuid_amd64.go uses pure-Go cpuid via |
| 76 | + # github.com/klauspost/cpuid/v2 — no CGO required on that arch. |
| 77 | + case "$TARGETARCH" in \ |
| 78 | + arm64|arm|ppc64le|s390x) \ |
| 79 | + go build -v -tags osusergo,netgo -o /tmp/nfd-worker-guard ./cmd/nfd-worker && \ |
| 80 | + go tool nm /tmp/nfd-worker-guard | grep -q 'source/cpu\._Cfunc_gethwcap' \ |
| 81 | + || { echo "FAIL: source/cpu._Cfunc_gethwcap missing from nfd-worker — CGO likely disabled for $TARGETPLATFORM"; exit 1; } && \ |
| 82 | + rm -f /tmp/nfd-worker-guard \ |
| 83 | + ;; \ |
| 84 | + esac && \ |
| 85 | + for bin in nfd-master nfd-worker nfd-topology-updater nfd-gc kubectl-nfd nfd; do \ |
| 86 | + go build -v -tags osusergo,netgo \ |
| 87 | + -ldflags "-s -w -extldflags=-static -X sigs.k8s.io/node-feature-discovery/pkg/version.version=${VERSION} -X sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath.pathPrefix=${HOSTMOUNT_PREFIX}" \ |
| 88 | + -o /go/bin/$bin ./cmd/$bin || exit 1; \ |
| 89 | + done && \ |
| 90 | + xx-verify /go/bin/nfd-master |
| 91 | + |
| 92 | +# Runtime stages run at $TARGETPLATFORM (implicit). They only COPY, set USER, |
| 93 | +# and set ENV — trivial work under QEMU. |
24 | 94 |
|
25 | | -# Create full variant of the production image |
26 | 95 | FROM ${BASE_IMAGE_FULL:-debian:stable-slim} AS full |
27 | 96 |
|
28 | | -# Run as unprivileged user |
29 | 97 | USER 65534:65534 |
30 | | - |
31 | | -# Use more verbose logging of gRPC |
32 | 98 | ENV GRPC_GO_LOG_SEVERITY_LEVEL="INFO" |
33 | 99 |
|
34 | 100 | COPY deployment/components/worker-config/nfd-worker.conf.example /etc/kubernetes/node-feature-discovery/nfd-worker.conf |
35 | | -COPY --from=builder /go/bin/* /usr/bin/ |
| 101 | +# Enumerate explicitly — matches Makefile BUILD_BINARIES. Defensive against |
| 102 | +# any future shim-leakage from xx-go. |
| 103 | +COPY --from=builder /go/bin/nfd-master /go/bin/nfd-worker /go/bin/nfd-topology-updater /go/bin/nfd-gc /go/bin/kubectl-nfd /go/bin/nfd /usr/bin/ |
36 | 104 |
|
37 | | -# Create minimal variant of the production image |
38 | 105 | FROM ${BASE_IMAGE_MINIMAL:-scratch} AS minimal |
39 | 106 |
|
40 | | -# Run as unprivileged user |
41 | 107 | USER 65534:65534 |
42 | | - |
43 | | -# Use more verbose logging of gRPC |
44 | 108 | ENV GRPC_GO_LOG_SEVERITY_LEVEL="INFO" |
45 | 109 |
|
46 | 110 | COPY deployment/components/worker-config/nfd-worker.conf.example /etc/kubernetes/node-feature-discovery/nfd-worker.conf |
47 | | -COPY --from=builder /go/bin/* /usr/bin/ |
| 111 | +COPY --from=builder /go/bin/nfd-master /go/bin/nfd-worker /go/bin/nfd-topology-updater /go/bin/nfd-gc /go/bin/kubectl-nfd /go/bin/nfd /usr/bin/ |
0 commit comments