Skip to content

Commit f3bbea0

Browse files
chore: analytics in every install path + drop test-deploy-run + doc cleanup (#396)
## Why User direction: "I always want clickhouse etc to work in all targets". Post-#391/#395 audit found three install paths missing analytics + one path that can't ever support it: | Path | Status before | Status after | |---|---|---| | `make run` / Compose Quick start | ✅ analytics | ✅ | | `make deploy` / `make deploy-release` (k3d) | ✅ analytics (after #395) | ✅ | | `make test-deploy-{dev,compose,oobe}` | ✅ (base compose + override) | ✅ | | `make run-ghcr` | ❌ go-server only | ✅ | | `make test-deploy-ghcr` | ❌ go-server only | ✅ | | `make test-deploy-registry` | ❌ go-server only | ✅ | | **`make test-deploy-run`** | ❌ bare docker run, can't have analytics | **dropped** | Plus `docs/DEPLOYMENT.md` referenced the now-deleted `k8s-infinite-streaming{,-dev}.yaml` and still said "k3s". ## Changes **Compose files — add analytics services:** - `docker-compose.ghcr.yml` — adds `clickhouse`, `forwarder`, `grafana`. Forwarder pulls from `ghcr.io/jonathaneoliver/infinite-streaming-forwarder:latest`. - `tests/deploy/docker-compose.registry.yml` — same set. Forwarder pulls from `${K3S_REGISTRY}/infinite-streaming-forwarder:dev`. **GHCR workflow — publish the forwarder too:** - `.github/workflows/docker-publish.yml` — extends the existing `infinite-streaming` build to also build/push `infinite-streaming-forwarder` from `./analytics/go-forwarder`. Same tag pattern (`:latest`, `:main`, `:sha-…`, semver). Docker Hub mirror gated on `vars.DOCKERHUB_NAMESPACE` the same way. **Drops:** - `make test-deploy-run` (bare `docker run`) — incompatible with the analytics-everywhere invariant. Removed from the recipe, from `test-deploy-all`, and from the `test-clean` cleanup list. - README "Docker run (single container, no compose)" section — gone. Macos/Docker-Desktop TC note kept (now under the section preface, applies to all compose-based installs). - Makefile stale defaults orphaned by #395: `K3S_KUBECONFIG`, `K8S_MANIFESTS`, `K8S_DEPLOYMENT`. **Doc updates (post-#395 reality):** - `README.md` — "Other ways to run it" rewritten. GHCR snippet now also fetches `analytics/` via tarball so the bind mounts in `docker-compose.ghcr.yml` resolve. k3s pointer → k3d. - `docs/DEPLOYMENT.md` — rewritten for two k3d clusters (api ports 6543/6544, kubeconfigs at `~/.config/k3d/`, `make k3d-bootstrap`, `make teardown-{dev,release}`). GHCR-publishing section mentions both images. - `docs/API.md`, `docs/ARCHITECTURE.md`, `docs/TROUBLESHOOTING.md`, `analytics/README.md` — `s/k3s/k3d/` where the change is real (port mapping, deployment modes, troubleshooting playbook, htpasswd runbook). ## Test plan - [x] `docker compose -f docker-compose.ghcr.yml config` parses. - [x] `docker compose -f tests/deploy/docker-compose.registry.yml config` parses. - [x] `make -n test-deploy-all` parses with no `test-deploy-run` reference. - [x] No remaining stale references: `grep k3s` across docs returns zero hits in active prose (only the migration-warning sentence in TROUBLESHOOTING). - [ ] Live verification: `make run-ghcr` / `make test-deploy-{ghcr,registry}` end-to-end against the test-dev host. Deferred until the GHCR forwarder image is first published — that requires this PR to merge so the workflow runs once on `main`. Note in the PR body that the first `make run-ghcr` after merge will hit a 404 on the forwarder image until the workflow completes (~3 min). ## Out of scope - k3d-equivalent maintenance targets for `analytics-update` / `analytics-rebuild-forwarder` / `analytics-migrate` (currently target the test-dev compose path only). Worth a separate issue if needed. - Real ClickHouse password hardening (unrelated, came up in #391's CodeQL discussion). Closes #394.
1 parent 0a800de commit f3bbea0

10 files changed

Lines changed: 296 additions & 94 deletions

File tree

.github/workflows/docker-publish.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,47 @@ jobs:
8383
${{ steps.meta-server-dh.outputs.tags }}
8484
labels: ${{ steps.meta-server-ghcr.outputs.labels }}
8585

86+
# ── Forwarder image ────────────────────────────────────────────────
87+
# Published alongside the main image so `make run-ghcr` and the
88+
# docker-compose.ghcr.yml install path can pull a complete analytics
89+
# stack from GHCR without a source checkout. The forwarder is
90+
# cluster-/install-agnostic; the same image works for compose, k3d,
91+
# and the various test-deploy variants.
92+
93+
- name: Extract metadata (forwarder, GHCR)
94+
id: meta-forwarder-ghcr
95+
uses: docker/metadata-action@v6
96+
with:
97+
images: ghcr.io/${{ github.repository }}-forwarder
98+
tags: |
99+
type=ref,event=branch
100+
type=sha
101+
type=raw,value=latest,enable={{is_default_branch}}
102+
type=semver,pattern={{version}},prefix=v
103+
type=semver,pattern={{major}}.{{minor}},prefix=v
104+
type=semver,pattern={{major}},prefix=v
105+
106+
- name: Extract metadata (forwarder, Docker Hub)
107+
if: ${{ vars.DOCKERHUB_NAMESPACE != '' }}
108+
id: meta-forwarder-dh
109+
uses: docker/metadata-action@v6
110+
with:
111+
images: docker.io/${{ vars.DOCKERHUB_NAMESPACE }}/infinite-streaming-forwarder
112+
tags: |
113+
type=ref,event=branch
114+
type=sha
115+
type=raw,value=latest,enable={{is_default_branch}}
116+
type=semver,pattern={{version}},prefix=v
117+
type=semver,pattern={{major}}.{{minor}},prefix=v
118+
type=semver,pattern={{major}},prefix=v
119+
120+
- name: Build and push forwarder
121+
uses: docker/build-push-action@v7
122+
with:
123+
context: ./analytics/go-forwarder
124+
push: true
125+
tags: |
126+
${{ steps.meta-forwarder-ghcr.outputs.tags }}
127+
${{ steps.meta-forwarder-dh.outputs.tags }}
128+
labels: ${{ steps.meta-forwarder-ghcr.outputs.labels }}
129+

Makefile

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ export
77

88

99
K3S_SSH_HOST ?= user@your-k3s-host
10-
K3S_KUBECONFIG ?= /home/user/.kube/config
1110
GO_SERVER_IMAGE ?= ghcr.io/jonathaneoliver/infinite-streaming:latest
12-
K8S_MANIFESTS ?= k8s-infinite-streaming.yaml
13-
K8S_DEPLOYMENT ?= infinite-streaming
1411
IOS_SIM_DEVICE ?= iPad Pro 13-inch (M5)
1512
IOS_APP_BUNDLE_ID ?= com.jeoliver.InfiniteStreamPlayer
1613
IOS_API_BASE ?= http://$(K3S_HOST):40000
@@ -304,7 +301,7 @@ test-go:
304301
@echo "=== go-upload ==="
305302
cd go-upload && go vet ./... && go test -race ./...
306303

307-
test-deploy-all: test-deploy-compose test-deploy-run test-deploy-ghcr test-deploy-registry
304+
test-deploy-all: test-deploy-compose test-deploy-ghcr test-deploy-registry
308305

309306
test-deploy-dev:
310307
@echo "=== Dev: local working tree (port 21000) ==="
@@ -385,7 +382,7 @@ test-clean-dev:
385382
ssh $(TEST_SSH) 'docker rm -f test-dev-server 2>/dev/null'
386383

387384
test-clean:
388-
ssh $(TEST_SSH) 'docker rm -f test-dev-server test-compose-server test-docker-run test-ghcr-server test-registry-server test-oobe-server 2>/dev/null; docker network prune -f 2>/dev/null'
385+
ssh $(TEST_SSH) 'docker rm -f test-dev-server test-compose-server test-ghcr-server test-registry-server test-oobe-server 2>/dev/null; docker network prune -f 2>/dev/null'
389386

390387
test-status:
391388
@ssh $(TEST_SSH) 'for p in 21000 22000 23000 24000 25000 26000; do \
@@ -464,16 +461,12 @@ test-deploy-compose:
464461
scp tests/deploy/override-compose.yml $(TEST_SSH):~/test-compose/docker-compose.override.yml
465462
ssh $(TEST_SSH) 'cd ~/test-compose && docker compose build && docker compose up -d'
466463

467-
test-deploy-run:
468-
@echo "=== Option 2: Docker run (port 23000) ==="
469-
ssh $(TEST_SSH) 'docker rm -f test-docker-run 2>/dev/null; \
470-
docker run -d --name test-docker-run --cap-add NET_ADMIN --privileged \
471-
-p 23000:30000 -p 23081:30081 -p 23181:30181 -p 23281:30281 -p 23381:30381 -p 23481:30481 \
472-
-p 23581:30581 -p 23681:30681 -p 23781:30781 -p 23881:30881 \
473-
-e INFINITE_STREAM_RENDEZVOUS_URL=$(INFINITE_STREAM_RENDEZVOUS_URL) \
474-
-e INFINITE_STREAM_ANNOUNCE_URL=http://$(TEST_HOST):23000 \
475-
-v $(TEST_MEDIA_DIR):/media \
476-
infinite-streaming:latest /sbin/launch.sh 1'
464+
# `test-deploy-run` (the bare `docker run` of a single container)
465+
# was removed in #394 — the install method it tested can't support
466+
# analytics by definition (one image, no sidecars), and analytics is
467+
# now a baseline expectation in every deploy path. The
468+
# `test-deploy-{compose,ghcr,registry}` variants cover the actual
469+
# install methods documented in the README.
477470

478471
test-deploy-ghcr:
479472
@echo "=== Option 3: GHCR pre-built (port 24000) ==="

README.md

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ From there, **Playback** plays the same clip standalone, **Testing Session** ope
131131

132132
Skipping the seed and uploading your own files via **Open Upload** or by dropping MP4s into `$CONTENT_DIR/originals/` works identically — the seed clip is just a zero-friction "Hello, World" that exercises the full pipeline against content the server generates itself.
133133

134-
Other deployment options (pre-built images, single container, k3s) are in [Advanced deployment](#advanced-deployment) at the bottom.
134+
Other deployment options (pre-built images from GHCR, k3d clusters) are in [Other ways to run it](#other-ways-to-run-it) at the bottom.
135135

136136
---
137137

@@ -342,7 +342,7 @@ A sidecar stack (ClickHouse + Grafana + a small Go forwarder) auto-archives sess
342342

343343
**Operating it**: `make analytics-rebuild-forwarder` recreates the forwarder container in-place (live UI untouched); `make analytics-update` reloads Grafana provisioning; `make analytics-migrate SQL='ALTER TABLE …'` runs a schema change. The data is exposed read-only to the dashboard via parameterized ClickHouse queries — no string interpolation, no auth-token leakage.
344344

345-
**Securing for WAN deployment**: opt-in HTTP Basic auth via `INFINITE_STREAM_AUTH_HTPASSWD` gates the dashboard, `/analytics/api/`, and `/grafana/`; player-app endpoints stay public so unattended Apple/Roku/AndroidTV clients keep working. ClickHouse binds to `127.0.0.1` only by default. See [`analytics/README.md`](analytics/README.md) for the docker-compose and k3s runbooks.
345+
**Securing for WAN deployment**: opt-in HTTP Basic auth via `INFINITE_STREAM_AUTH_HTPASSWD` gates the dashboard, `/analytics/api/`, and `/grafana/`; player-app endpoints stay public so unattended Apple/Roku/AndroidTV clients keep working. ClickHouse binds to `127.0.0.1` only by default. See [`analytics/README.md`](analytics/README.md) for the docker-compose and k3d runbooks.
346346

347347
The two pages downstream of this stack — **Sessions view** (the picker) and **Session Viewer** (replay one) — are described in their own sections below.
348348

@@ -694,7 +694,7 @@ That's it — no third-party services beyond a Cloudflare account.
694694
| `INFINITE_STREAM_RENDEZVOUS_URL` | Rendezvous Worker base URL. Required to enable any pairing. |
695695
| `INFINITE_STREAM_ANNOUNCE_URL` | URL that clients should use to reach this server (e.g. `http://lenovo.local:30000`). When set, this server appears in same-WAN auto-discovery. |
696696
| `INFINITE_STREAM_ANNOUNCE_LABEL` | Optional friendly label. Defaults to `host:port` from the announce URL. |
697-
| `INFINITE_STREAM_SERVER_ID` | Optional explicit announce ID (4–64 chars `[A-Za-z0-9_-]`). Defaults to a stable random ID persisted at `<data_dir>/server_id`. Set this when multiple deployments share the same data directory (e.g. dev + release pods on the same k3s node), otherwise their announces overwrite each other on the rendezvous. |
697+
| `INFINITE_STREAM_SERVER_ID` | Optional explicit announce ID (4–64 chars `[A-Za-z0-9_-]`). Defaults to a stable random ID persisted at `<data_dir>/server_id`. Set this when multiple deployments share the same data directory (e.g. dev + release pods on the same k3d host), otherwise their announces overwrite each other on the rendezvous. |
698698

699699
### HTTP, HTTPS, and iOS App Transport Security
700700

@@ -709,47 +709,42 @@ The server defaults to plain HTTP on its dashboard / API / playback ports. That'
709709

710710
The iOS/tvOS Info.plist files in this repo include an explicit `NSExceptionDomains` entry for `infinitestreaming.jeoliver.com` (the upstream maintainer's public domain). **If you fork and ship apps that talk to a different public-HTTP hostname** (your own server, a Tailscale MagicDNS name like `*.ts.net`, a Tailscale CGNAT IP in `100.64.0.0/10`, etc.) you must add it to both Info.plists or those clients will silently fail to load anything.
711711

712-
The cleaner long-term answer is to terminate TLS at the server so all clients use HTTPS and no per-domain ATS / cleartext exceptions are needed. The k3s manifests already mount a `certs-vol` for this; flipping the nginx template to `listen … ssl` and pointing it at a Let's Encrypt cert (or whichever cert lives in `K3S_CERTS_DIR`) gets you there.
712+
The cleaner long-term answer is to terminate TLS at the server so all clients use HTTPS and no per-domain ATS / cleartext exceptions are needed. The k3d manifests already mount a `certs-vol` for this; flipping the nginx template to `listen … ssl` and pointing it at a Let's Encrypt cert (or whichever cert lives in `K3S_CERTS_DIR`) gets you there.
713713

714714
---
715715

716716
## Other ways to run it
717717

718718
Most users should stick with Docker Compose from the [Quick start](#quick-start). These variants are for specific scenarios.
719719

720-
### Docker run (single container, no compose)
721-
722-
```bash
723-
export CONTENT_DIR=/path/to/your/media
724-
725-
docker run -d --name infinite-streaming \
726-
--cap-add NET_ADMIN --privileged \
727-
-p 30000:30000 \
728-
-p 30081:30081 \
729-
-p 30181:30181 -p 30281:30281 -p 30381:30381 -p 30481:30481 \
730-
-p 30581:30581 -p 30681:30681 -p 30781:30781 -p 30881:30881 \
731-
-v $CONTENT_DIR:/media \
732-
ghcr.io/jonathaneoliver/infinite-streaming:latest \
733-
/sbin/launch.sh 1
734-
```
735-
736-
Ports 30181–30881 are the per-session proxy ports that testing sessions get redirected to. Without mapping them, `testing-session.html` works but segments never load because the allocated session port is unreachable from the host.
737-
738720
> **macOS / Docker Desktop note:** Network shaping (TC/nftables) works on Docker Desktop for Mac with `--cap-add NET_ADMIN`, but the TC stats polling (every 100ms per session) spawns processes through the Linux VM layer, which causes significantly higher CPU usage and fan noise compared to native Linux. This is a Docker Desktop VM overhead issue, not a code issue. For sustained testing with shaping, use a native Linux host.
739721
740722
### Pre-built images from GHCR (no source checkout)
741723

724+
The compose file pulls `infinite-streaming` and `infinite-streaming-forwarder` from GHCR. ClickHouse and Grafana provisioning files are tiny (~30 KB) so the install grabs them via a tarball alongside the compose file:
725+
742726
```bash
743727
mkdir infinite-streaming && cd infinite-streaming
728+
729+
# Compose file
744730
curl -fsSL https://raw.githubusercontent.com/jonathaneoliver/infinite-streaming/main/docker-compose.ghcr.yml \
745731
-o docker-compose.yml
732+
733+
# Analytics provisioning (ClickHouse schema + Grafana datasources/dashboards)
734+
mkdir -p analytics
735+
curl -fsSL https://github.com/jonathaneoliver/infinite-streaming/archive/main.tar.gz | \
736+
tar -xzC . --strip-components=1 \
737+
infinite-streaming-main/analytics
738+
746739
echo "CONTENT_DIR=/path/to/your/media" > .env
747740
docker compose up -d
748741
```
749742

750-
### k3s, release tagging, GHCR publishing
743+
Open `http://localhost:30000/`. The dashboard's Sessions / Session Viewer / Grafana features all work in this mode (analytics tier comes up alongside the main image — see [Analytics tier](#analytics-tier)).
744+
745+
### k3d, release tagging, GHCR publishing
751746

752-
See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) for running in a k3s cluster (release + dev side by side), pinning immutable release tags, and configuring GHCR publishing from a fork.
747+
See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) for running in two side-by-side k3d clusters (release + dev), pinning immutable release tags, and configuring GHCR publishing from a fork.
753748

754749
---
755750

@@ -773,7 +768,7 @@ Captured from the live dashboard; files live in [`docs/screenshots/`](docs/scree
773768
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — services, routing, port map, request flow
774769
- [`docs/API.md`](docs/API.md) — HTTP endpoints across go-live, go-upload, go-proxy
775770
- [`docs/FAULT_INJECTION.md`](docs/FAULT_INJECTION.md) — full fault and shaping reference
776-
- [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md)k3s, release tagging, GHCR publishing
771+
- [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md)k3d, release tagging, GHCR publishing
777772
- [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) — common issues and fixes
778773
- [`PRD.md`](PRD.md) — product behavior source of truth
779774
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — development workflow

analytics/README.md

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,15 @@ Then:
3737
- Grafana dashboard: <http://localhost:30300/d/is-session-analytics>
3838
- Replay a session: <http://localhost:30000/testing.html?replay=1&session=SESSION_ID>
3939

40-
## k3s
40+
## k3d
4141

42-
Apply `k8s-analytics.yaml` alongside the main deployment. Set
43-
`ANALYTICS_SSE_URL` (default `http://infinite-streaming-dev:30081/api/sessions/stream`)
44-
and `ANALYTICS_GRAFANA_NODEPORT`.
42+
`make deploy` and `make deploy-release` apply `k8s-analytics.yaml`
43+
into the matching k3d cluster automatically — one analytics tier per
44+
cluster (each cluster has its own ClickHouse PVC, forwarder, and
45+
Grafana). The forwarder's SSE source is the same in-cluster URL in
46+
both clusters (`http://infinite-streaming:30081/api/sessions/stream`)
47+
because each cluster has exactly one `infinite-streaming` Service at
48+
NodePort 30081.
4549

4650
## Replay mode
4751

@@ -104,18 +108,23 @@ When `INFINITE_STREAM_AUTH_HTPASSWD` is unset (the default), auth is
104108
disabled — same behaviour as before. With it set, the dashboard pages,
105109
`/analytics/api/*`, and `/grafana/*` all return 401 without credentials.
106110

107-
### k3s deployment (lenovo)
111+
### k3d deployment (lenovo)
112+
113+
Both clusters use the same Deployment name (`infinite-streaming`); pick the right kubeconfig per cluster.
108114

109115
```sh
116+
# Pick a cluster (dev or release)
117+
export KUBECONFIG=~/.config/k3d/smashing-release-kubeconfig.yaml
118+
# (or smashing-dev-kubeconfig.yaml for the dev cluster)
119+
110120
# Generate htpasswd
111121
docker run --rm httpd:alpine htpasswd -nbB myuser 'mypass' > /tmp/htpasswd
112122

113-
# Create a Secret holding the file
123+
# Create a Secret holding the file (per-cluster)
114124
kubectl create secret generic infinite-streaming-auth \
115125
--from-file=htpasswd=/tmp/htpasswd
116126

117-
# Patch the deployment (use `infinite-streaming` for release,
118-
# `infinite-streaming-dev` for the dev stack)
127+
# Patch the deployment (same name in both clusters)
119128
kubectl patch deployment infinite-streaming --patch '
120129
spec:
121130
template:
@@ -143,7 +152,7 @@ curl -s -o /dev/null -w '%{http_code}\n' -u myuser:mypass http://lenovo.local:30
143152
# → 200
144153
```
145154

146-
Rotate the password by re-creating the secret and restarting the rollout:
155+
Rotate the password by re-creating the secret and restarting the rollout (in the same cluster context):
147156

148157
```sh
149158
docker run --rm httpd:alpine htpasswd -nbB myuser 'newpass' > /tmp/htpasswd

docker-compose.ghcr.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,83 @@ services:
3636
- INFINITE_STREAM_UPSTREAM_PORT=30000
3737
- INFINITE_STREAM_MAX_SESSIONS=8
3838
- INFINITE_STREAM_TC_INTERFACE=eth0
39+
# Wire nginx /analytics/api/* and /grafana/* to the analytics
40+
# sidecar services below. Same gating pattern as base compose;
41+
# missing/down sidecar yields a 502 from nginx, not a startup
42+
# crash (#390).
43+
- INFINITE_STREAM_ENABLE_ANALYTICS=1
44+
- INFINITE_STREAM_FORWARDER_HOST=forwarder
45+
- INFINITE_STREAM_GRAFANA_HOST=grafana
3946
tmpfs:
4047
- /go-live:size=4G,mode=755
4148
networks:
4249
- app_network
50+
depends_on:
51+
- clickhouse
52+
- forwarder
53+
- grafana
4354
restart: unless-stopped
4455
stop_grace_period: 1s
4556

57+
# ── Analytics sidecar (parity with base docker-compose.yml) ──────────
58+
# Same shape as the source-build path — only the images come from
59+
# GHCR instead of being built locally. ClickHouse + Grafana are
60+
# upstream public images either way.
61+
62+
clickhouse:
63+
image: clickhouse/clickhouse-server:24.8-alpine
64+
container_name: infinite-streaming-clickhouse
65+
environment:
66+
- CLICKHOUSE_DB=infinite_streaming
67+
- CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
68+
- CLICKHOUSE_SKIP_USER_SETUP=1
69+
# Loopback-only — same posture as base compose. Internal services
70+
# reach it via the bridge network; ad-hoc curl from the host uses
71+
# 127.0.0.1:30123. Never exposed on the LAN by default.
72+
ports:
73+
- "127.0.0.1:30123:8123"
74+
volumes:
75+
- ${CONTENT_DIR:-./sample-content}/analytics:/var/lib/clickhouse
76+
- ./analytics/clickhouse/init.d:/docker-entrypoint-initdb.d:ro
77+
networks:
78+
- app_network
79+
restart: unless-stopped
80+
81+
forwarder:
82+
image: ghcr.io/jonathaneoliver/infinite-streaming-forwarder:latest
83+
container_name: infinite-streaming-forwarder
84+
environment:
85+
- FORWARDER_SSE_URL=http://go-server:30081/api/sessions/stream
86+
- FORWARDER_CLICKHOUSE_URL=http://clickhouse:8123
87+
- FORWARDER_CLICKHOUSE_DB=infinite_streaming
88+
- FORWARDER_CLICKHOUSE_TABLE=session_snapshots
89+
volumes:
90+
- ${CONTENT_DIR:-./sample-content}/logs:/media/logs
91+
networks:
92+
- app_network
93+
depends_on:
94+
- clickhouse
95+
restart: unless-stopped
96+
97+
grafana:
98+
image: grafana/grafana-oss:11.3.0
99+
container_name: infinite-streaming-grafana
100+
environment:
101+
- GF_AUTH_ANONYMOUS_ENABLED=true
102+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
103+
- GF_AUTH_DISABLE_LOGIN_FORM=false
104+
- GF_INSTALL_PLUGINS=grafana-clickhouse-datasource
105+
- GF_SERVER_ROOT_URL=http://localhost:30000/grafana/
106+
- GF_SERVER_SERVE_FROM_SUB_PATH=true
107+
- GF_LIVE_ALLOWED_ORIGINS=*
108+
# No host port — reach Grafana through nginx at /grafana/ where
109+
# opt-in basic auth applies uniformly (see CLAUDE.md WAN runbook).
110+
volumes:
111+
- ./analytics/grafana/provisioning:/etc/grafana/provisioning:ro
112+
networks:
113+
- app_network
114+
restart: unless-stopped
115+
46116
networks:
47117
app_network:
48118
driver: bridge

docs/API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
The dashboard is a thin client over this API. Every fault-injection action, every shaping change, every session control the UI exposes is available here — so anything you can do in the browser, a test script or CI job can do too. There are no UI-only controls.
44

5-
All endpoints are exposed through nginx on port `30000` (Docker Compose and k3s release) or `40000` (k3s dev). nginx routes them to the backing service based on path.
5+
All endpoints are exposed through nginx on port `30000` (Docker Compose and k3d release) or `40000` (k3d dev). nginx routes them to the backing service based on path.
66

77
For the **fault-injection** surface (`/api/session/*` patch payloads, `/api/nftables/*` shaping), see [`docs/FAULT_INJECTION.md`](FAULT_INJECTION.md) — this page only summarises those endpoints and points to the full reference.
88

0 commit comments

Comments
 (0)