Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/workflows/ci-pr-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
run: go mod download

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v8
uses: golangci/golangci-lint-action@v9
with:
version: v2.8.0
args: ""
Expand Down
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ KIND_CLUSTER_NAME ?= ipp-e2e

# Tools
GOLANGCI_LINT_VERSION ?= v2.8.0
KUSTOMIZE ?= $(LOCALBIN)/kustomize
KUSTOMIZE_VERSION ?= v5.4.3
KUSTOMIZE_OVERLAY ?= default

.DEFAULT_GOAL := help

Expand Down Expand Up @@ -128,6 +131,25 @@ $(YQ): | $(LOCALBIN)
helm-push: yq helm-install ## Package and push the payload-processor Helm chart.
CHART=$(CHART) EXTRA_TAG="$(EXTRA_TAG)" IMAGE_REPOSITORY="$(IMAGE_REPOSITORY)" YQ="$(YQ)" HELM="$(HELM)" ./hack/push-chart.sh

##@ Deployment

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

.PHONY: kustomize-build
kustomize-build: kustomize ## Render Kustomize manifests (KUSTOMIZE_OVERLAY=default|istio|gke)
$(KUSTOMIZE) build config/kustomize/overlays/$(KUSTOMIZE_OVERLAY)

.PHONY: kustomize-deploy
kustomize-deploy: kustomize ## Deploy using Kustomize (KUSTOMIZE_OVERLAY=default|istio|gke)
$(KUSTOMIZE) build config/kustomize/overlays/$(KUSTOMIZE_OVERLAY) | kubectl apply -f -

.PHONY: kustomize-undeploy
kustomize-undeploy: kustomize ## Remove Kustomize deployment (KUSTOMIZE_OVERLAY=default|istio|gke)
$(KUSTOMIZE) build config/kustomize/overlays/$(KUSTOMIZE_OVERLAY) | kubectl delete --ignore-not-found -f -

##@ CI Helpers

.PHONY: ci-lint
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,35 @@ Helm chart provisions the provider-specific integration automatically:
- **GKE** — Installs a `GCPRoutingExtension` that registers IPP as a routing extension.
- **None** — Deploys the core IPP resources (Deployment, Service, config, RBAC) but no proxy integration; you wire that up yourself.

## Deployment

The payload processor can be deployed using either **Helm** or **Kustomize**.

### Helm

```bash
helm install payload-processor ./config/charts/payload-processor \
--set provider.name=[gke|istio] \
--set inferenceGateway.name=inference-gateway
```

See [config/charts/payload-processor/README.md](config/charts/payload-processor/README.md) for the full parameter reference.

### Kustomize

```bash
# No provider (Deployment + Service only)
kubectl kustomize config/kustomize/overlays/default | kubectl apply -f -

# Istio (adds EnvoyFilter + DestinationRule)
kubectl kustomize config/kustomize/overlays/istio | kubectl apply -f -

# GKE (adds GCPRoutingExtension + HealthCheckPolicy)
kubectl kustomize config/kustomize/overlays/gke | kubectl apply -f -
```

See [config/kustomize/README.md](config/kustomize/README.md) for customization options (namespace, image tag, custom config, multi-namespace RBAC).

## Documentation

| Document | Description |
Expand All @@ -50,6 +79,7 @@ Helm chart provisions the provider-specific integration automatically:
| [Creating a Plugin](docs/create_new_plugin.md) | Tutorial for writing and registering a custom plugin. |
| [Metrics](docs/metrics.md) | Prometheus metrics exposed by IPP. |
| [Helm Chart](config/charts/payload-processor/README.md) | Chart install reference and values table. |
| [Kustomize](config/kustomize/README.md) | Kustomize overlay reference and customization options. |
| [ModelSelector Proposal](docs/proposals/043-model-selection-framework/README.md) | Design of the model-selection framework. |

For end-to-end deployment, see the [llm-d] project documentation and guides.
Expand Down
189 changes: 189 additions & 0 deletions config/kustomize/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Kustomize Deployment

This directory provides [Kustomize](https://kustomize.io/) manifests for deploying the
Inference Payload Processor (IPP). It mirrors the same resources as the Helm chart at
`config/charts/payload-processor/` and is the recommended path for integrations such as
[llm-d-benchmark](https://github.com/llm-d/llm-d-benchmark) and GitOps workflows.

## Structure

```
config/kustomize/
├── base/ # Core resources (provider-agnostic)
│ ├── kustomization.yaml
│ ├── deployment.yaml # Deployment
│ ├── service.yaml # ClusterIP Service on port 9004 (HTTP2)
│ ├── serviceaccount.yaml # ServiceAccount
│ ├── rbac.yaml # Role + RoleBinding (single-namespace)
│ └── configmap.yaml # Default PayloadProcessorConfig
└── overlays/
├── default/ # No provider — Deployment + Service only
├── istio/ # Adds EnvoyFilter + DestinationRule
└── gke/ # Adds GCPRoutingExtension + HealthCheckPolicy
```

## Quick Start

### Prerequisites

- `kubectl` ≥ 1.24
- `kustomize` ≥ 5.0 (or the `kustomize` embedded in `kubectl`)
- A running Kubernetes cluster with an Inference Gateway deployed

### Deploy (no provider)

```bash
# Render to stdout
kubectl kustomize config/kustomize/overlays/default

# Apply directly
kubectl kustomize config/kustomize/overlays/default | kubectl apply -f -

# Or via make
make kustomize-deploy
```

### Deploy with Istio

```bash
kubectl kustomize config/kustomize/overlays/istio | kubectl apply -f -

# Or via make
make kustomize-deploy KUSTOMIZE_OVERLAY=istio
```

### Deploy with GKE

```bash
kubectl kustomize config/kustomize/overlays/gke | kubectl apply -f -

# Or via make
make kustomize-deploy KUSTOMIZE_OVERLAY=gke
```

### Undeploy

```bash
make kustomize-undeploy # default overlay
make kustomize-undeploy KUSTOMIZE_OVERLAY=istio
make kustomize-undeploy KUSTOMIZE_OVERLAY=gke
```

## Customization

### Change the target namespace

Edit the `namespace:` field in the overlay's `kustomization.yaml`:

```yaml
# config/kustomize/overlays/default/kustomization.yaml
namespace: my-namespace # ← change this
```

Or patch it inline from the command line:

```bash
cd config/kustomize/overlays/default
kustomize edit set namespace my-namespace
```

> **Istio users:** The `cluster_name` in `overlays/istio/envoyfilter.yaml` and the `host` in
> `overlays/istio/destinationrule.yaml` embed the namespace as part of the FQDN
> (`payload-processor.<namespace>.svc.cluster.local`). This is handled automatically — the
> `replacements` block in `overlays/istio/kustomization.yaml` injects the overlay's
> `namespace:` value into both fields at build time, so there is nothing to edit manually and
> no risk of drift between them.

### Change the container image

Add an `images` override in your overlay's `kustomization.yaml`:

```yaml
images:
- name: ghcr.io/llm-d/llm-d-inference-payload-processor
newTag: v0.3.0
```

### Change the Gateway name

Patch the `targetRefs[0].name` field in `envoyfilter.yaml` (Istio) or
`gcproutingextension.yaml` (GKE) using a strategic merge patch:

```yaml
# overlays/istio/gateway-patch.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: payload-processor
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: my-custom-gateway # ← your Gateway name
```

```yaml
# overlays/istio/kustomization.yaml (add to existing file)
patches:
- path: gateway-patch.yaml
```

### Use a custom IPP config

Add a `configMapGenerator` entry in your overlay's `kustomization.yaml` to merge your own
`PayloadProcessorConfig`:

```yaml
configMapGenerator:
- name: payload-processor
behavior: merge
files:
- custom-ipp-config.yaml=path/to/your/config.yaml
```

Then update the `--config-file` arg in a Deployment patch to point to
`/config/custom-ipp-config.yaml`.

### Multi-namespace RBAC

The base uses a namespace-scoped `Role`/`RoleBinding`. To watch ConfigMaps across
namespaces, create an overlay that replaces them with a `ClusterRole`/`ClusterRoleBinding`:

```yaml
# overlays/multi-namespace/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: my-namespace

resources:
- ../../base
- clusterrole.yaml
- clusterrolebinding.yaml

patches:
- target:
kind: Role
patch: |-
$patch: delete
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payload-processor-configmap-reader
- target:
kind: RoleBinding
patch: |-
$patch: delete
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payload-processor-configmap-reader
```

## Notes

- This chart should only be deployed once per Gateway (same constraint as the Helm chart).
- The `base/` layer intentionally omits `metadata.namespace` so that the overlay's
`namespace:` field is the single source of truth.
- For production use, pin the image tag and consider setting resource requests/limits via
a Deployment patch.
20 changes: 20 additions & 0 deletions config/kustomize/base/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: payload-processor
data:
default-ipp-config.yaml: |
apiVersion: llm-d.ai/v1alpha1
kind: PayloadProcessorConfig
plugins:
- type: body-field-to-header
parameters:
fieldName: model
headerName: X-Gateway-Model-Name
- type: base-model-to-header
profiles:
- name: default
plugins:
request:
- pluginRef: body-field-to-header
- pluginRef: base-model-to-header
62 changes: 62 additions & 0 deletions config/kustomize/base/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: payload-processor
spec:
replicas: 1
selector:
matchLabels:
app: payload-processor
template:
metadata:
labels:
app: payload-processor
spec:
serviceAccountName: payload-processor
containers:
- name: payload-processor
image: ghcr.io/llm-d/llm-d-inference-payload-processor:main
imagePullPolicy: IfNotPresent
args:
- --config-file
- /config/default-ipp-config.yaml
- --v=3
- --tracing=false
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: grpc
containerPort: 9004
- name: grpc-health
containerPort: 9005
# Conservative starting point for a request/response processing
# sidecar; tune based on observed load (payload size, RPS) before
# running in production.
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 512Mi
# Port 9005 serves the standard gRPC health protocol
# (grpc.health.v1), see cmd/runner/health.go.
readinessProbe:
grpc:
port: 9005
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
grpc:
port: 9005
initialDelaySeconds: 15
periodSeconds: 20
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
configMap:
name: payload-processor
9 changes: 9 additions & 0 deletions config/kustomize/base/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- configmap.yaml
- serviceaccount.yaml
- rbac.yaml
- deployment.yaml
- service.yaml
20 changes: 20 additions & 0 deletions config/kustomize/base/rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payload-processor-configmap-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payload-processor-configmap-reader
subjects:
- kind: ServiceAccount
name: payload-processor
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: payload-processor-configmap-reader
Loading