# SPDX-FileCopyrightText: Copyright The Kubernetes Authors. # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # # http://www.apache.org/licenses/LICENSE-2.0 # # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Modifications Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES # Dynamo EPP Dockerfile # Self-contained 3-stage build: Rust FFI library → Go binary → Runtime # # Uses two build contexts (requires Docker BuildKit): # - Default context (.): the epp/ Go project # - Named context "dynamo": the Dynamo repository root (Rust workspace) # # Build via Makefile (recommended): # make image-load # # Build manually: # docker buildx build \ # --build-context dynamo=../../.. \ # -t dynamo/dynamo-epp:dev . ARG RUST_IMAGE=rust:1.93.1 ARG BUILDER_IMAGE=golang:1.25 ARG BASE_IMAGE=ubuntu:24.04 # ============================================================================= # Stage 1: Build Dynamo FFI static library (Rust) # ============================================================================= FROM ${RUST_IMAGE} AS rust-builder # TARGETARCH is provided automatically by buildx for multi-platform builds. # Used here only for per-platform cache isolation. ARG TARGETARCH # etcd-client crate requires protoc to compile proto files RUN apt-get update && apt-get install -y --no-install-recommends \ protobuf-compiler \ libclang-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /dynamo # Copy Cargo workspace manifests, lockfile, and README (some crates inherit # readme.workspace = true, so cargo needs README.md at the workspace root) COPY --from=dynamo .cargo/ .cargo/ COPY --from=dynamo Cargo.toml Cargo.lock README.md ./ # Copy all workspace crates (libdynamo_llm depends transitively on many) COPY --from=dynamo lib/ lib/ # Build the static library; use BuildKit cache mounts for cargo registry and # build artifacts so incremental Docker rebuilds are fast. # Cache IDs are keyed by TARGETARCH so multi-platform builds don't collide. # Artifacts are copied to /out/ because the target/ cache mount is ephemeral. RUN --mount=type=cache,target=/usr/local/cargo/registry,id=cargo-registry-${TARGETARCH} \ --mount=type=cache,target=/usr/local/cargo/git,id=cargo-git-${TARGETARCH} \ --mount=type=cache,target=/dynamo/target,id=cargo-target-${TARGETARCH} \ cargo build --release -p libdynamo_llm && \ mkdir -p /out && \ cp target/release/libdynamo_llm_capi.a /out/ && \ HEADER=$(find target/release/build -name llm_engine.h -path "*/out/*" | head -1) && \ [ -n "$HEADER" ] && cp "$HEADER" /out/ || { echo "ERROR: llm_engine.h not found in target/"; exit 1; } # ============================================================================= # Stage 2: Build Go EPP binary # ============================================================================= FROM ${BUILDER_IMAGE} AS go-builder # Docker buildx provides these automatically for multi-platform builds ARG TARGETOS=linux ARG TARGETARCH ARG COMMIT_SHA ARG BUILD_REF WORKDIR /workspace # Install build dependencies for CGO RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ libc-dev \ && rm -rf /var/lib/apt/lists/* # Copy go mod files first for better caching (from default context = epp/) COPY go.mod go.sum ./ RUN --mount=type=cache,target=/go/pkg/mod \ go mod download # Copy Go source (from default context = epp/) COPY . . # Place Rust artifacts where CGO expects them (see plugin.go #cgo directives) COPY --from=rust-builder /out/libdynamo_llm_capi.a pkg/plugins/dynamo_kv_scorer/lib/ COPY --from=rust-builder /out/llm_engine.h pkg/plugins/dynamo_kv_scorer/include/ RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ CGO_ENABLED=1 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ -ldflags="-X sigs.k8s.io/gateway-api-inference-extension/version.GitVersion=${BUILD_REF} \ -X sigs.k8s.io/gateway-api-inference-extension/version.GitCommit=${COMMIT_SHA}" \ -o epp ./cmd/epp # ============================================================================= # Stage 3: Runtime # ============================================================================= FROM ${BASE_IMAGE} RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ libstdc++6 \ && rm -rf /var/lib/apt/lists/* WORKDIR / COPY --from=go-builder /workspace/epp . # Note: EPP config is mounted via Kubernetes ConfigMap at runtime # See helm/dynamo-gaie/templates/epp-configmap.yaml RUN useradd -r -u 65532 -g nogroup nonroot USER 65532:65534 ENTRYPOINT ["/epp"]