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
5 changes: 3 additions & 2 deletions .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ POD_NAME="dev-router-pod"

# Public URLs
BASEURL="dev.vendeuvre.lan"
BASE_URL="dev.vendeuvre.lan"
PUBLIC_BASE_URL="https://dev.vendeuvre.lan/llm-routing"
PUBLIC_BASE_URL="https://dev.vendeuvre.lan"
PROXY_BASE_URL="https://litellm.dev.vendeuvre.lan"
NEXTAUTH_URL="https://langfuse.dev.vendeuvre.lan"

# Dev port assignments (+10 offset from production)
ROUTER_PORT="5010"
Expand Down
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,20 @@ For secure production deployments, the gateway services are configured to run un
### 1. Launching the Stack
Run the startup script from the root of the repository:
```bash
./start-stack.sh # Fast restart (preserves container IDs and logs)
./start-stack.sh --replace # Recreate pod from YAML (picks up new ports,
# health probes, env vars, containers — no rebuild)
./start-stack.sh --full-rebuild # Full reset: rebuild image + recreate pod
./start-stack.sh # Restart the systemd-managed Quadlet stack
./start-stack.sh --replace # Render Quadlets, daemon-reload, and recreate the stack
# (picks up ports, probes, env vars, and containers)
./start-stack.sh --full-rebuild # Same as --replace plus rebuild the router image

# Inspect the generated systemd units and their logs
systemctl --user status llm-routing-pod.service --no-pager
systemctl --user list-units 'llm-routing-*' --no-pager
journalctl --user -u llm-routing-router.service -n 100 --no-pager
```
*Note: If running for the first time, the script will prompt you for your `OpenRouter API Key`, securely saving it inside `.env` with restrictive permissions (`chmod 600`). The script also automatically generates and persists secure random secrets (`LITELLM_MASTER_KEY`, `POSTGRES_PASSWORD`, `NEXTAUTH_SECRET`, `SALT`, `ENCRYPTION_KEY`, and `ROUTER_API_KEY`) to this file on startup if they are missing.*

### 2. Verify Container Status
Check that all **10 containers** inside `prod-router-pod` are up and running:
Check that all **9 application containers** in `prod-router-pod` are up and running (the tenth pod infra container is Podman-managed):
```bash
podman pod ps
podman ps --pod --filter pod=prod-router-pod
Expand Down Expand Up @@ -840,14 +845,15 @@ Tests cover:
| Section | Endpoints |
|---------|-----------|
| Router API | `/v1/models`, `/metrics`, `/dashboard`, `/api/dashboard-stats`, `/visualizer` |
| LiteLLM | `/health/liveness`, `/health/readiness`, `/v1/models`, `/llm-routing/litellm/ui/` |
| Langfuse | `/api/public/health`, `/` (web UI) |
| LiteLLM | Local `/health/liveness`, `/health/readiness`, `/v1/models`; canonical `https://litellm.<host>/ui/` |
| Langfuse | Local `/api/public/health`, `/`; canonical `https://langfuse.<host>/` |
| llama.cpp | Canonical `https://llama.<host>/health` |
| Infrastructure | MinIO `/minio/health/live`, ClickHouse `/ping` |
| E2E chat | 3 completions through triage router |
| LiteLLM direct | 1 completion directly to LiteLLM |
| Canonical URLs | 6 GET + 1 POST through public HTTPS (graceful DNS skip) |
| Canonical URLs | 7 GET + 1 POST through public HTTPS (graceful DNS skip) |

Requires `PUBLIC_BASE_URL` in `.env` for canonical URL tests. Dev `.env.dev` already has it; prod `.env` should include `PUBLIC_BASE_URL="https://x570.vendeuvre.lan/llm-routing"`.
Requires `PUBLIC_BASE_URL` in `.env` for canonical URL tests. The router remains under its configured path (for example `https://x570.vendeuvre.lan/llm-routing`), while the verifier derives service URLs from its host: `https://litellm.<host>/ui/`, `https://langfuse.<host>/`, and `https://llama.<host>/health`. Dev `.env.dev` already has it; prod `.env` should include `PUBLIC_BASE_URL="https://x570.vendeuvre.lan/llm-routing"`.

## 10. Performance Benchmarks

Expand Down
27 changes: 27 additions & 0 deletions quadlets/llm-routing-clickhouse.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[Unit]
Description=ClickHouse — Langfuse v3 OLAP trace store (POD_NAME_PLACEHOLDER)

[Container]
ContainerName=POD_NAME_PLACEHOLDER-clickhouse-db
Image=clickhouse/clickhouse-server:26.6.2.81
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
User=101
Group=101
Environment=CLICKHOUSE_DB=default
Environment=CLICKHOUSE_USER=clickhouse
Environment=CLICKHOUSE_PASSWORD=CLICKHOUSE_PASSWORD_PLACEHOLDER
Volume=DATA_ROOT_PLACEHOLDER/clickhouse-data:/var/lib/clickhouse
Volume=DATA_ROOT_PLACEHOLDER/clickhouse-config/port-override.xml:/etc/clickhouse-server/config.d/port-override.xml
HealthCmd=clickhouse-client --host 127.0.0.1 --port CLICKHOUSE_TCP_PORT_PLACEHOLDER --user clickhouse --password CLICKHOUSE_PASSWORD_PLACEHOLDER --query "SELECT 1"
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=20s

[Service]
Restart=always
TimeoutStartSec=120
51 changes: 51 additions & 0 deletions quadlets/llm-routing-langfuse-web.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[Unit]
Description=Langfuse Web — observability dashboard (POD_NAME_PLACEHOLDER)
After=llm-routing-postgres.service llm-routing-clickhouse.service llm-routing-valkey-lf.service llm-routing-minio.service
Wants=llm-routing-postgres.service llm-routing-clickhouse.service llm-routing-valkey-lf.service llm-routing-minio.service

[Container]
ContainerName=POD_NAME_PLACEHOLDER-langfuse-web
Image=langfuse/langfuse:3.222.0
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
Environment=DATABASE_URL=postgresql://postgres:POSTGRES_PASSWORD_ENCODED_PLACEHOLDER@127.0.0.1:POSTGRES_PORT_PLACEHOLDER/langfuse
Environment=NEXTAUTH_SECRET=NEXTAUTH_SECRET_PLACEHOLDER
Environment=NEXTAUTH_URL=NEXTAUTH_URL_PLACEHOLDER
Environment=SALT=SALT_PLACEHOLDER
Environment=ENCRYPTION_KEY=ENCRYPTION_KEY_PLACEHOLDER
Environment=HOSTNAME=0.0.0.0
Environment=PORT=LANGFUSE_WEB_PORT_PLACEHOLDER
Environment=TELEMETRY_ENABLED=false
Environment=LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse-events
Environment=LANGFUSE_S3_EVENT_UPLOAD_REGION=us-east-1
Environment=LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=MINIO_USER_PLACEHOLDER
Environment=LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=MINIO_PASSWORD_PLACEHOLDER
Environment=LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://127.0.0.1:MINIO_S3_PORT_PLACEHOLDER
Environment=S3_FORCE_PATH_STYLE=true
Environment=CLICKHOUSE_URL=http://127.0.0.1:CLICKHOUSE_HTTP_PORT_PLACEHOLDER
Environment=CLICKHOUSE_MIGRATION_URL=clickhouse://127.0.0.1:CLICKHOUSE_TCP_PORT_PLACEHOLDER
Environment=CLICKHOUSE_USER=clickhouse
Environment=CLICKHOUSE_PASSWORD=CLICKHOUSE_PASSWORD_PLACEHOLDER
Environment=CLICKHOUSE_CLUSTER_ENABLED=false
Environment=REDIS_HOST=127.0.0.1
Environment=REDIS_PORT=VALKEY_LF_PORT_PLACEHOLDER
Environment=REDIS_AUTH=REDIS_AUTH_PLACEHOLDER
Environment=LANGFUSE_INIT_ORG_ID=org-local-dev-id
Environment=LANGFUSE_INIT_ORG_NAME=Local Development
Environment=LANGFUSE_INIT_PROJECT_ID=proj-triage-gateway-id
Environment=LANGFUSE_INIT_PROJECT_NAME=Triage Gateway
Environment=LANGFUSE_INIT_USER_EMAIL=admin@local.dev
Environment=LANGFUSE_INIT_USER_PASSWORD=LANGFUSE_INIT_USER_PASSWORD_PLACEHOLDER
Environment=LANGFUSE_LOG_LEVEL=warn
HealthCmd=wget -q -O /dev/null http://127.0.0.1:LANGFUSE_WEB_PORT_PLACEHOLDER/api/public/health
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=240s

[Service]
Restart=always
TimeoutStartSec=300
40 changes: 40 additions & 0 deletions quadlets/llm-routing-langfuse-worker.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[Unit]
Description=Langfuse Worker — background job processor (POD_NAME_PLACEHOLDER)
After=llm-routing-postgres.service llm-routing-clickhouse.service llm-routing-valkey-lf.service llm-routing-minio.service
Wants=llm-routing-postgres.service llm-routing-clickhouse.service llm-routing-valkey-lf.service llm-routing-minio.service

[Container]
ContainerName=POD_NAME_PLACEHOLDER-langfuse-worker
Image=langfuse/langfuse-worker:3.222.0
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
Environment=DATABASE_URL=postgresql://postgres:POSTGRES_PASSWORD_ENCODED_PLACEHOLDER@127.0.0.1:POSTGRES_PORT_PLACEHOLDER/langfuse
Environment=CLICKHOUSE_URL=http://127.0.0.1:CLICKHOUSE_HTTP_PORT_PLACEHOLDER
Environment=CLICKHOUSE_USER=clickhouse
Environment=CLICKHOUSE_PASSWORD=CLICKHOUSE_PASSWORD_PLACEHOLDER
Environment=CLICKHOUSE_CLUSTER_ENABLED=false
Environment=REDIS_HOST=127.0.0.1
Environment=REDIS_PORT=VALKEY_LF_PORT_PLACEHOLDER
Environment=REDIS_AUTH=REDIS_AUTH_PLACEHOLDER
Environment=HOSTNAME=0.0.0.0
Environment=PORT=LANGFUSE_WORKER_PORT_PLACEHOLDER
Environment=TELEMETRY_ENABLED=false
Environment=LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse-events
Environment=LANGFUSE_S3_EVENT_UPLOAD_REGION=us-east-1
Environment=LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=MINIO_USER_PLACEHOLDER
Environment=LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=MINIO_PASSWORD_PLACEHOLDER
Environment=LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://127.0.0.1:MINIO_S3_PORT_PLACEHOLDER
Environment=S3_FORCE_PATH_STYLE=true
Environment=LANGFUSE_LOG_LEVEL=warn
HealthCmd=pgrep node
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=240s

[Service]
Restart=always
TimeoutStartSec=300
44 changes: 44 additions & 0 deletions quadlets/llm-routing-litellm.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[Unit]
Description=LiteLLM Gateway — upstream proxy with adaptive routing (POD_NAME_PLACEHOLDER)
After=llm-routing-postgres.service llm-routing-valkey-cache.service
Wants=llm-routing-postgres.service llm-routing-valkey-cache.service

[Container]
ContainerName=POD_NAME_PLACEHOLDER-litellm-gateway
Image=ghcr.io/berriai/litellm:v1.93.0
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
# Image entrypoint is docker/prod_entrypoint.sh (litellm CLI); pod.yaml used
# command: python3 /app/entrypoint.py which replaced it. Quadlet Exec= only sets
# args, so override Entrypoint= with the venv python (matches play-kube behavior).
Entrypoint=/app/.venv/bin/python3
Exec=/app/entrypoint.py
Environment=DATABASE_URL=postgresql://postgres:POSTGRES_PASSWORD_ENCODED_PLACEHOLDER@127.0.0.1:POSTGRES_PORT_PLACEHOLDER/postgres
Environment=STORE_MODEL_IN_DB=True
Environment=LITELLM_LOG=INFO
Environment=LANGFUSE_HOST=http://127.0.0.1:LANGFUSE_WEB_PORT_PLACEHOLDER
Environment=LITELLM_MASTER_KEY=LITELLM_MASTER_KEY_PLACEHOLDER
Environment=LITELLM_UI_USERNAME=LITELLM_UI_USERNAME_PLACEHOLDER
Environment=LITELLM_UI_PASSWORD=LITELLM_UI_PASSWORD_PLACEHOLDER
Environment=OLLAMA_API_KEY=OLLAMA_API_KEY_PLACEHOLDER
Environment=OPENROUTER_API_KEY=OPENROUTER_API_KEY_PLACEHOLDER
Environment=SERVER_ROOT_PATH=/llm-routing/litellm
Environment=PROXY_BASE_URL=PROXY_BASE_URL_PLACEHOLDER
Environment=LITELLM_PORT=LITELLM_PORT_PLACEHOLDER
Environment=POSTGRES_PORT=POSTGRES_PORT_PLACEHOLDER
Volume=DATA_ROOT_PLACEHOLDER/litellm-rendered/config.yaml:/app/config.yaml
Volume=DATA_ROOT_PLACEHOLDER/litellm-rendered/entrypoint.py:/app/entrypoint.py
Volume=WORKDIR_PLACEHOLDER/.env:/config/.env
Volume=HOME_PLACEHOLDER/.gemini:/config/gemini_auth
HealthCmd=python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:LITELLM_PORT_PLACEHOLDER/health/liveness')"
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=240s

[Service]
Restart=always
TimeoutStartSec=300
27 changes: 27 additions & 0 deletions quadlets/llm-routing-minio.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[Unit]
Description=MinIO S3 — Langfuse v3 event storage (POD_NAME_PLACEHOLDER)

[Container]
ContainerName=POD_NAME_PLACEHOLDER-minio-s3
Image=minio/minio:RELEASE.2025-09-07T16-13-09Z
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
Environment=MINIO_ROOT_USER=MINIO_USER_PLACEHOLDER
Environment=MINIO_ROOT_PASSWORD=MINIO_PASSWORD_PLACEHOLDER
# pod.yaml used args: server ... with no command:, so image entrypoint
# /usr/bin/docker-entrypoint.sh ran and consumed them. Quadlet Exec= sets args
# the same way — image entrypoint stays, Exec provides the server args.
Exec=server --quiet /data --address :MINIO_S3_PORT_PLACEHOLDER --console-address :MINIO_CONSOLE_PORT_PLACEHOLDER
Volume=DATA_ROOT_PLACEHOLDER/minio-data:/data
HealthCmd=curl -f http://127.0.0.1:MINIO_S3_PORT_PLACEHOLDER/minio/health/live
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=10s

[Service]
Restart=always
TimeoutStartSec=90
26 changes: 26 additions & 0 deletions quadlets/llm-routing-postgres.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[Unit]
Description=PostgreSQL — Langfuse + LiteLLM metadata store (POD_NAME_PLACEHOLDER)

[Container]
ContainerName=POD_NAME_PLACEHOLDER-postgres-db
Image=pgvector/pgvector:0.8.5-pg18
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
Environment=POSTGRES_USER=postgres
Environment=POSTGRES_PASSWORD=POSTGRES_PASSWORD_RAW_PLACEHOLDER
Environment=POSTGRES_DB=langfuse
Environment=PGDATA=/var/lib/postgresql/data/pg18
Environment=PGPORT=POSTGRES_PORT_PLACEHOLDER
Volume=DATA_ROOT_PLACEHOLDER/postgres-data:/var/lib/postgresql
HealthCmd=pg_isready -U postgres -p POSTGRES_PORT_PLACEHOLDER
HealthInterval=10s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=15s

[Service]
Restart=always
TimeoutStartSec=120
53 changes: 53 additions & 0 deletions quadlets/llm-routing-router.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[Unit]
Description=LLM Triage Router — classification + routing gateway (POD_NAME_PLACEHOLDER)
After=llm-routing-litellm.service
Wants=llm-routing-litellm.service

[Container]
ContainerName=POD_NAME_PLACEHOLDER-llm-triage-router
Image=ROUTER_IMAGE_PLACEHOLDER
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
# Router image has no entrypoint (EP=null, CMD=uvicorn...); pod.yaml used
# command: /bin/sh + args: -c ... — Entrypoint=/bin/sh, Exec=-c "..." matches.
Entrypoint=/bin/sh
Exec=-c "set -a && . /config/.env && set +a && LITELLM_PORT=LITELLM_PORT_PLACEHOLDER VALKEY_CACHE_PORT=VALKEY_CACHE_PORT_PLACEHOLDER exec uvicorn main:app --host 0.0.0.0 --port ROUTER_PORT_PLACEHOLDER --log-level $${LOG_LEVEL:-warning}"
Environment=CONFIG_PATH=/config/router_dir/config.yaml
Environment=LITELLM_CONFIG_PATH=/config/litellm_dir/config.yaml
Environment=DATABASE_URL=postgresql://postgres:POSTGRES_PASSWORD_ENCODED_PLACEHOLDER@127.0.0.1:POSTGRES_PORT_PLACEHOLDER/postgres
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=RUN_USER_PLACEHOLDER/bus
Environment=LITELLM_MASTER_KEY=LITELLM_MASTER_KEY_PLACEHOLDER
Environment=LANGFUSE_PUBLIC_KEY=LANGFUSE_PUBLIC_KEY_PLACEHOLDER
Environment=LANGFUSE_SECRET_KEY=LANGFUSE_SECRET_KEY_PLACEHOLDER
Environment=LANGFUSE_HOST=http://127.0.0.1:LANGFUSE_WEB_PORT_PLACEHOLDER
Environment=OLLAMA_API_KEY=OLLAMA_API_KEY_PLACEHOLDER
Environment=PUBLIC_BASE_URL=PUBLIC_BASE_URL_PLACEHOLDER
Environment=ROUTING_DOMAIN=ROUTING_DOMAIN_PLACEHOLDER
Environment=LITELLM_PORT=LITELLM_PORT_PLACEHOLDER
Environment=VALKEY_CACHE_PORT=VALKEY_CACHE_PORT_PLACEHOLDER
Environment=ROUTER_PORT=ROUTER_PORT_PLACEHOLDER
Environment=LANGFUSE_WEB_PORT=LANGFUSE_WEB_PORT_PLACEHOLDER
Environment=LOG_LEVEL=info
Volume=DATA_ROOT_PLACEHOLDER/router-rendered:/config/router_dir
Volume=DATA_ROOT_PLACEHOLDER/litellm-rendered:/config/litellm_dir
Volume=DATA_ROOT_PLACEHOLDER/datasets:/app/data
Volume=HOME_PLACEHOLDER/.gemini:/config/gemini_auth
Volume=HOME_PLACEHOLDER/.gemini:/root/.gemini
Volume=HOME_PLACEHOLDER/.local/share/goose:/config/goose_sessions
Volume=HOME_PLACEHOLDER/.local/bin/agy:/usr/local/bin/agy
Volume=RUN_USER_PLACEHOLDER/bus:RUN_USER_PLACEHOLDER/bus
Volume=HOME_PLACEHOLDER/.local/share/keyrings:/root/.local/share/keyrings
Volume=RUN_USER_PLACEHOLDER:RUN_USER_PLACEHOLDER
Volume=WORKDIR_PLACEHOLDER/.env:/config/.env
HealthCmd=python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:ROUTER_PORT_PLACEHOLDER/metrics')"
HealthInterval=15s
HealthTimeout=5s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=240s

[Service]
Restart=always
TimeoutStartSec=300
25 changes: 25 additions & 0 deletions quadlets/llm-routing-valkey-cache.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[Unit]
Description=Valkey Cache — LiteLLM response cache (POD_NAME_PLACEHOLDER)

[Container]
ContainerName=POD_NAME_PLACEHOLDER-valkey-cache
Image=valkey/valkey:9.1.1
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
# pod.yaml used command: (replaces entrypoint). Image entrypoint docker-entrypoint.sh
# would also work, but explicit Entrypoint= matches play-kube semantics exactly.
Entrypoint=valkey-server
Exec=--bind 127.0.0.1 --port VALKEY_CACHE_PORT_PLACEHOLDER --loglevel warning
Volume=DATA_ROOT_PLACEHOLDER/valkey-data:/data
HealthCmd=valkey-cli -p VALKEY_CACHE_PORT_PLACEHOLDER ping
HealthInterval=10s
HealthTimeout=2s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=5s

[Service]
Restart=always
TimeoutStartSec=90
23 changes: 23 additions & 0 deletions quadlets/llm-routing-valkey-lf.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[Unit]
Description=Valkey LF — Langfuse v3 BullMQ job queue (POD_NAME_PLACEHOLDER)

[Container]
ContainerName=POD_NAME_PLACEHOLDER-valkey-lf
Image=valkey/valkey:9.1.1
Pod=llm-routing.pod
# play-kube injected <pod-name> -> 127.0.0.1 into /etc/hosts; replicate for apps
# (langfuse 3.222+) that resolve the pod hostname for self/intra-pod calls.
AddHost=POD_NAME_PLACEHOLDER:127.0.0.1
Entrypoint=redis-server
Exec=--bind 127.0.0.1 --port VALKEY_LF_PORT_PLACEHOLDER --requirepass REDIS_AUTH_PLACEHOLDER --maxmemory-policy noeviction --loglevel warning
Volume=DATA_ROOT_PLACEHOLDER/redis-lf-data:/data
HealthCmd=valkey-cli -p VALKEY_LF_PORT_PLACEHOLDER -a REDIS_AUTH_PLACEHOLDER ping
HealthInterval=10s
HealthTimeout=2s
HealthOnFailure=kill
HealthRetries=5
HealthStartPeriod=5s

[Service]
Restart=always
TimeoutStartSec=90
13 changes: 13 additions & 0 deletions quadlets/llm-routing.pod
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# LLM Triage Gateway pod — Quadlet template (rendered by start-stack.sh)
# Pod name is rendered from POD_NAME (prod-router-pod / dev-router-pod).
[Unit]
Description=LLM Triage Gateway Pod (POD_NAME_PLACEHOLDER)
Wants=network-online.target
After=network-online.target

[Pod]
PodName=POD_NAME_PLACEHOLDER
Network=host

[Install]
WantedBy=default.target
Loading
Loading