Unverified Commit bc320806 authored by Ran Rubin's avatar Ran Rubin Committed by GitHub
Browse files

chore: self contained EPP Dockerfile (#6412)

parent 2316516e
......@@ -16,18 +16,64 @@
# Modifications Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES
# Dynamo EPP Dockerfile
# Builds a custom EPP image with Dynamo KV-aware routing plugins
# Self-contained 3-stage build: Rust FFI library → Go binary → Runtime
#
# PREREQUISITES: Run `make dynamo-lib` before building this image to ensure
# the Dynamo FFI library and headers are in place.
# 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 BUILDER_IMAGE=golang:1.24-bookworm
ARG RUST_IMAGE=rust:1.90
ARG BUILDER_IMAGE=golang:1.24
ARG BASE_IMAGE=ubuntu:24.04
# =============================================================================
# Build stage
# 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.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/ && \
cp lib/bindings/c/include/nvidia/dynamo_llm/llm_engine.h /out/
# =============================================================================
# Stage 2: Build Go EPP binary
# =============================================================================
FROM ${BUILDER_IMAGE} AS builder
FROM ${BUILDER_IMAGE} AS go-builder
# Docker buildx provides these automatically for multi-platform builds
ARG TARGETOS=linux
......@@ -45,33 +91,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libc-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy go mod files first for better caching
# Copy go mod files first for better caching (from default context = epp/)
COPY go.mod go.sum ./
RUN go mod download
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
# Copy the source code (including pre-built Dynamo library)
# Copy Go source (from default context = epp/)
COPY . .
# Verify Dynamo library exists
RUN if [ ! -f "pkg/plugins/dynamo_kv_scorer/lib/libdynamo_llm_capi.a" ]; then \
echo "ERROR: Dynamo library not found!"; \
echo "Run 'make dynamo-lib' before building the Docker image."; \
exit 1; \
fi
# 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/
# Build with CGO enabled for the Dynamo FFI
# Use TARGETOS/TARGETARCH from Docker buildx for proper platform support
RUN CGO_ENABLED=1 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
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
# =============================================================================
# Runtime stage
# Stage 3: Runtime
# =============================================================================
FROM ${BASE_IMAGE}
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libstdc++6 \
......@@ -79,13 +122,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /
# Copy the binary from builder
COPY --from=builder /workspace/epp .
COPY --from=go-builder /workspace/epp .
# Note: EPP config is mounted via Kubernetes ConfigMap at runtime
# See helm/dynamo-gaie/templates/epp-configmap.yaml
# Create non-root user
RUN useradd -r -u 65532 -g nogroup nonroot
USER 65532:65534
......
......@@ -2,7 +2,6 @@
# Builds custom EPP image with Dynamo KV-aware routing plugins
# Image configuration
# Image lives in local cache only, not pushed to any registry
DOCKER_SERVER ?= dynamo
IMAGE_NAME := dynamo-epp
GIT_COMMIT_SHA ?= $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
......@@ -11,8 +10,8 @@ IMAGE_REPO ?= $(DOCKER_SERVER)/$(IMAGE_NAME)
IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG)
# Build configuration
# Auto-detect host architecture for consistent builds with Dynamo library
# The Dynamo library is built for the host arch, so Docker must match
# PLATFORMS: defaults to host arch for fast local builds (image-load, image-kind)
# MULTIARCH_PLATFORMS: used by image-multiarch for multi-architecture manifests
HOST_ARCH := $(shell uname -m)
ifeq ($(HOST_ARCH),x86_64)
PLATFORMS ?= linux/amd64
......@@ -23,12 +22,13 @@ else ifeq ($(HOST_ARCH),arm64)
else
PLATFORMS ?= linux/amd64
endif
MULTIARCH_PLATFORMS ?= linux/amd64,linux/arm64
# Docker proxy for avoiding rate limits (e.g., ECR mirror)
# Set DOCKER_PROXY to prefix base images, e.g., DOCKER_PROXY=my-registry.com/dockerhub/
DOCKER_PROXY ?=
DOCKER_BUILDX_CMD ?= docker buildx
IMAGE_BUILD_CMD ?= $(DOCKER_BUILDX_CMD) build
RUST_IMAGE ?= $(DOCKER_PROXY)rust:1.90
BUILDER_IMAGE ?= $(DOCKER_PROXY)golang:1.24
BASE_IMAGE ?= $(DOCKER_PROXY)ubuntu:24.04
......@@ -41,9 +41,10 @@ KIND_CLUSTER ?= kind
# Project directory
PROJECT_DIR := $(shell pwd)
# Dynamo directories
# Default: assume we're in dynamo/deploy/inference-gateway/epp
# Dynamo repository root (build context for Docker)
DYNAMO_DIR ?= $(shell cd $(PROJECT_DIR)/../../.. && pwd)
# Local development paths (for host-native builds only, not used by Docker)
DYNAMO_LIB_DIR := $(PROJECT_DIR)/pkg/plugins/dynamo_kv_scorer/lib
DYNAMO_INCLUDE_DIR := $(PROJECT_DIR)/pkg/plugins/dynamo_kv_scorer/include
......@@ -79,16 +80,16 @@ build: dynamo-lib-check ## Build the EPP binary locally (requires CGO and Dynamo
build-with-lib: dynamo-lib build ## Build Dynamo library and EPP binary
.PHONY: image-build
image-build: dynamo-lib-check ## Build the Docker image using buildx
image-build: ## Build the Docker image (self-contained, no host prerequisites)
$(IMAGE_BUILD_CMD) -t $(IMAGE_TAG) \
--platform=$(PLATFORMS) \
--build-context dynamo=$(DYNAMO_DIR) \
--build-arg RUST_IMAGE=$(RUST_IMAGE) \
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
--build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) \
--build-arg COMMIT_SHA=$(GIT_COMMIT_SHA) \
--build-arg BUILD_REF=$(GIT_TAG) \
$(PUSH) \
$(LOAD) \
.
$(PUSH) $(LOAD) .
.PHONY: image-push
image-push: PUSH=--push ## Build and push the Docker image
......@@ -102,6 +103,25 @@ image-load: image-build
image-kind: image-load ## Build and load the image into kind cluster
kind load docker-image $(IMAGE_TAG) --name $(KIND_CLUSTER)
##@ Multi-Architecture Builds
.PHONY: image-multiarch
image-multiarch: ## Build multi-arch image (requires --push ; --load not supported)
$(IMAGE_BUILD_CMD) -t $(IMAGE_TAG) \
--platform=$(MULTIARCH_PLATFORMS) \
--build-context dynamo=$(DYNAMO_DIR) \
--build-arg RUST_IMAGE=$(RUST_IMAGE) \
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
--build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) \
--build-arg COMMIT_SHA=$(GIT_COMMIT_SHA) \
--build-arg BUILD_REF=$(GIT_TAG) \
$(PUSH) .
.PHONY: image-multiarch-push
image-multiarch-push: PUSH=--push ## Build and push multi-arch image to registry
image-multiarch-push: image-multiarch
##@ Local Development with Buildx
.PHONY: image-local-build
......@@ -118,18 +138,12 @@ image-local-push: image-local-build
image-local-load: LOAD=--load ## Build and load using local buildx builder
image-local-load: image-local-build
##@ Dynamo Library Build
##@ Dynamo Library (for local host-native builds only)
.PHONY: dynamo-lib
dynamo-lib: ## Build Dynamo static library and copy to project
dynamo-lib: ## Build Dynamo static library and copy to project (for local dev)
@echo "Building Dynamo static library..."
cd "$(DYNAMO_DIR)" && cargo build --release -p libdynamo_llm
@echo "Generating C header..."
@mkdir -p "$(DYNAMO_DIR)/lib/bindings/c/include/nvidia/dynamo_llm"
cd "$(DYNAMO_DIR)" && \
(cbindgen --config lib/bindings/c/cbindgen.toml --crate libdynamo_llm \
--output lib/bindings/c/include/nvidia/dynamo_llm/llm_engine.h || \
cp lib/bindings/c/src/fallback_header.h lib/bindings/c/include/nvidia/dynamo_llm/llm_engine.h)
@echo "Copying files to EPP project..."
@mkdir -p "$(DYNAMO_LIB_DIR)"
@mkdir -p "$(DYNAMO_INCLUDE_DIR)"
......@@ -138,7 +152,7 @@ dynamo-lib: ## Build Dynamo static library and copy to project
@echo "Dynamo library ready!"
.PHONY: dynamo-lib-check
dynamo-lib-check: ## Check if Dynamo library files exist
dynamo-lib-check: ## Check if Dynamo library files exist (for local dev)
@if [ ! -f "$(DYNAMO_LIB_DIR)/libdynamo_llm_capi.a" ]; then \
echo "ERROR: Dynamo library not found. Run 'make dynamo-lib' first."; \
exit 1; \
......@@ -159,13 +173,13 @@ clean: ## Clean build artifacts
##@ All-in-one Build
.PHONY: all
all: dynamo-lib image-local-load ## Build Dynamo lib and Docker image, load locally
all: image-local-load ## Build Docker image and load locally
.PHONY: all-push
all-push: dynamo-lib image-push ## Build Dynamo lib and Docker image, push to registry
all-push: image-push ## Build Docker image and push to registry
.PHONY: all-kind
all-kind: dynamo-lib image-kind ## Build Dynamo lib and Docker image, load to kind
all-kind: image-kind ## Build Docker image and load to kind
##@ Info
......@@ -175,10 +189,9 @@ info: ## Show build info
@echo "Git Commit: $(GIT_COMMIT_SHA)"
@echo "Git Tag: $(GIT_TAG)"
@echo "Platforms: $(PLATFORMS)"
@echo "Multi-Arch Platforms: $(MULTIARCH_PLATFORMS)"
@echo "Docker Proxy: $(DOCKER_PROXY)"
@echo "Rust Image: $(RUST_IMAGE)"
@echo "Builder Image: $(BUILDER_IMAGE)"
@echo "Base Image: $(BASE_IMAGE)"
@echo "Dynamo Dir: $(DYNAMO_DIR)"
@echo "Dynamo Lib Dir: $(DYNAMO_LIB_DIR)"
@echo "Dynamo Include Dir: $(DYNAMO_INCLUDE_DIR)"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment