Add Unraid deployment via the Portainer API
ops/deploy.py ships each service's build context to the remote Docker daemon's /build endpoint and pushes docker-compose.prod.yml as a Portainer stack — there is no docker CLI in WSL and Unraid's SSH is closed. The prod compose file drops the dev bind mounts and uvicorn --reload, publishes only the frontend port (8000 is taken by Portainer's Edge tunnel), and pins bms_net to 172.31.42.0/24 because the host's default address pools are fully subnetted. Mosquitto's config is baked into an image since the repo is not checked out on the host. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d4a104be9d
commit
de9b8c51bd
5 changed files with 510 additions and 22 deletions
85
memory.md
Normal file
85
memory.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# BMS — memory
|
||||
|
||||
DCIM demo platform: Next.js 16 frontend, FastAPI backend, TimescaleDB, Mosquitto MQTT,
|
||||
and Python simulator bots that publish fake data-centre telemetry.
|
||||
|
||||
Live at **http://192.168.1.249:5646/dashboard** (Portainer stack `bms` on Unraid).
|
||||
|
||||
## Decisions & rationale
|
||||
|
||||
- **Auth is disabled (demo mode).** The repo shipped half-converted: `proxy.ts` already said
|
||||
"auth is disabled for demo mode", but `app/layout.tsx` still wrapped the tree in
|
||||
`<ClerkProvider>` and `topbar.tsx` used `<UserButton>`. `@clerk/nextjs` v7 fails `next build`
|
||||
without a real publishable key, so the frontend image could not build at all. Finished the
|
||||
conversion instead of buying Clerk keys: removed `ClerkProvider`/`UserButton`, deleted the
|
||||
`sign-in`/`sign-up` route groups, and dropped `@clerk/nextjs` from `package.json`. The service
|
||||
is LAN-only and reachable remotely over Tailscale, so the tailnet is the auth boundary.
|
||||
- **Deploy via the Portainer API, not compose-on-host.** No `docker` CLI in WSL and Unraid's
|
||||
SSH (port 22) is closed, so `ops/deploy.py` tars each service's build context, POSTs it to the
|
||||
remote daemon's `/build` endpoint, then pushes `docker-compose.prod.yml` as a Portainer stack.
|
||||
Same pattern as `toknmtr/ops/deploy.py`.
|
||||
- **Separate `docker-compose.prod.yml`.** The dev compose file bind-mounts source into the
|
||||
containers and runs `uvicorn --reload` — wrong for a long-running deploy, and impossible
|
||||
anyway since the repo is not checked out on the Unraid host. The prod file references
|
||||
prebuilt image tags, sets env inline (no `.env` files on the host), and publishes only the
|
||||
frontend's port.
|
||||
- **Mosquitto config is baked into an image** (`infra/mosquitto/Dockerfile`) rather than
|
||||
bind-mounted, for the same reason: no repo on the host.
|
||||
- **`bms_net` pins subnet 172.31.42.0/24.** Docker's default address pools on that host are
|
||||
fully subnetted — 24 existing stacks have claimed every `172.17-172.31/16` and
|
||||
`192.168.x/20` slot, so auto-allocation fails with "all predefined address pools have been
|
||||
fully subnetted". An explicit subnet bypasses the allocator without disturbing other stacks.
|
||||
Only other 172.31 tenant is `wg0` on 172.31.200.0/24.
|
||||
- **Postgres data bind-mounts to `/mnt/user/appdata/bms/db`**, not a named volume, so a
|
||||
growing timeseries DB lands on the array instead of filling Unraid's fixed-size `docker.img`.
|
||||
- **`pnpm-workspace.yaml` must be copied in the frontend Dockerfile's deps stage.** It carries
|
||||
the build-script allowlist; without it pnpm aborts with `ERR_PNPM_IGNORED_BUILDS`. The file
|
||||
now declares both `allowBuilds` (pnpm 11 spelling) and `ignoredBuiltDependencies` (pnpm 10).
|
||||
`sharp`, `unrs-resolver` and `msw` are all declined — the app has no `next/image`, so sharp
|
||||
is dead weight. `packageManager: pnpm@11.20.0` is pinned so a future pnpm release cannot
|
||||
silently change this again.
|
||||
|
||||
## Open questions / TODOs
|
||||
|
||||
- [ ] Postgres uses the repo's default credentials (`dcim`/`dcim_pass`). Fine while the DB has
|
||||
no published host port and the box is LAN-only, but change both the compose env and
|
||||
`DATABASE_URL` together if the port is ever exposed.
|
||||
- [ ] The simulator floods logs with `mqtt WARNING There are N pending publish calls.` — it
|
||||
publishes faster than aiomqtt drains. Cosmetic, but it makes `docker logs` near-useless
|
||||
and grows the log file. Worth batching or throttling the bots.
|
||||
- [ ] `backend/api/routes/ws.py` exists but nothing in the frontend opens a WebSocket (the UI
|
||||
polls every 15 s). Either wire it up or drop it. Note: Next.js rewrites do not proxy WS
|
||||
upgrades, so a WS client would need to reach the backend directly.
|
||||
- [ ] No host port is published for Postgres or MQTT. Add a `ports:` entry to
|
||||
`docker-compose.prod.yml` if direct DB access or external MQTT publishing is ever needed.
|
||||
- [ ] No reverse-proxy entry yet. Add an Nginx Proxy Manager host pointing at `:5646` if this
|
||||
should be reachable by name rather than IP:port.
|
||||
|
||||
## Session log
|
||||
|
||||
### 2026-08-04
|
||||
|
||||
- Cloned the Forgejo repo into `~/claude/projects/BMS` and deployed it to the Unraid host.
|
||||
- Finished the demo-mode auth conversion (see Decisions) so the frontend image could build;
|
||||
regenerated `pnpm-lock.yaml` without `@clerk/nextjs`. Verified `next build` locally — all
|
||||
18 routes prerender.
|
||||
- Hit and fixed three deploy blockers in order: (1) the frontend Dockerfile never copied
|
||||
`pnpm-workspace.yaml`, so pnpm's ignored-builds allowlist was invisible inside the build;
|
||||
(2) pnpm 11 renamed that setting to `allowBuilds` and ignores `ignoredBuiltDependencies`;
|
||||
(3) the Unraid daemon's Docker address pools were exhausted, so the stack network could not
|
||||
be created.
|
||||
- Backend's host port 8000 deliberately not published — Portainer's Edge tunnel already owns
|
||||
8000 on that host. Ports 1883/5433/5646 were free; only 5646 is published.
|
||||
- Added `ops/deploy.py`, `docker-compose.prod.yml`, `infra/mosquitto/Dockerfile`; updated the
|
||||
README (demo-mode note, Unraid deploy section) and both `.env` examples.
|
||||
- Verified live: all 5 containers healthy, 30 min of seeded history present, telemetry
|
||||
flowing, alarm engine firing (55 active), dashboard screenshotted and rendering correctly.
|
||||
|
||||
## External references
|
||||
|
||||
- Repo: https://git.rdx4.com/megaproxy/BMS
|
||||
- Live dashboard: http://192.168.1.249:5646/dashboard
|
||||
- API docs (Swagger): http://192.168.1.249:5646/api/backend/docs
|
||||
- Portainer (stack `bms`, endpoint id 3): http://192.168.1.249:9000 — token at `~/.portainer-token`
|
||||
- Postgres data on the host: `/mnt/user/appdata/bms/db`
|
||||
- Deploy pattern copied from: `~/claude/projects/toknmtr/ops/deploy.py`
|
||||
Loading…
Add table
Add a link
Reference in a new issue