Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,18 @@ curl -s -w '\n' http://localhost:8080/v1/completions -H 'Content-Type: applicati

#### Environment Configurateion

**1. Setting the EPP image and tag:**
**1. Setting the EPP image registry and tag:**

You can optionally set a custom EPP image (otherwise, the default will be used):
You can optionally set a custom image registry and tag (otherwise, defaults will be used):

```bash
export IMAGE_REGISTRY="<YOUR_REGISTRY>"
export EPP_TAG="<YOUR_TAG>"
export EPP_IMAGE="<YOUR_REGISTRY>/<YOUR_IMAGE>"
```

> [!NOTE]
> The full image reference will be constructed as `${EPP_IMAGE}`, where `EPP_IMAGE` defaults to `${IMAGE_REGISTRY}/llm-d-inference-scheduler:{EPP_TAG}`. For example, with `IMAGE_REGISTRY=quay.io/<my-id>` and `EPP_TAG=v1.0.0`, the final image will be `quay.io/<my-id>/llm-d-inference-scheduler:v1.0.0`.

**2. Setting the vLLM replicas:**

You can optionally set the vllm replicas:
Expand Down
486 changes: 100 additions & 386 deletions Makefile

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions Makefile.cluster.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
##@ Cluster Development Environments

.PHONY: env-dev-kubernetes
env-dev-kubernetes: check-kubectl check-kustomize check-envsubst ## Deploy full dev environment (vLLM + Gateway + EPP) to K8s/OpenShift cluster
IMAGE_REGISTRY=$(IMAGE_REGISTRY) ./scripts/kubernetes-dev-env.sh 2>&1

# Kubernetes Development Environment - Teardown
.PHONY: clean-env-dev-kubernetes
clean-env-dev-kubernetes: check-kubectl check-kustomize check-envsubst ## Clean up full dev environment from K8s/OpenShift cluster
@CLEAN=true ./scripts/kubernetes-dev-env.sh 2>&1
@echo "INFO: Finished cleanup of development environment for namespace $(NAMESPACE)"


##@ RBAC Targets

.PHONY: install-rbac
install-rbac: check-kubectl check-kustomize check-envsubst ## Apply RBAC configuration to cluster
@echo "Applying RBAC configuration from deploy/rbac..."
$(KUSTOMIZE) build deploy/environments/kubernetes-base/rbac | envsubst '$$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION' | kubectl apply -f -

.PHONY: uninstall-rbac
uninstall-rbac: check-kubectl check-kustomize check-envsubst ## Remove RBAC configuration from cluster
@echo "Removing RBAC configuration from deploy/rbac..."
$(KUSTOMIZE) build deploy/environments/kubernetes-base/rbac | envsubst '$$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION' | kubectl delete -f - || true

##@ Kubernetes Targets

.PHONY: install-k8s
install-k8s: check-kubectl check-kustomize check-envsubst ## Deploy resources to Kubernetes
@echo "Creating namespace (if needed) and setting context to $(NAMESPACE)..."
kubectl create namespace $(NAMESPACE) 2>/dev/null || true
kubectl config set-context --current --namespace=$(NAMESPACE)
@echo "Deploying resources from deploy/ ..."
# Build the kustomization from deploy, substitute variables, and apply the YAML
$(KUSTOMIZE) build deploy/environments/kubernetes-base | envsubst | kubectl apply -f -
@echo "Waiting for pod to become ready..."
sleep 5
@POD=$$(kubectl get pod -l app=$(PROJECT_NAME)-statefulset -o jsonpath='{.items[0].metadata.name}'); \
echo "Kubernetes installation complete."; \
echo "To use the app, run:"; \
echo "alias $(PROJECT_NAME)='kubectl exec -n $(NAMESPACE) -it $$POD -- /app/$(PROJECT_NAME)'"

.PHONY: uninstall-k8s
uninstall-k8s: check-kubectl check-kustomize check-envsubst ## Remove resources from Kubernetes
@echo "Removing resources from Kubernetes..."
$(KUSTOMIZE) build deploy/environments/kubernetes-base | envsubst | kubectl delete --force -f - || true
POD=$$(kubectl get pod -l app=$(PROJECT_NAME)-statefulset -o jsonpath='{.items[0].metadata.name}'); \
echo "Deleting pod: $$POD"; \
kubectl delete pod "$$POD" --force --grace-period=0 || true; \
echo "Kubernetes uninstallation complete. Remove alias if set: unalias $(PROJECT_NAME)"

##@ OpenShift Targets

.PHONY: install-openshift
install-openshift: check-kubectl check-kustomize check-envsubst ## Deploy resources to OpenShift
@echo $$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION
@echo "Creating namespace $(NAMESPACE)..."
kubectl create namespace $(NAMESPACE) 2>/dev/null || true
@echo "Deploying common resources from deploy/ ..."
# Build and substitute the base manifests from deploy, then apply them
$(KUSTOMIZE) build deploy/environments/kubernetes-base | envsubst '$$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION' | kubectl apply -n $(NAMESPACE) -f -
@echo "Waiting for pod to become ready..."
sleep 5
@POD=$$(kubectl get pod -l app=$(PROJECT_NAME)-statefulset -n $(NAMESPACE) -o jsonpath='{.items[0].metadata.name}'); \
echo "OpenShift installation complete."; \
echo "To use the app, run:"; \
echo "alias $(PROJECT_NAME)='kubectl exec -n $(NAMESPACE) -it $$POD -- /app/$(PROJECT_NAME)'"

.PHONY: uninstall-openshift
uninstall-openshift: check-kubectl check-kustomize check-envsubst ## Remove resources from OpenShift
@echo "Removing resources from OpenShift..."
$(KUSTOMIZE) build deploy/environments/kubernetes-base | envsubst '$$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION' | kubectl delete --force -f - || true
# @if kubectl api-resources --api-group=route.openshift.io | grep -q Route; then \
# envsubst '$$PROJECT_NAME $$NAMESPACE $$IMAGE_TAG_BASE $$VERSION' < deploy/openshift/route.yaml | kubectl delete --force -f - || true; \
# fi
@POD=$$(kubectl get pod -l app=$(PROJECT_NAME)-statefulset -n $(NAMESPACE) -o jsonpath='{.items[0].metadata.name}'); \
echo "Deleting pod: $$POD"; \
kubectl delete pod "$$POD" --force --grace-period=0 || true; \
echo "OpenShift uninstallation complete. Remove alias if set: unalias $(PROJECT_NAME)"
35 changes: 35 additions & 0 deletions Makefile.kind.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
##@ Kind Development Environments

KIND_CLUSTER_NAME ?= llm-d-inference-scheduler-dev
KIND_GATEWAY_HOST_PORT ?= 30080

.PHONY: env-dev-kind
env-dev-kind: image-build ## Run under kind ($(KIND_CLUSTER_NAME))
@if [ "$$PD_ENABLED" = "true" ] && [ "$$KV_CACHE_ENABLED" = "true" ]; then \
echo "Error: Both PD_ENABLED and KV_CACHE_ENABLED are true. Skipping env-dev-kind."; \
exit 1; \
else \
CLUSTER_NAME=$(KIND_CLUSTER_NAME) \
GATEWAY_HOST_PORT=$(KIND_GATEWAY_HOST_PORT) \
IMAGE_REGISTRY=$(IMAGE_REGISTRY) \
EPP_IMAGE=$(EPP_IMAGE) \
VLLM_SIMULATOR_IMAGE=${VLLM_SIMULATOR_IMAGE} \
SIDECAR_IMAGE=$(SIDECAR_IMAGE) \
./scripts/kind-dev-env.sh; \
fi

.PHONY: clean-env-dev-kind
clean-env-dev-kind: ## Cleanup kind setup (delete cluster $(KIND_CLUSTER_NAME))
@echo "INFO: cleaning up kind cluster $(KIND_CLUSTER_NAME)"
kind delete cluster --name $(KIND_CLUSTER_NAME)

##@ Alias checking
.PHONY: check-alias
check-alias: check-container-tool ## Check if the container alias works correctly
@echo "Checking alias functionality for container '$(PROJECT_NAME)-container'..."
@if ! $(CONTAINER_RUNTIME) exec $(PROJECT_NAME)-container /app/$(PROJECT_NAME) --help >/dev/null 2>&1; then \
echo "WARNING: The container '$(PROJECT_NAME)-container' is running, but the alias might not work."; \
echo "Try: $(CONTAINER_RUNTIME) exec -it $(PROJECT_NAME)-container /app/$(PROJECT_NAME)"; \
else \
echo "Alias is likely to work: alias $(PROJECT_NAME)='$(CONTAINER_RUNTIME) exec -it $(PROJECT_NAME)-container /app/$(PROJECT_NAME)'"; \
fi
245 changes: 241 additions & 4 deletions Makefile.tools.mk
Original file line number Diff line number Diff line change
@@ -1,16 +1,253 @@
LOCALBIN ?= $(shell pwd)/bin
## Local directories are defined in main Makefile
$(LOCALBIN):
[ -d $@ ] || mkdir -p $@

$(LOCALLIB):
[ -d $@ ] || mkdir -p $@

## Tool binary names.
GINKGO = $(LOCALBIN)/ginkgo
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
KUSTOMIZE = $(LOCALBIN)/kustomize
TYPOS = $(LOCALBIN)/typos
## Dependencies
TOKENIZER_LIB = $(LOCALLIB)/libtokenizers.a

## Tool versions.
## Tool fixed versions.
GINKGO_VERSION ?= v2.27.2
GOLANGCI_LINT_VERSION ?= v2.1.6
KUSTOMIZE_VERSION ?= v5.5.0
TYPOS_VERSION ?= v1.34.0

.PHONY: typos
typos: $(TYPOS)
## Python Configuration
PYTHON_VERSION ?= 3.12
# Extract RELEASE_VERSION from Dockerfile
TOKENIZER_VERSION := $(shell grep '^ARG RELEASE_VERSION=' Dockerfile.epp | cut -d'=' -f2)

# Python executable for creating venv
PYTHON_EXE := $(shell command -v python$(PYTHON_VERSION) || command -v python3)
VENV_DIR := $(shell pwd)/build/venv
VENV_BIN := $(VENV_DIR)/bin

## go-install-tool will 'go install' any package with custom target and version.
define go-install-tool
@[ -f "$(1)-$(3)" ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
rm -f $(1) || true ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv $(1) $(1)-$(3) ;\
} ;\
ln -sf $(notdir $(1))-$(3) $(1)
endef


##@ Tools

.PHONY: install-tools
install-tools: install-ginkgo install-golangci-lint install-kustomize install-typos install-dependencies download-tokenizer ## Install all development tools and dependencies
@echo "All development tools and dependencies are installed."

.PHONY: install-ginkgo
install-ginkgo: $(GINKGO)
$(GINKGO): | $(LOCALBIN)
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo,$(GINKGO_VERSION))

.PHONY: install-golangci-lint
install-golangci-lint: $(GOLANGCI_LINT)
$(GOLANGCI_LINT): | $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

.PHONY: install-kustomize
install-kustomize: $(KUSTOMIZE)
$(KUSTOMIZE): | $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))

.PHONY: install-typos
install-typos: $(TYPOS)
$(TYPOS): | $(LOCALBIN)
@echo "Downloading typos $(TYPOS_VERSION)..."
curl -L https://github.com/crate-ci/typos/releases/download/$(TYPOS_VERSION)/typos-$(TYPOS_VERSION)-$(TYPOS_ARCH).tar.gz | tar -xz -C $(LOCALBIN) $(TAR_OPTS)
chmod +x $(TYPOS)
@echo "typos installed successfully."

##@ Dependencies

.PHONY: check-dependencies
check-dependencies: ## Check if development dependencies are installed
@if [ "$(TARGETOS)" = "linux" ]; then \
if [ -x "$$(command -v apt)" ]; then \
if ! dpkg -s libzmq3-dev >/dev/null 2>&1 || ! dpkg -s g++ >/dev/null 2>&1 || ! dpkg -s python$(PYTHON_VERSION)-dev >/dev/null 2>&1; then \
echo "ERROR: Missing dependencies. Please run 'sudo make install-dependencies'"; \
exit 1; \
fi; \
elif [ -x "$$(command -v dnf)" ]; then \
if ! rpm -q zeromq-devel >/dev/null 2>&1 || ! rpm -q gcc-c++ >/dev/null 2>&1 || ! rpm -q python$(PYTHON_VERSION)-devel >/dev/null 2>&1; then \
echo "ERROR: Missing dependencies. Please run 'sudo make install-dependencies'"; \
exit 1; \
fi; \
else \
echo "WARNING: Unsupported Linux package manager. Cannot verify dependencies."; \
fi; \
elif [ "$(TARGETOS)" = "darwin" ]; then \
if [ -x "$$(command -v brew)" ]; then \
if ! brew list zeromq pkg-config >/dev/null 2>&1; then \
echo "ERROR: Missing dependencies. Please run 'make install-dependencies'"; \
exit 1; \
fi; \
else \
echo "ERROR: Homebrew is not installed and is required. Install it from https://brew.sh/"; \
exit 1; \
fi; \
fi
@echo "✅ All dependencies are installed."

.PHONY: install-dependencies
install-dependencies: ## Install development dependencies based on OS/ARCH
@echo "Checking and installing development dependencies..."
@if [ "$(TARGETOS)" = "linux" ]; then \
if [ -x "$$(command -v apt)" ]; then \
if ! dpkg -s libzmq3-dev >/dev/null 2>&1 || ! dpkg -s g++ >/dev/null 2>&1 || ! dpkg -s python$(PYTHON_VERSION)-dev >/dev/null 2>&1; then \
echo "Installing dependencies with apt..."; \
apt-get update && apt-get install -y libzmq3-dev g++ python$(PYTHON_VERSION)-dev; \
else \
echo "✅ ZMQ, g++, and Python dev headers are already installed."; \
fi; \
elif [ -x "$$(command -v dnf)" ]; then \
if ! rpm -q zeromq-devel >/dev/null 2>&1 || ! rpm -q gcc-c++ >/dev/null 2>&1 || ! rpm -q python$(PYTHON_VERSION)-devel >/dev/null 2>&1; then \
echo "Installing dependencies with dnf..."; \
dnf install -y zeromq-devel gcc-c++ python$(PYTHON_VERSION)-devel; \
else \
echo "✅ ZMQ, gcc-c++, and Python dev headers are already installed."; \
fi; \
else \
echo "ERROR: Unsupported Linux package manager. Install libzmq, g++/gcc-c++, and python-devel manually."; \
exit 1; \
fi; \
elif [ "$(TARGETOS)" = "darwin" ]; then \
if [ -x "$$(command -v brew)" ]; then \
if ! brew list zeromq pkg-config >/dev/null 2>&1; then \
echo "Installing dependencies with brew..."; \
brew install zeromq pkg-config; \
else \
echo "✅ ZeroMQ and pkgconf are already installed."; \
fi; \
else \
echo "ERROR: Homebrew is not installed and is required to install zeromq. Install it from https://brew.sh/"; \
exit 1; \
fi; \
else \
echo "ERROR: Unsupported OS: $(TARGETOS). Install development dependencies manually."; \
exit 1; \
fi

.PHONY: download-tokenizer
download-tokenizer: $(TOKENIZER_LIB)
$(TOKENIZER_LIB): | $(LOCALLIB)
## Download the HuggingFace tokenizer bindings.
@echo "Downloading HuggingFace tokenizer bindings for version $(TOKENIZER_VERSION)..."
@curl -L https://github.com/daulet/tokenizers/releases/download/$(TOKENIZER_VERSION)/libtokenizers.$(TARGETOS)-$(TOKENIZER_ARCH).tar.gz | tar -xz -C $(LOCALLIB)
@ranlib $(LOCALLIB)/*.a
@echo "Tokenizer bindings downloaded successfully."


.PHONY: install-python-deps
install-python-deps: ## Sets up Python virtual environment and installs dependencies
@printf "\033[33;1m==== Setting up Python virtual environment in $(VENV_DIR) ====\033[0m\n"
@if [ -z "$(PYTHON_EXE)" ]; then \
echo "ERROR: Python 3 not found in PATH."; \
exit 1; \
fi
@if [ ! -f "$(VENV_BIN)/pip" ]; then \
echo "Creating virtual environment..."; \
$(PYTHON_EXE) -m venv $(VENV_DIR) || { \
echo "ERROR: Failed to create virtual environment."; \
echo "Your Python installation may be missing the 'venv' module."; \
exit 1; \
}; \
fi
@echo "Upgrading pip and installing dependencies..."
@$(VENV_BIN)/pip install --upgrade pip --quiet
@KV_CACHE_PKG=$$(go list -m -f '{{.Dir}}' github.com/llm-d/llm-d-kv-cache-manager 2>/dev/null); \
if [ -n "$$KV_CACHE_PKG" ] && [ -f "$$KV_CACHE_PKG/pkg/preprocessing/chat_completions/requirements.txt" ]; then \
echo "Installing Python dependencies from kv-cache-manager..."; \
$(VENV_BIN)/pip install --quiet -r "$$KV_CACHE_PKG/pkg/preprocessing/chat_completions/requirements.txt"; \
else \
echo "WARNING: Could not find kv-cache-manager requirements.txt, installing minimal deps..."; \
$(VENV_BIN)/pip install --quiet 'transformers>=4.53.0' 'jinja2>=2.11'; \
fi
@echo "✅ Python dependencies installed in venv"

.PHONY: check-tools
check-tools: check-go check-ginkgo check-golangci-lint check-kustomize check-envsubst check-container-tool check-kubectl check-buildah check-typos ## Check that all required tools are installed
@echo "All required tools are available."

.PHONY: check-go
check-go:
@command -v go >/dev/null 2>&1 || { \
echo "ERROR: Go is not installed. Install it from https://golang.org/dl/"; exit 1; }

.PHONY: check-ginkgo
check-ginkgo:
@command -v ginkgo >/dev/null 2>&1 || [ -f "$(GINKGO)" ] || { \
echo "ERROR: ginkgo is not installed."; \
echo "Run: make install-ginkgo (or install-tools)"; \
exit 1; }

.PHONY: check-golangci-lint
check-golangci-lint:
@command -v golangci-lint >/dev/null 2>&1 || [ -f "$(GOLANGCI_LINT)" ] || { \
echo "ERROR: golangci-lint is not installed."; \
echo "Run: make install-golangci-lint (or install-tools)"; \
exit 1; }

.PHONY: check-kustomize
check-kustomize:
@command -v kustomize >/dev/null 2>&1 || [ -f "$(KUSTOMIZE)" ] || { \
echo "ERROR: kustomize is not installed."; \
echo "Run: make install-kustomize (or install-tools)"; \
exit 1; }

.PHONY: check-envsubst
check-envsubst:
@command -v envsubst >/dev/null 2>&1 || { \
echo "ERROR: envsubst is not installed. It is part of gettext."; \
echo "Try: sudo apt install gettext OR brew install gettext"; exit 1; }

.PHONY: check-container-tool
check-container-tool:
@if [ -z "$(CONTAINER_RUNTIME)" ]; then \
echo "ERROR: Error: No container tool detected. Please install docker or podman."; \
exit 1; \
else \
echo "Container tool '$(CONTAINER_RUNTIME)' found."; \
fi

.PHONY: check-kubectl
check-kubectl:
@command -v kubectl >/dev/null 2>&1 || { \
echo "ERROR: kubectl is not installed. Install it from https://kubernetes.io/docs/tasks/tools/"; exit 1; }

.PHONY: check-builder
check-builder:
@if [ -z "$(BUILDER)" ]; then \
echo "ERROR: No container builder tool (buildah, docker, or podman) found."; \
exit 1; \
else \
echo "Using builder: $(BUILDER)"; \
fi

.PHONY: check-buildah
check-buildah:
@command -v buildah >/dev/null 2>&1 || { \
echo "WARNING: buildah is not installed (optional - docker/podman can be used instead)."; }

.PHONY: check-typos
check-typos:
@command -v typos >/dev/null 2>&1 || [ -f "$(TYPOS)" ] || { \
echo "ERROR: typos is not installed."; \
echo "Run: make install-typos (or install-tools)"; \
exit 1; }
@echo "Checking for spelling errors with typos..."
@$(TYPOS) --format brief
Loading