Skip to content

Commit ad70b7f

Browse files
authored
feat: k8s support and some fixes (#407)
* update README Signed-off-by: JaredforReal <[email protected]> * update README & delete network config Signed-off-by: JaredforReal <[email protected]> * add owner Signed-off-by: JaredforReal <[email protected]> * add dashboard demo to k8s Signed-off-by: JaredforReal <[email protected]> * add Xunzhuo to owner Signed-off-by: JaredforReal <[email protected]> --------- Signed-off-by: JaredforReal <[email protected]>
1 parent 8b1d14e commit ad70b7f

File tree

6 files changed

+143
-87
lines changed

6 files changed

+143
-87
lines changed

Dockerfile.extproc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,11 @@ FROM golang:1.24 AS go-builder
5757

5858
WORKDIR /app
5959

60-
ENV GOPROXY=https://goproxy.cn,direct
61-
ENV GOSUMDB=sum.golang.google.cn
62-
6360
# Copy Go module files first for better layer caching
6461
RUN mkdir -p src/semantic-router
6562
COPY src/semantic-router/go.mod src/semantic-router/go.sum src/semantic-router/
6663
COPY candle-binding/go.mod candle-binding/semantic-router.go candle-binding/
6764

68-
RUN cd src/semantic-router && go mod download && \
69-
cd /app/candle-binding && go mod download
70-
7165
# Copy semantic-router source code
7266
COPY src/semantic-router/ src/semantic-router/
7367

dashboard/OWNER

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dashboard directory Owners
2+
@JaredforReal
3+
@Xunzhuo

dashboard/README.md

Lines changed: 91 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Semantic Router Modern Dashboard
1+
# Semantic Router Dashboard
22

33
Unified dashboard that brings together Configuration Management, an Interactive Playground, and Real-time Monitoring & Observability. It provides a single entry point across local, Docker Compose, and Kubernetes deployments.
44

@@ -12,16 +12,15 @@ Unified dashboard that brings together Configuration Management, an Interactive
1212
## What’s already in this repo (reused)
1313

1414
- Prometheus + Grafana
15-
- Docker Compose services in `docker-compose.yml` (ports: Prometheus 9090, Grafana 3000)
16-
- Local observability in `docker-compose.obs.yml` (host network)
15+
- Docker Compose services in `deploy/docker-compose/docker-compose.yml` (Prometheus 9090, Grafana 3000)
16+
- Local observability in `tools/observability/docker-compose.obs.yml` (host network)
1717
- K8s manifests under `deploy/kubernetes/observability/{prometheus,grafana}`
1818
- Provisioned datasource and dashboard in `tools/observability/`
1919
- Router metrics and API
2020
- Metrics at `:9190/metrics` (Prometheus format)
2121
- Classification API on `:8080` with endpoints like `GET /api/v1`, `GET /config/classification`
2222
- Open WebUI integration
2323
- Pipe in `tools/openwebui-pipe/vllm_semantic_router_pipe.py`
24-
- Doc in `website/docs/tutorials/observability/open-webui-integration.md`
2524

2625
These are sufficient to embed and proxy—no need to duplicate core functionality.
2726

@@ -38,8 +37,9 @@ Modern SPA built with:
3837

3938
Pages:
4039

40+
- **Landing** (`/`): Intro landing with animated terminal demo and quick links
4141
- **Monitoring** (`/monitoring`): Grafana dashboard embedding with custom path input
42-
- **Config** (`/config`): Real-time configuration viewer with multiple endpoints
42+
- **Config** (`/config`): Real-time configuration viewer with non-persistent edit demo (see note)
4343
- **Playground** (`/playground`): Open WebUI interface for testing
4444

4545
Features:
@@ -49,6 +49,13 @@ Features:
4949
- ⚡ Fast navigation with React Router
5050
- 🎨 Modern UI inspired by vLLM website design
5151

52+
Config edit demo (frontend only):
53+
54+
- The Config page includes edit/add modals to showcase how configuration could be managed.
55+
- Current backend is read-only for config: it exposes `GET /api/router/config/all` only.
56+
- Demo save targets `POST /api/router/config/update` (not implemented by default). You can wire this endpoint in the backend to persist changes, or keep the edits as a UI mock.
57+
- Tools DB panel attempts to load `/api/tools-db` for `tools_db.json`. Add a backend route or static file handler to serve this if you want it live.
58+
5259
### Backend (Go HTTP Server)
5360

5461
- Serves static frontend (Vite production build)
@@ -58,6 +65,7 @@ Features:
5865
- `GET /embedded/openwebui/*` → Open WebUI (optional)
5966
- `GET /api/router/*` → Router Classification API (`:8080`)
6067
- `GET /metrics/router` → Router `/metrics` (optional aggregation later)
68+
- `GET /api/router/config/all` → Returns your `config.yaml` as JSON (read-only)
6169
- `GET /healthz` → Health check endpoint
6270
- Normalizes headers for iframe embedding: strips/overrides `X-Frame-Options` and `Content-Security-Policy` frame-ancestors as needed
6371
- SPA routing support: serves `index.html` for all non-asset routes
@@ -73,6 +81,7 @@ dashboard/
7381
│ │ │ ├── Layout.tsx # Main layout with header/nav
7482
│ │ │ └── Layout.module.css
7583
│ │ ├── pages/ # Page components
84+
│ │ │ ├── LandingPage.tsx # Welcome page with terminal demo
7685
│ │ │ ├── MonitoringPage.tsx # Grafana iframe with path control
7786
│ │ │ ├── ConfigPage.tsx # Config viewer with API fetch
7887
│ │ │ ├── PlaygroundPage.tsx # Open WebUI iframe
@@ -90,10 +99,9 @@ dashboard/
9099
│ ├── go.mod # Go module (minimal dependencies)
91100
│ └── Dockerfile # Multi-stage build (Node + Go + Alpine)
92101
├── deploy/
93-
│ ├── docker/ # Docker Compose overlay (deprecated)
94-
│ └── kubernetes/ # K8s manifests (Service/Ingress/ConfigMap)
102+
│ └── kubernetes/ # K8s manifests (Deployment/Service/ConfigMap)
95103
├── README.md # This file
96-
└── RISKS.md # Security considerations
104+
└── (no RISKS.md) # Security considerations are documented inline for now
97105
```
98106

99107
## Environment-agnostic configuration
@@ -108,7 +116,7 @@ Required env vars (with sensible defaults per environment):
108116
- `TARGET_ROUTER_API_URL` (router `:8080`)
109117
- `TARGET_ROUTER_METRICS_URL` (router `:9190/metrics`)
110118
- `TARGET_OPENWEBUI_URL` (optional; enable playground tab only if present)
111-
- `ALLOW_IFRAME_EMBED` (default: true; backend will remove/override frame-busting headers)
119+
Note: The backend already adjusts frame-busting headers (X-Frame-Options/CSP) to allow embedding from the dashboard origin; no extra env flag is required.
112120

113121
Recommended upstream settings for embedding:
114122

@@ -117,16 +125,16 @@ Recommended upstream settings for embedding:
117125

118126
## URL strategy (stable, user-facing)
119127

120-
- Dashboard Home: `http://<host>:8700/`
128+
- Dashboard Home (Landing): `http://<host>:8700/`
121129
- Monitoring tab: iframe `src="/embedded/grafana/d/<dashboard-uid>?kiosk&theme=light"`
122-
- Config tab: frontend fetch `GET /api/router/config/classification`
130+
- Config tab: frontend fetch `GET /api/router/config/all` (demo edit modals; see note above)
123131
- Playground tab: iframe `src="/embedded/openwebui/"` (rendered only if `TARGET_OPENWEBUI_URL` is set)
124132

125133
## Deployment matrix
126134

127135
1) Local dev (router and observability on host)
128136

129-
- Use `docker-compose.obs.yml` to start Prometheus (9090) and Grafana (3000) on host network
137+
- Use `tools/observability/docker-compose.obs.yml` to start Prometheus (9090) and Grafana (3000) on host network
130138
- Start dashboard backend locally (port 8700)
131139
- Env examples:
132140
- `TARGET_GRAFANA_URL=http://localhost:3000`
@@ -137,8 +145,7 @@ Recommended upstream settings for embedding:
137145

138146
2) Docker Compose (all-in-one)
139147

140-
- Reuse services defined in root `docker-compose.yml`
141-
- Add dashboard and optional Open WebUI services in `dashboard/deploy/docker/compose.yml`
148+
- Reuse services defined in `deploy/docker-compose/docker-compose.yml` (Dashboard included by default)
142149
- Env examples (inside compose network):
143150
- `TARGET_GRAFANA_URL=http://grafana:3000`
144151
- `TARGET_PROMETHEUS_URL=http://prometheus:9090`
@@ -170,37 +177,21 @@ Recommended upstream settings for embedding:
170177
- New integrations: add target env vars and a new `/embedded/<service>` route in backend proxy
171178
- Metrics aggregation: add `/api/metrics` in backend to produce derived KPIs from Prometheus
172179

173-
## Implementation milestones
174-
175-
1) MVP (this PR)
176-
177-
- Scaffold `dashboard/` (this README)
178-
- Backend: Go server with reverse proxies for `/embedded/*` and `/api/router/*`
179-
- Frontend: minimal SPA with three tabs and iframes + JSON viewer
180-
- Compose overlay: `dashboard/deploy/docker/compose.yml` to launch dashboard with existing stack
181-
182-
2) K8s manifests
183-
184-
- Deployment + Service + ConfigMap with env vars; optional Ingress
185-
- Document `kubectl port-forward` for dev
186-
187-
3) Auth hardening and polish
180+
## Implementation notes
188181

189-
- Env toggles for anonymous/off
190-
- OIDC enablement behind a flag
191-
- Metrics summary endpoint
182+
— Backend: Go server with reverse proxies for `/embedded/*` and `/api/router/*`, plus `/api/router/config/all`
183+
— Frontend: SPA with three tabs and iframes + structured config viewer
184+
— K8s manifests: Deployment + Service + ConfigMap; optional Ingress (add per cluster)
185+
— Future: OIDC, per-route RBAC, metrics summary endpoint
192186

193187
## Quick Start
194188

195-
### Method 1: One-click Start with Docker Compose (Recommended)
189+
### Method 1: Start with Docker Compose (Recommended)
196190

197191
The Dashboard is integrated into the main Compose stack, requiring no extra configuration:
198192

199193
```bash
200-
# Run from the project root directory
201-
make docker-compose-up
202-
203-
# Or use docker compose directly
194+
# From the project root directory
204195
docker compose -f deploy/docker-compose/docker-compose.yml up -d --build
205196
```
206197

@@ -215,33 +206,25 @@ After startup, access:
215206
When developing the Dashboard code locally:
216207

217208
```bash
218-
# 1. Start the local Observability stack
219-
make o11y-local
220-
# Or
209+
# 1) Start Observability locally (Prometheus + Grafana on host network)
221210
docker compose -f tools/observability/docker-compose.obs.yml up -d
222211

223-
# 2. Start the Router (in another terminal)
224-
cd src/semantic-router
225-
go run cmd/main.go -config ../../config/config.yaml
226-
227-
# 3. Install frontend dependencies
212+
# 2) Install frontend dependencies and run Vite dev server
228213
cd dashboard/frontend
229214
npm install
230-
231-
# 4. Start the frontend dev server (with HMR)
232215
npm run dev
233-
# Vite will start on http://localhost:3001 with proxy to backend
216+
# Vite runs at http://localhost:3001 and proxies /api and /embedded to http://localhost:8700
234217

235-
# 5. Start the Dashboard backend (in another terminal)
218+
# 3) Start the Dashboard backend in another terminal
236219
cd dashboard/backend
237220
export TARGET_GRAFANA_URL=http://localhost:3000
238221
export TARGET_PROMETHEUS_URL=http://localhost:9090
239222
export TARGET_ROUTER_API_URL=http://localhost:8080
240223
export TARGET_ROUTER_METRICS_URL=http://localhost:9190/metrics
241-
go run main.go -port=8700 -static=../frontend/dist
224+
export ROUTER_CONFIG_PATH=../../config/config.yaml
225+
go run main.go -port=8700 -static=../frontend/dist -config=$ROUTER_CONFIG_PATH
242226

243-
# For development, use the Vite dev server at http://localhost:3001
244-
# For production preview, build first: cd frontend && npm run build
227+
# Tip: If your router runs inside Docker Compose, point TARGET_* to the container hostnames instead.
245228
```
246229

247230
### Method 3: Rebuild Dashboard Only
@@ -263,8 +246,8 @@ docker logs -f semantic-router-dashboard
263246

264247
### Docker Compose Integration Notes
265248

266-
- The Dashboard service is integrated as a **default service** in `deploy/docker-compose/docker-compose.yml`.
267-
- No additional overlay files are needed; `make docker-compose-up` will automatically start all services.
249+
- The Dashboard service is integrated as a default service in `deploy/docker-compose/docker-compose.yml`.
250+
- No additional overlay files are needed; the compose file will start all services.
268251
- The Dashboard depends on the `semantic-router` (for health checks), `grafana`, and `prometheus` services.
269252

270253
### Dockerfile Build
@@ -289,6 +272,8 @@ Grafana is already configured for embedding in `deploy/docker-compose/docker-com
289272
290273
The Dashboard reverse proxy will automatically clean up `X-Frame-Options` and adjust CSP headers to ensure the iframe loads correctly.
291274

275+
Default dashboard path in Monitoring tab: `/d/llm-router-metrics/llm-router-metrics`.
276+
292277
### Health Check
293278

294279
The Dashboard provides a `/healthz` endpoint for container health checks:
@@ -298,7 +283,57 @@ curl http://localhost:8700/healthz
298283
# Returns: {"status":"healthy","service":"semantic-router-dashboard"}
299284
```
300285

286+
### Kubernetes deployment
287+
288+
The manifest at `dashboard/deploy/kubernetes/deployment.yaml` includes:
289+
290+
- Deployment with args `-port=8700 -static=/app/frontend -config=/app/config/config.yaml`
291+
- Service (ClusterIP) exposing port 80 → container port 8700
292+
- ConfigMap `semantic-router-dashboard-config` for upstream targets (`TARGET_*` env)
293+
- ConfigMap `semantic-router-config` to provide a minimal `config.yaml` (replace with your real one)
294+
295+
Quick start:
296+
297+
```bash
298+
# Set your namespace and apply
299+
kubectl create ns vllm-semantic-router-system --dry-run=client -o yaml | kubectl apply -f -
300+
kubectl -n vllm-semantic-router-system apply -f dashboard/deploy/kubernetes/deployment.yaml
301+
302+
# Port-forward for local testing
303+
kubectl -n vllm-semantic-router-system port-forward svc/semantic-router-dashboard 8700:80
304+
# Open http://localhost:8700
305+
```
306+
307+
Notes:
308+
309+
- Edit `semantic-router-dashboard-config` in the YAML to match your in-cluster service DNS names and namespace.
310+
- Replace `semantic-router-config` content with your actual `config.yaml` or mount a Secret/ConfigMap you already manage.
311+
- To expose externally, add an Ingress or Service of type LoadBalancer according to your cluster.
312+
313+
Optional Ingress example (Nginx Ingress):
314+
315+
```yaml
316+
apiVersion: networking.k8s.io/v1
317+
kind: Ingress
318+
metadata:
319+
name: semantic-router-dashboard
320+
annotations:
321+
kubernetes.io/ingress.class: nginx
322+
spec:
323+
rules:
324+
- host: dashboard.example.com
325+
http:
326+
paths:
327+
- path: /
328+
pathType: Prefix
329+
backend:
330+
service:
331+
name: semantic-router-dashboard
332+
port:
333+
number: 80
334+
```
335+
301336
## Notes
302337

303-
- The website/ (Docusaurus) remains for documentation. The dashboard is a runtime operator/try-it surface, not docs.
304-
- We’ll keep upstream services untouched and do all UX unification at the proxy + SPA layer.
338+
- The dashboard is a runtime operator/try-it surface, not docs. See repository docs for broader guides.
339+
- Upstream services remain untouched; UX unification happens at the proxy + SPA layer.

dashboard/deploy/kubernetes/deployment.yaml

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,46 @@ spec:
1818
- name: dashboard
1919
image: ghcr.io/vllm-project/semantic-router/dashboard:latest
2020
imagePullPolicy: IfNotPresent
21-
args: ["-port=8700", "-static=/app/frontend"]
21+
args: ["-port=8700", "-static=/app/frontend", "-config=/app/config/config.yaml"]
2222
env:
2323
- name: TARGET_GRAFANA_URL
24-
value: http://grafana.vllm-semantic-router-system.svc.cluster.local:3000
24+
valueFrom:
25+
configMapKeyRef:
26+
name: semantic-router-dashboard-config
27+
key: TARGET_GRAFANA_URL
2528
- name: TARGET_PROMETHEUS_URL
26-
value: http://prometheus.vllm-semantic-router-system.svc.cluster.local:9090
29+
valueFrom:
30+
configMapKeyRef:
31+
name: semantic-router-dashboard-config
32+
key: TARGET_PROMETHEUS_URL
2733
- name: TARGET_ROUTER_API_URL
28-
value: http://semantic-router.vllm-semantic-router-system.svc.cluster.local:8080
34+
valueFrom:
35+
configMapKeyRef:
36+
name: semantic-router-dashboard-config
37+
key: TARGET_ROUTER_API_URL
2938
- name: TARGET_ROUTER_METRICS_URL
30-
value: http://semantic-router.vllm-semantic-router-system.svc.cluster.local:9190/metrics
39+
valueFrom:
40+
configMapKeyRef:
41+
name: semantic-router-dashboard-config
42+
key: TARGET_ROUTER_METRICS_URL
3143
- name: TARGET_OPENWEBUI_URL
32-
value: ""
44+
valueFrom:
45+
configMapKeyRef:
46+
name: semantic-router-dashboard-config
47+
key: TARGET_OPENWEBUI_URL
48+
- name: ROUTER_CONFIG_PATH
49+
value: /app/config/config.yaml
3350
ports:
3451
- name: http
3552
containerPort: 8700
3653
volumeMounts:
37-
- name: frontend
38-
mountPath: /app/frontend
54+
- name: router-config
55+
mountPath: /app/config
56+
readOnly: true
3957
volumes:
40-
- name: frontend
58+
- name: router-config
4159
configMap:
42-
name: semantic-router-dashboard-frontend
60+
name: semantic-router-config
4361
---
4462
apiVersion: v1
4563
kind: Service
@@ -59,14 +77,24 @@ spec:
5977
apiVersion: v1
6078
kind: ConfigMap
6179
metadata:
62-
name: semantic-router-dashboard-frontend
80+
name: semantic-router-dashboard-config
6381
data:
64-
index.html: |
65-
<!doctype html>
66-
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>Semantic Router Dashboard</title></head>
67-
<body>
68-
<script>
69-
// Fallback page that redirects to container-mounted frontend if available
70-
window.location.replace('/');
71-
</script>
72-
</body></html>
82+
TARGET_GRAFANA_URL: http://grafana.vllm-semantic-router-system.svc.cluster.local:3000
83+
TARGET_PROMETHEUS_URL: http://prometheus.vllm-semantic-router-system.svc.cluster.local:9090
84+
TARGET_ROUTER_API_URL: http://semantic-router.vllm-semantic-router-system.svc.cluster.local:8080
85+
TARGET_ROUTER_METRICS_URL: http://semantic-router.vllm-semantic-router-system.svc.cluster.local:9190/metrics
86+
TARGET_OPENWEBUI_URL: ""
87+
88+
---
89+
apiVersion: v1
90+
kind: ConfigMap
91+
metadata:
92+
name: semantic-router-config
93+
data:
94+
# Minimal config.yaml to let /api/router/config/all return something.
95+
# Replace with your real configuration or mount a different ConfigMap/Secret.
96+
config.yaml: |
97+
default_model: example-model
98+
default_reasoning_effort: medium
99+
vllm_endpoints: []
100+
model_config: {}

0 commit comments

Comments
 (0)