Skip to content

Commit e772a0d

Browse files
committed
ADR-0007 level-3: GPU image variant, rehearsed on kind 7/7 + baseline 6/6
Dockerfile parameterized via build args: default unchanged (musl static on distroless/static), GPU variant builds the gnu target with feature gpu-nvidia on distroless/cc-debian12 -- nvml-wrapper dlopens libnvidia-ml.so at runtime, which a static musl binary cannot do, so the GPU build must be dynamically linked (verified: interpreter present in the builder stage). NVIDIA driver libs are injected by the node container runtime, never baked in. Rehearsal script grows GPU_VARIANT=1: same cluster, same asserts, but the image is the exact level-3 GPU build with REPORTER_GPU=nvidia set. kind has no GPU, so the double gate must fail open -- assert 7 requires the NVML init-failure warning on every reporter. Also fixes the helm image tag to derive from IMG (was hardcoded, broke any variant tag with ErrImageNeverPull). Evidence (local runs/, gitignored by design -- kind rehearsal evidence stays off-repo, GPU-session evidence is what gets committed): GPU variant 7/7 (20260722T162142), baseline re-run 6/6 (20260722T162312).
1 parent a3b9fee commit e772a0d

2 files changed

Lines changed: 48 additions & 12 deletions

File tree

Dockerfile

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
# syntax=docker/dockerfile:1.7
2+
# ---- Build args ------------------------------------------------------------
3+
# Default: static musl binary on distroless/static (CPU-only path, unchanged).
4+
# GPU variant (level-3 sessions): nvml-wrapper dlopens libnvidia-ml.so at
5+
# runtime, which a static musl binary cannot do. Build with:
6+
# --build-arg RUST_TARGET=x86_64-unknown-linux-gnu \
7+
# --build-arg CARGO_FEATURES=gpu-nvidia \
8+
# --build-arg RUNTIME_IMAGE=gcr.io/distroless/cc-debian12:nonroot
9+
# (distroless/cc = glibc + dynamic loader; NVIDIA driver libs are injected
10+
# on the node by the NVIDIA container runtime, never baked into the image.)
11+
ARG RUNTIME_IMAGE=gcr.io/distroless/static:nonroot
212
# ---- Builder ---------------------------------------------------------------
313
# Pinned to the dev toolchain (1.95) for reproducible builds.
4-
# Static musl target -> single self-contained binary, no shared libs at runtime.
514
FROM rust:1.95-bookworm AS builder
15+
ARG RUST_TARGET=x86_64-unknown-linux-musl
16+
ARG CARGO_FEATURES=""
617
RUN apt-get update \
718
&& apt-get install -y --no-install-recommends musl-tools \
819
&& rm -rf /var/lib/apt/lists/* \
9-
&& rustup target add x86_64-unknown-linux-musl
20+
&& rustup target add "${RUST_TARGET}"
1021
WORKDIR /build
1122
# Manifests + sources together: the manifest uses target auto-discovery,
1223
# so `cargo fetch` needs the targets present. Heavy compile cost stays
@@ -15,23 +26,25 @@ COPY Cargo.toml Cargo.lock ./
1526
COPY src ./src
1627
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
1728
cargo fetch --locked
18-
# CC points at musl-gcc so ring's C code compiles for the musl target.
29+
# CC points at musl-gcc so ring's C code compiles for the musl target
30+
# (harmless for the gnu target, which never reads this variable).
1931
# The LINKER is intentionally NOT overridden: rustc's default linker emits a
2032
# correct static-pie binary, whereas forcing musl-gcc as linker breaks
2133
# static-pie and produces a bogus INTERP (rust-lang/rust#95926).
2234
ENV CC_x86_64_unknown_linux_musl=musl-gcc
2335
RUN --mount=type=cache,target=/build/target,sharing=locked \
2436
--mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
2537
cargo build --release --locked \
26-
--target x86_64-unknown-linux-musl \
38+
--target "${RUST_TARGET}" \
39+
${CARGO_FEATURES:+--features "${CARGO_FEATURES}"} \
2740
--bin vllm-coldstart-operator \
2841
--bin reporter \
29-
&& cp target/x86_64-unknown-linux-musl/release/vllm-coldstart-operator /vllm-coldstart-operator \
30-
&& cp target/x86_64-unknown-linux-musl/release/reporter /reporter \
42+
&& cp "target/${RUST_TARGET}/release/vllm-coldstart-operator" /vllm-coldstart-operator \
43+
&& cp "target/${RUST_TARGET}/release/reporter" /reporter \
3144
&& strip /vllm-coldstart-operator /reporter
3245
# ---- Runtime ---------------------------------------------------------------
33-
# distroless static: no shell, no libc, nonroot (uid 65532) by default.
34-
FROM gcr.io/distroless/static:nonroot AS runtime
46+
# Default distroless static: no shell, no libc, nonroot (uid 65532).
47+
FROM ${RUNTIME_IMAGE} AS runtime
3548
LABEL org.opencontainers.image.source="https://github.com/MicheleCampi/vllm-coldstart-operator"
3649
LABEL org.opencontainers.image.description="Kubernetes operator for vLLM cold-start lifecycle management"
3750
LABEL org.opencontainers.image.licenses="Apache-2.0"

hack/rehearsal/adr0007-real-source.sh

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,24 @@
99
# 5) gpuUtilization/gpuMemoryUsedBytes ABSENT on every worker (NVML not
1010
# wired = key deleted by merge-patch null, not zero)
1111
# 6) reporter logs free of panics
12+
# GPU_VARIANT=1: same asserts, but the image is the level-3 GPU build
13+
# (gnu target + gpu-nvidia feature + distroless/cc) with REPORTER_GPU=nvidia
14+
# set. kind has no GPU, so the double gate must fail open: adds assert
15+
# 7) every reporter logs the NVML init failure warning
1216
set -euo pipefail
1317
cd "$(dirname "$0")/../.."
1418
CLUSTER="${CLUSTER:-adr0007rs}"
1519
CTX="kind-${CLUSTER}"
16-
IMG="vllm-coldstart-operator:adr0007rs"
20+
GPU_VARIANT="${GPU_VARIANT:-}"
21+
if [ -n "$GPU_VARIANT" ]; then
22+
IMG="vllm-coldstart-operator:adr0007rs-gpu"
23+
BUILD_ARGS=(--build-arg RUST_TARGET=x86_64-unknown-linux-gnu
24+
--build-arg CARGO_FEATURES=gpu-nvidia
25+
--build-arg RUNTIME_IMAGE=gcr.io/distroless/cc-debian12:nonroot)
26+
else
27+
IMG="vllm-coldstart-operator:adr0007rs"
28+
BUILD_ARGS=()
29+
fi
1730
TS="$(date -u +%Y%m%dT%H%M%S)"
1831
RUN_DIR="hack/rehearsal/runs/${TS}-adr0007-real-source"
1932
mkdir -p "$RUN_DIR"
@@ -36,7 +49,7 @@ nodes:
3649
KINDCFG
3750

3851
echo "==> build + load operator image"
39-
docker build -t "$IMG" .
52+
docker build "${BUILD_ARGS[@]}" -t "$IMG" .
4053
kind load docker-image "$IMG" --name "$CLUSTER"
4154

4255
echo "==> fixtures: fake vLLM /metrics with advancing counters"
@@ -82,15 +95,16 @@ echo "==> CRDs + chart install (reporter enabled, REAL source, per-node targets)
8295
kubectl --context "$CTX" apply --server-side -f deploy/crd.yaml
8396
helm --kube-context "$CTX" install adr7rs chart/ \
8497
--set image.repository=vllm-coldstart-operator \
85-
--set image.tag=adr0007rs \
98+
--set "image.tag=${IMG##*:}" \
8699
--set image.pullPolicy=Never \
87100
--set reporter.enabled=true \
88101
--set-string 'reporter.extraEnv[0].name=REPORTER_SCRAPE_TARGETS_NODE_ADR0007RS_WORKER' \
89102
--set-string 'reporter.extraEnv[0].value=http://fixture-a.default.svc.cluster.local:9090/metrics' \
90103
--set-string 'reporter.extraEnv[1].name=REPORTER_SCRAPE_TARGETS_NODE_ADR0007RS_WORKER2' \
91104
--set-string 'reporter.extraEnv[1].value=http://fixture-b.default.svc.cluster.local:9090/metrics' \
92105
--set-string 'reporter.extraEnv[2].name=REPORTER_SCRAPE_TARGETS_NODE_ADR0007RS_WORKER3' \
93-
--set-string 'reporter.extraEnv[2].value=http://no-such-service.default.svc.cluster.local:9090/metrics'
106+
--set-string 'reporter.extraEnv[2].value=http://no-such-service.default.svc.cluster.local:9090/metrics' \
107+
${GPU_VARIANT:+--set-string 'reporter.extraEnv[3].name=REPORTER_GPU' --set-string 'reporter.extraEnv[3].value=nvidia'}
94108

95109
kubectl --context "$CTX" rollout status deployment/adr7rs-vllm-coldstart-operator --timeout=120s
96110
kubectl --context "$CTX" rollout status daemonset/adr7rs-vllm-coldstart-operator-reporter --timeout=120s
@@ -134,6 +148,15 @@ for p in $(kubectl --context "$CTX" get pods -l app.kubernetes.io/component=repo
134148
done
135149
ok=0; [ "$PANICS" -eq 0 ] || ok=1; verdict "reporter logs free of panics" $ok
136150

151+
if [ -n "$GPU_VARIANT" ]; then
152+
MISSING=0
153+
for f in "$RUN_DIR"/reporter-*.log; do
154+
grep -qi "NVML init failed" "$f" || MISSING=$((MISSING + 1))
155+
done
156+
ok=0; [ "$MISSING" -eq 0 ] || ok=1
157+
verdict "GPU variant: NVML fail-open warning on every reporter" $ok
158+
fi
159+
137160
echo "==> verdict: ${PASS} pass / ${FAIL} fail (evidence: ${RUN_DIR})"
138161
cat "$RUN_DIR/verdict.txt"
139162
[ "$FAIL" -eq 0 ]

0 commit comments

Comments
 (0)