Skip to content

Commit 4aceaa2

Browse files
committed
[coordinator] e2e tests: containerize and share deploy components
Signed-off-by: Revital Sur <eres@il.ibm.com>
1 parent eb5b1fa commit 4aceaa2

18 files changed

Lines changed: 213 additions & 18907 deletions

File tree

Makefile.coord.mk

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
SHELL := /usr/bin/env bash
22

3-
# Image registry + dev-environment image tags (single source of truth).
4-
include versions.mk
5-
6-
# Export all dev-env image references so the e2e suite sees them.
7-
export IMAGE_REGISTRY COORDINATOR_TAG VLLM_SIMULATOR_TAG EPP_TAG
8-
export COORDINATOR_IMAGE VLLM_IMAGE EPP_IMAGE
9-
103
# Defaults
114
TARGETOS ?= $(shell command -v go >/dev/null 2>&1 && go env GOOS || uname -s | tr '[:upper:]' '[:lower:]')
125
TARGETARCH ?= $(shell command -v go >/dev/null 2>&1 && go env GOARCH || uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/; s/armv7l/arm/')
136
PROJECT_NAME ?= llm-d-coordinator
147
BUILDER_IMAGE_NAME ?= llm-d-coordinator-builder
158
IMAGE_REGISTRY ?= ghcr.io/llm-d
169

10+
# Image tags
11+
COORDINATOR_TAG ?= dev
12+
VLLM_SIMULATOR_TAG ?= v0.10.0
13+
EPP_TAG ?= dev
14+
15+
# Full image references (derived; override only if you need a non-standard repo)
16+
COORDINATOR_IMAGE ?= $(IMAGE_REGISTRY)/llm-d-coordinator:$(COORDINATOR_TAG)
17+
VLLM_IMAGE ?= $(IMAGE_REGISTRY)/llm-d-inference-sim:$(VLLM_SIMULATOR_TAG)
18+
EPP_IMAGE ?= $(IMAGE_REGISTRY)/llm-d-router-endpoint-picker:$(EPP_TAG)
19+
20+
# vllm-render defaults to the same image as the other simulated vLLM roles; override
21+
# independently to point it at a real vLLM image (e.g. vllm/vllm-openai-cpu:v0.21.0).
22+
VLLM_RENDER_IMAGE ?= $(VLLM_IMAGE)
23+
VLLM_RENDER_PORT ?= 8082
24+
1725
# Internal variable mappings for the generic image-build-% target.
1826
coordinator_IMAGE = $(COORDINATOR_IMAGE)
1927
epp_IMAGE = $(EPP_IMAGE)
2028

29+
# Export all dev-env image references so the e2e suite sees them.
30+
export IMAGE_REGISTRY COORDINATOR_TAG VLLM_SIMULATOR_TAG EPP_TAG
31+
export COORDINATOR_IMAGE VLLM_IMAGE EPP_IMAGE VLLM_RENDER_IMAGE VLLM_RENDER_PORT
32+
2133
BUILDER_TAG ?= dev
2234
BUILDER_TAG_BASE ?= $(IMAGE_REGISTRY)/$(BUILDER_IMAGE_NAME)
2335
export BUILDER_IMAGE ?= $(BUILDER_TAG_BASE):$(BUILDER_TAG)
@@ -56,11 +68,64 @@ endif
5668

5769
BUILDER_RUN_FLAGS = --rm $(BUILDER_USER_FLAGS) \
5870
-v $$(pwd):/app:Z -w /app \
59-
-v $(GO_MOD_CACHE_VOL):/go/pkg/mod \
60-
-v $(GO_BUILD_CACHE_VOL):/go/cache
71+
-v $(GO_MOD_CACHE_VOL):/go/pkg/mod:z \
72+
-v $(GO_BUILD_CACHE_VOL):/go/cache:z
6173

6274
BUILDER_RUN = $(CONTAINER_RUNTIME) run $(BUILDER_RUN_FLAGS) $(BUILDER_IMAGE) sh -c
6375

76+
# Mount the container runtime socket and set CONTAINER_HOST so podman --remote
77+
# inside the builder can talk to the host's container runtime.
78+
ifeq ($(CONTAINER_RUNTIME),podman)
79+
CONTAINER_SOCK ?= $(or $(shell podman info --format '{{.Host.RemoteSocket.Path}}' 2>/dev/null | sed 's|^unix://||'),/run/podman/podman.sock)
80+
BUILDER_SOCK_FLAGS = --security-opt label=disable \
81+
-v $(CONTAINER_SOCK):$(CONTAINER_SOCK) \
82+
-e CONTAINER_HOST=unix://$(CONTAINER_SOCK) \
83+
-e DOCKER_HOST=unix://$(CONTAINER_SOCK) \
84+
-e CONTAINER_RUNTIME=podman \
85+
-e KIND_EXPERIMENTAL_PROVIDER=podman
86+
else
87+
CONTAINER_SOCK ?= /var/run/docker.sock
88+
ifeq ($(TARGETOS),darwin)
89+
DOCKER_SOCK_GID := $(shell stat -f '%g' $(CONTAINER_SOCK) 2>/dev/null)
90+
else
91+
DOCKER_SOCK_GID := $(shell stat -c '%g' $(CONTAINER_SOCK) 2>/dev/null)
92+
endif
93+
ifneq ($(DOCKER_SOCK_GID),)
94+
DOCKER_GROUP_PARAM := --group-add $(DOCKER_SOCK_GID)
95+
else
96+
DOCKER_GROUP_PARAM :=
97+
endif
98+
BUILDER_SOCK_FLAGS = $(DOCKER_GROUP_PARAM) \
99+
-v $(CONTAINER_SOCK):$(CONTAINER_SOCK) \
100+
-e DOCKER_HOST=unix://$(CONTAINER_SOCK) \
101+
-e CONTAINER_RUNTIME=docker
102+
endif
103+
104+
# Respect host KUBECONFIG if set; fall back to ~/.kube/config.
105+
HOST_KUBECONFIG ?= $(or $(KUBECONFIG),$(HOME)/.kube/config)
106+
107+
# When K8S_CONTEXT is set, mount the host kubeconfig so the e2e suite can call
108+
# config.GetConfigWithContext(K8S_CONTEXT) against an existing cluster instead of
109+
# creating a new kind cluster.
110+
ifdef K8S_CONTEXT
111+
BUILDER_E2E_KUBECONFIG_FLAGS = -v $(HOST_KUBECONFIG):/.kube/config:ro -e KUBECONFIG=/.kube/config
112+
else
113+
BUILDER_E2E_KUBECONFIG_FLAGS =
114+
endif
115+
116+
# Env vars forwarded into the e2e test container.
117+
E2E_ENV_VARS = COORDINATOR_IMAGE VLLM_IMAGE EPP_IMAGE VLLM_RENDER_IMAGE VLLM_RENDER_PORT \
118+
COORDINATOR_PORT E2E_GATEWAY_PORT E2E_KEEP_CLUSTER_ON_FAILURE \
119+
E2E_PRINT_COORDINATOR_LOGS K8S_CONTEXT READY_TIMEOUT MODEL_NAME
120+
BUILDER_E2E_ENV_FLAGS = $(foreach v,$(E2E_ENV_VARS),$(if $($(v)),-e '$(v)=$($(v))'))
121+
ifneq ($(filter command line environment,$(origin NAMESPACE)),)
122+
BUILDER_E2E_ENV_FLAGS += -e NAMESPACE=$(NAMESPACE)
123+
endif
124+
125+
# E2e tests create their own kind cluster, need host network (for NodePort access)
126+
# and the container socket (for kind), but not the host kubeconfig.
127+
BUILDER_E2E_FLAGS = --network=host $(BUILDER_SOCK_FLAGS) $(BUILDER_E2E_ENV_FLAGS) $(BUILDER_E2E_KUBECONFIG_FLAGS)
128+
64129
BUILDER_STAMP = build/.builder.stamp
65130

66131
.PHONY: help
@@ -132,7 +197,9 @@ test-unit: image-build-builder
132197

133198
.PHONY: test-e2e-coordinator
134199
test-e2e-coordinator: image-build-coordinator image-build-epp image-build-builder image-pull ## Run coordinator e2e tests against a new kind cluster
135-
test/coordinator/scripts/run_e2e_coordinator.sh
200+
@printf "\033[33;1m==== Running Coordinator End to End Tests ====\033[0m\n"
201+
$(CONTAINER_RUNTIME) run $(BUILDER_RUN_FLAGS) $(BUILDER_E2E_FLAGS) \
202+
$(BUILDER_IMAGE) test/coordinator/scripts/run_e2e_coordinator.sh
136203

137204
.PHONY: build
138205
build: image-build-builder ## Build the coordinator binary
@@ -182,10 +249,6 @@ image-build-builder: check-container-tool ## Build builder image if missing loca
182249
touch $(BUILDER_STAMP); \
183250
fi
184251

185-
.PHONY: image-build-epp
186-
image-build-epp: ## Clone llm-d-inference-scheduler at pinned commit and build EPP image
187-
scripts/build-epp-image.sh
188-
189252
.PHONY: image-pull
190253
image-pull: check-container-tool ## Pull all related images using $(CONTAINER_RUNTIME)
191254
@printf "\033[33;1m==== Pulling Container images ====\033[0m\n"

README.coord.md

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,35 @@
22

33
A Go service that orchestrates multi-phase LLM inference pipelines (Encode/Prefill/Decode) across specialized worker pools. It exposes OpenAI-compatible APIs and routes requests through an Inference Gateway to disaggregated vLLM workers.
44

5+
## Table of Contents
6+
7+
- [LLM-D Coordinator](#llm-d-coordinator)
8+
- [Table of Contents](#table-of-contents)
9+
- [Architecture](#architecture)
10+
- [Quick Start](#quick-start)
11+
- [Configuration](#configuration)
12+
- [Server](#server)
13+
- [Gateway](#gateway)
14+
- [Pipeline](#pipeline)
15+
- [Built-in Step Parameters](#built-in-step-parameters)
16+
- [Gateway Routing](#gateway-routing)
17+
- [Plugin API](#plugin-api)
18+
- [Step Interface](#step-interface)
19+
- [Writing a Custom Step](#writing-a-custom-step)
20+
- [Registering the Step](#registering-the-step)
21+
- [Dependency Injection](#dependency-injection)
22+
- [RequestContext](#requestcontext)
23+
- [API Endpoints](#api-endpoints)
24+
- [Docker](#docker)
25+
- [Development](#development)
26+
- [Running Tests](#running-tests)
27+
- [Unit Tests](#unit-tests)
28+
- [End-to-End Tests](#end-to-end-tests)
29+
530
## Architecture
631

732
```
8-
Client -> Coordinator -> Inference Gateway -> EPP -> vLLM Workers
33+
Client -> Inference Gateway -> Coordinator -> Inference Gateway -> EPP -> vLLM Workers
934
```
1035

1136
The Coordinator processes each request through a configurable pipeline of steps:
@@ -243,9 +268,71 @@ docker run -p 8080:8080 -v $(pwd)/config/coordinator:/config/coordinator coordin
243268
The coordinator targets live in `Makefile.coord.mk`; pass it with `-f`:
244269

245270
```bash
246-
make -f Makefile.coord.mk build # Build binary to bin/coordinator
247-
make -f Makefile.coord.mk test # Run all tests
248-
make -f Makefile.coord.mk lint # Run golangci-lint
249-
make -f Makefile.coord.mk tidy # Run go mod tidy
250-
make -f Makefile.coord.mk clean # Remove build artifacts
271+
make -f Makefile.coord.mk build # Build binary to bin/coordinator
272+
make -f Makefile.coord.mk lint # Run golangci-lint
273+
make -f Makefile.coord.mk tidy # Run go mod tidy
274+
make -f Makefile.coord.mk clean # Remove build artifacts
275+
```
276+
277+
### Running Tests
278+
279+
#### Unit Tests
280+
281+
```bash
282+
make -f Makefile.coord.mk test # run all tests
283+
```
284+
285+
#### End-to-End Tests
286+
287+
```bash
288+
make -f Makefile.coord.mk test-e2e-coordinator
289+
```
290+
291+
This creates a temporary Kind cluster named `e2e-coordinator-tests`, runs the coordinator e2e suite against it, and deletes the cluster on completion.
292+
293+
**Keeping the cluster on failure**
294+
295+
Set `E2E_KEEP_CLUSTER_ON_FAILURE=true` to preserve the cluster when any test fails. This is useful for inspecting pod logs, events, or cluster state after a failure.
296+
297+
```bash
298+
E2E_KEEP_CLUSTER_ON_FAILURE=true make -f Makefile.coord.mk test-e2e-coordinator
299+
```
300+
301+
When set, a successful run still cleans up normally: the cluster is only kept if there is at least one test failure.
302+
303+
**Accessing the cluster after a failure**
304+
305+
E2E tests do not update the host's kubeconfig to point at the `e2e-coordinator-tests` Kind cluster. After a preserved failure, export the kubeconfig manually:
306+
307+
```bash
308+
# Merge into the default kubeconfig ($HOME/.kube/config or $KUBECONFIG)
309+
kind export kubeconfig --name e2e-coordinator-tests
310+
311+
# Or write to a specific file
312+
kind export kubeconfig --name e2e-coordinator-tests --kubeconfig /path/to/kubeconfig
251313
```
314+
315+
Then use it as normal:
316+
317+
```bash
318+
kubectl --context kind-e2e-coordinator-tests get pods
319+
```
320+
321+
**Environment variables**
322+
323+
| Variable | Default | Description |
324+
|---|---|---|
325+
| `E2E_KEEP_CLUSTER_ON_FAILURE` | `false` | Preserve the Kind cluster when the suite fails |
326+
| `COORDINATOR_PORT` | `30081` | Host port mapped to the coordinator NodePort |
327+
| `E2E_GATEWAY_PORT` | `30080` | Host port mapped to the gateway NodePort |
328+
| `E2E_PRINT_COORDINATOR_LOGS` | `false` | Print coordinator pod logs during the run |
329+
| `CONTAINER_RUNTIME` | `docker` | Container runtime used to load images into Kind (`docker` or `podman`) |
330+
| `EPP_IMAGE` | `ghcr.io/llm-d/llm-d-router-endpoint-picker:dev` | EPP image loaded into the Kind cluster |
331+
| `VLLM_IMAGE` | `ghcr.io/llm-d/llm-d-inference-sim:v0.10.0` | vLLM image loaded into the Kind cluster |
332+
| `VLLM_RENDER_IMAGE` | same as `VLLM_IMAGE` | vLLM render image loaded into the Kind cluster |
333+
| `VLLM_RENDER_PORT` | `8082` | Port the vllm-render service listens on |
334+
| `COORDINATOR_IMAGE` | _(empty)_ | Coordinator image loaded into the Kind cluster |
335+
| `MODEL_NAME` | `Qwen/Qwen3-VL-2B-Instruct` | Model name used by the test pools |
336+
| `NAMESPACE` | `default` | Namespace to deploy test resources into |
337+
| `K8S_CONTEXT` | _(empty)_ | Use an existing cluster context instead of creating a Kind cluster |
338+
| `READY_TIMEOUT` | `10m` | How long to wait for resources to become ready |

deploy/components/vllm-encode/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44
# Encoder deployment for multimodal disaggregation scenarios (E/PD, E/P/D).
55
# Includes a PVC for shared encoder embeddings cache.
6+
# Also referenced by deploy/coordinator/environments/dev/epd-pools/kustomization.yaml.
67
# ------------------------------------------------------------------------------
78
apiVersion: kustomize.config.k8s.io/v1beta1
89
kind: Kustomization

deploy/components/vllm-prefill/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# VLLM Prefill Component
33
#
44
# Prefill deployment for disaggregation scenarios (P/D, E/P/D).
5+
# Also referenced by deploy/coordinator/environments/dev/epd-pools/kustomization.yaml.
56
# ------------------------------------------------------------------------------
67
apiVersion: kustomize.config.k8s.io/v1beta1
78
kind: Kustomization

0 commit comments

Comments
 (0)