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 @@ ...@@ -16,18 +16,64 @@
# Modifications Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES # Modifications Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES
# Dynamo EPP Dockerfile # 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 # Uses two build contexts (requires Docker BuildKit):
# the Dynamo FFI library and headers are in place. # - 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 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 # Docker buildx provides these automatically for multi-platform builds
ARG TARGETOS=linux ARG TARGETOS=linux
...@@ -45,33 +91,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ...@@ -45,33 +91,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libc-dev \ libc-dev \
&& rm -rf /var/lib/apt/lists/* && 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 ./ 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 . . COPY . .
# Verify Dynamo library exists # Place Rust artifacts where CGO expects them (see plugin.go #cgo directives)
RUN if [ ! -f "pkg/plugins/dynamo_kv_scorer/lib/libdynamo_llm_capi.a" ]; then \ COPY --from=rust-builder /out/libdynamo_llm_capi.a pkg/plugins/dynamo_kv_scorer/lib/
echo "ERROR: Dynamo library not found!"; \ COPY --from=rust-builder /out/llm_engine.h pkg/plugins/dynamo_kv_scorer/include/
echo "Run 'make dynamo-lib' before building the Docker image."; \
exit 1; \
fi
# Build with CGO enabled for the Dynamo FFI RUN --mount=type=cache,target=/go/pkg/mod \
# Use TARGETOS/TARGETARCH from Docker buildx for proper platform support --mount=type=cache,target=/root/.cache/go-build \
RUN CGO_ENABLED=1 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ CGO_ENABLED=1 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-ldflags="-X sigs.k8s.io/gateway-api-inference-extension/version.GitVersion=${BUILD_REF} \ -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}" \ -X sigs.k8s.io/gateway-api-inference-extension/version.GitCommit=${COMMIT_SHA}" \
-o epp ./cmd/epp -o epp ./cmd/epp
# ============================================================================= # =============================================================================
# Runtime stage # Stage 3: Runtime
# ============================================================================= # =============================================================================
FROM ${BASE_IMAGE} FROM ${BASE_IMAGE}
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \ ca-certificates \
libstdc++6 \ libstdc++6 \
...@@ -79,13 +122,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ...@@ -79,13 +122,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR / WORKDIR /
# Copy the binary from builder COPY --from=go-builder /workspace/epp .
COPY --from=builder /workspace/epp .
# Note: EPP config is mounted via Kubernetes ConfigMap at runtime # Note: EPP config is mounted via Kubernetes ConfigMap at runtime
# See helm/dynamo-gaie/templates/epp-configmap.yaml # See helm/dynamo-gaie/templates/epp-configmap.yaml
# Create non-root user
RUN useradd -r -u 65532 -g nogroup nonroot RUN useradd -r -u 65532 -g nogroup nonroot
USER 65532:65534 USER 65532:65534
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
# Builds custom EPP image with Dynamo KV-aware routing plugins # Builds custom EPP image with Dynamo KV-aware routing plugins
# Image configuration # Image configuration
# Image lives in local cache only, not pushed to any registry
DOCKER_SERVER ?= dynamo DOCKER_SERVER ?= dynamo
IMAGE_NAME := dynamo-epp IMAGE_NAME := dynamo-epp
GIT_COMMIT_SHA ?= $(shell git rev-parse HEAD 2>/dev/null || echo "unknown") GIT_COMMIT_SHA ?= $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
...@@ -11,8 +10,8 @@ IMAGE_REPO ?= $(DOCKER_SERVER)/$(IMAGE_NAME) ...@@ -11,8 +10,8 @@ IMAGE_REPO ?= $(DOCKER_SERVER)/$(IMAGE_NAME)
IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG) IMAGE_TAG ?= $(IMAGE_REPO):$(GIT_TAG)
# Build configuration # Build configuration
# Auto-detect host architecture for consistent builds with Dynamo library # PLATFORMS: defaults to host arch for fast local builds (image-load, image-kind)
# The Dynamo library is built for the host arch, so Docker must match # MULTIARCH_PLATFORMS: used by image-multiarch for multi-architecture manifests
HOST_ARCH := $(shell uname -m) HOST_ARCH := $(shell uname -m)
ifeq ($(HOST_ARCH),x86_64) ifeq ($(HOST_ARCH),x86_64)
PLATFORMS ?= linux/amd64 PLATFORMS ?= linux/amd64
...@@ -23,12 +22,13 @@ else ifeq ($(HOST_ARCH),arm64) ...@@ -23,12 +22,13 @@ else ifeq ($(HOST_ARCH),arm64)
else else
PLATFORMS ?= linux/amd64 PLATFORMS ?= linux/amd64
endif endif
MULTIARCH_PLATFORMS ?= linux/amd64,linux/arm64
# Docker proxy for avoiding rate limits (e.g., ECR mirror) # 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_PROXY ?=
DOCKER_BUILDX_CMD ?= docker buildx DOCKER_BUILDX_CMD ?= docker buildx
IMAGE_BUILD_CMD ?= $(DOCKER_BUILDX_CMD) build IMAGE_BUILD_CMD ?= $(DOCKER_BUILDX_CMD) build
RUST_IMAGE ?= $(DOCKER_PROXY)rust:1.90
BUILDER_IMAGE ?= $(DOCKER_PROXY)golang:1.24 BUILDER_IMAGE ?= $(DOCKER_PROXY)golang:1.24
BASE_IMAGE ?= $(DOCKER_PROXY)ubuntu:24.04 BASE_IMAGE ?= $(DOCKER_PROXY)ubuntu:24.04
...@@ -41,9 +41,10 @@ KIND_CLUSTER ?= kind ...@@ -41,9 +41,10 @@ KIND_CLUSTER ?= kind
# Project directory # Project directory
PROJECT_DIR := $(shell pwd) PROJECT_DIR := $(shell pwd)
# Dynamo directories # Dynamo repository root (build context for Docker)
# Default: assume we're in dynamo/deploy/inference-gateway/epp
DYNAMO_DIR ?= $(shell cd $(PROJECT_DIR)/../../.. && pwd) 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_LIB_DIR := $(PROJECT_DIR)/pkg/plugins/dynamo_kv_scorer/lib
DYNAMO_INCLUDE_DIR := $(PROJECT_DIR)/pkg/plugins/dynamo_kv_scorer/include 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 ...@@ -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 build-with-lib: dynamo-lib build ## Build Dynamo library and EPP binary
.PHONY: image-build .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) \ $(IMAGE_BUILD_CMD) -t $(IMAGE_TAG) \
--platform=$(PLATFORMS) \ --platform=$(PLATFORMS) \
--build-context dynamo=$(DYNAMO_DIR) \
--build-arg RUST_IMAGE=$(RUST_IMAGE) \
--build-arg BASE_IMAGE=$(BASE_IMAGE) \ --build-arg BASE_IMAGE=$(BASE_IMAGE) \
--build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) \ --build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) \
--build-arg COMMIT_SHA=$(GIT_COMMIT_SHA) \ --build-arg COMMIT_SHA=$(GIT_COMMIT_SHA) \
--build-arg BUILD_REF=$(GIT_TAG) \ --build-arg BUILD_REF=$(GIT_TAG) \
$(PUSH) \ $(PUSH) $(LOAD) .
$(LOAD) \
.
.PHONY: image-push .PHONY: image-push
image-push: PUSH=--push ## Build and push the Docker image image-push: PUSH=--push ## Build and push the Docker image
...@@ -102,6 +103,25 @@ image-load: image-build ...@@ -102,6 +103,25 @@ image-load: image-build
image-kind: image-load ## Build and load the image into kind cluster image-kind: image-load ## Build and load the image into kind cluster
kind load docker-image $(IMAGE_TAG) --name $(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 ##@ Local Development with Buildx
.PHONY: image-local-build .PHONY: image-local-build
...@@ -118,18 +138,12 @@ image-local-push: 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: LOAD=--load ## Build and load using local buildx builder
image-local-load: image-local-build image-local-load: image-local-build
##@ Dynamo Library Build ##@ Dynamo Library (for local host-native builds only)
.PHONY: dynamo-lib .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..." @echo "Building Dynamo static library..."
cd "$(DYNAMO_DIR)" && cargo build --release -p libdynamo_llm 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..." @echo "Copying files to EPP project..."
@mkdir -p "$(DYNAMO_LIB_DIR)" @mkdir -p "$(DYNAMO_LIB_DIR)"
@mkdir -p "$(DYNAMO_INCLUDE_DIR)" @mkdir -p "$(DYNAMO_INCLUDE_DIR)"
...@@ -138,7 +152,7 @@ dynamo-lib: ## Build Dynamo static library and copy to project ...@@ -138,7 +152,7 @@ dynamo-lib: ## Build Dynamo static library and copy to project
@echo "Dynamo library ready!" @echo "Dynamo library ready!"
.PHONY: dynamo-lib-check .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 \ @if [ ! -f "$(DYNAMO_LIB_DIR)/libdynamo_llm_capi.a" ]; then \
echo "ERROR: Dynamo library not found. Run 'make dynamo-lib' first."; \ echo "ERROR: Dynamo library not found. Run 'make dynamo-lib' first."; \
exit 1; \ exit 1; \
...@@ -159,13 +173,13 @@ clean: ## Clean build artifacts ...@@ -159,13 +173,13 @@ clean: ## Clean build artifacts
##@ All-in-one Build ##@ All-in-one Build
.PHONY: all .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 .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 .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 ##@ Info
...@@ -175,10 +189,9 @@ info: ## Show build info ...@@ -175,10 +189,9 @@ info: ## Show build info
@echo "Git Commit: $(GIT_COMMIT_SHA)" @echo "Git Commit: $(GIT_COMMIT_SHA)"
@echo "Git Tag: $(GIT_TAG)" @echo "Git Tag: $(GIT_TAG)"
@echo "Platforms: $(PLATFORMS)" @echo "Platforms: $(PLATFORMS)"
@echo "Multi-Arch Platforms: $(MULTIARCH_PLATFORMS)"
@echo "Docker Proxy: $(DOCKER_PROXY)" @echo "Docker Proxy: $(DOCKER_PROXY)"
@echo "Rust Image: $(RUST_IMAGE)"
@echo "Builder Image: $(BUILDER_IMAGE)" @echo "Builder Image: $(BUILDER_IMAGE)"
@echo "Base Image: $(BASE_IMAGE)" @echo "Base Image: $(BASE_IMAGE)"
@echo "Dynamo Dir: $(DYNAMO_DIR)" @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