This Helm chart deploys the Batch Gateway on a Kubernetes cluster, which includes:
- API Server: REST API server for file and batch management
- Processor: Background processor for batch job execution
- Garbage Collector: Periodic cleanup of expired jobs and files
- Kubernetes 1.19+
- Helm 3.0+
The API server provides a REST API for managing files and batch jobs.
The processor is a background worker component that polls for and processes batch jobs.
For TLS to HTTPS inference backends (custom CA, mTLS, mounting certificate Secrets), see the Processor inference TLS guide.
The garbage collector periodically cleans up expired jobs and files.
The chart is published to GitHub Container Registry for each release. Use --version with the chart semver (same as Chart.yaml version: the git tag without v, e.g. v1.0.0 → 1.0.0):
helm install batch-gateway oci://ghcr.io/llm-d/charts/batch-gateway --version 1.0.0Replace 1.0.0 with the version you need. Image tags in the published chart are pinned to the release version.
To install the chart with the release name my-release:
helm install my-release ./charts/batch-gatewayThis will deploy the API server, processor, and garbage collector by default.
To uninstall/delete the my-release deployment:
helm uninstall my-releaseTo upgrade an existing release with new values:
# Upgrade with a values file
helm upgrade my-release ./charts/batch-gateway -f my-values.yaml
# Or use --set
helm upgrade my-release ./charts/batch-gateway \
--set apiserver.replicaCount=5
# View what would change before upgrading
helm upgrade my-release ./charts/batch-gateway \
-f my-values.yaml \
--dry-run --debugFor a complete list of parameters, see values.yaml.
cat > my-values.yaml <<EOF
apiserver:
replicaCount: 3
resources:
requests:
memory: 256Mi
cpu: 200m
EOF
helm install batch-gateway ./charts/batch-gateway -f my-values.yamlhelm install batch-gateway ./charts/batch-gateway \
--set apiserver.replicaCount=3 \
--set apiserver.resources.requests.memory=256MiOpenShift uses Security Context Constraints (SCC) that assign UIDs dynamically. Override the podSecurityContext to use SCC-assigned UIDs:
cat > openshift-values.yaml <<EOF
apiserver:
podSecurityContext: {} # Let OpenShift SCC assign UIDs
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
processor:
podSecurityContext: {} # Let OpenShift SCC assign UIDs
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
gc:
podSecurityContext: {} # Let OpenShift SCC assign UIDs
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
EOF
helm install batch-gateway ./charts/batch-gateway -f openshift-values.yamlThe chart will work with OpenShift's restricted SCC by default when podSecurityContext is empty.
For ClusterIP service type (default):
export POD_NAME=$(kubectl get pods -l "app.kubernetes.io/component=apiserver" -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 8080:8000 8081:8081
curl http://localhost:8080/v1/batches # API port
curl http://localhost:8081/health # health check portThe processor is a background worker and does not expose a service. To view logs:
kubectl logs -l "app.kubernetes.io/component=processor" -fThe chart creates a ClusterIP Service by default. To expose it externally, create your own Ingress or HTTPRoute.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: batch-gateway-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: <release-name>-batch-gateway-apiserver
port:
number: 8000
tls:
- hosts:
- api.example.com
secretName: batch-gateway-tlsapiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: batch-gateway-route
spec:
parentRefs:
- name: my-gateway
namespace: gateway-system
hostnames:
- api.example.com
rules:
- backendRefs:
- name: <release-name>-batch-gateway-apiserver
port: 8000- Liveness Probe:
GET /healthon port 8081 - Readiness Probe:
GET /readyon port 8081
- Liveness Probe:
GET /healthon port 9090 - Readiness Probe:
GET /readyon port 9090
Enable ServiceMonitor/PodMonitor for automatic Prometheus scraping:
apiserver:
serviceMonitor:
enabled: true
processor:
podMonitor:
enabled: trueRequires the Prometheus Operator (included in OpenShift Monitoring).
Enable built-in alert rules:
prometheusRule:
enabled: trueThe chart includes pre-built dashboards in charts/batch-gateway/dashboards/:
- apiserver.json — request rate, error rate, latency, in-flight requests
- processor.json — job throughput, queue wait, worker utilization, per-model metrics
Option 1: Grafana sidecar (Kubernetes/OpenShift)
Enable the dashboard ConfigMap and configure Grafana's sidecar to auto-load it:
grafana:
dashboards:
enabled: trueThe ConfigMap is labeled grafana_dashboard: "1" for sidecar discovery.
Option 2: Manual import (any Grafana instance)
- Copy the JSON file from
charts/batch-gateway/dashboards/ - In Grafana UI: Dashboards → Import → paste JSON
- Select your Prometheus datasource
Option 3: OpenShift with Grafana Operator
If the Grafana Operator is installed, create a GrafanaDashboard CR referencing the JSON. This is not automated by the chart yet — see #176 for updates.
The chart follows security best practices:
- Runs as non-root user (UID 65532 from Dockerfile by default)
- Uses read-only root filesystem
- Drops all Linux capabilities
- Prevents privilege escalation
- Uses seccomp RuntimeDefault profile
The chart is compatible with OpenShift's Security Context Constraints (SCC):
- Set
podSecurityContext: {}to allow OpenShift to assign UIDs from the namespace range - The minimal
securityContext(drop all capabilities, no privilege escalation, read-only filesystem) works with therestrictedSCC - No additional SCC configuration is required
Copyright 2026 The llm-d Authors
Licensed under the Apache License, Version 2.0.