ADR-011: статика игры вынесена из куба на nginx (LXC 152 game-web), версии каталогами
- корень smart-updown.binom.pw -> nginx на Proxmox (LXC 152, 192.168.76.152) - /api,/ws -> куб (router PathPrefix на внешнем Traefik VDS), куб не менялся - версионирование: /opt/game/releases/<N>/, активная = симлинк /opt/game/current - tools/proxmox-nginx: unpack-release.sh, publish-release.sh, game.nginx.conf, smart-updown.traefik.yaml, README - приёмка живьём: корень 200 nginx/1.24.0 (Ubuntu), /27/ /28/ 200, /api/state 200 JSON, /api/ws цена, autoclose-check 9/9 - питфоллы: OCI-manifest в skopeo dir-дампе, слэш в конце версии, /solana-rpc мимо PathPrefix /api
This commit is contained in:
@@ -203,3 +203,58 @@
|
||||
(отдать фронтендеру, см. `TASKS.md`).
|
||||
|
||||
---
|
||||
|
||||
## ADR-011 — Статика игры вынесена из куба на nginx (LXC 152), версии — каталогами (2026-09-15)
|
||||
|
||||
**Контекст.** До этого и корень, и `/api`,`/ws` жили в кубе: внешний Traefik (VDS) вёл весь домен
|
||||
`smart-updown.binom.pw` на k3s `192.168.76.120`, статику отдавал под `fun-game-front2`
|
||||
(nginx внутри образа), API — отдельный ingress `smart-updown-api` → TS-шлюз `:8895`.
|
||||
Владелец решил **разделить плоскости**: бэк честно деплоится в куб, а сама игра (статика)
|
||||
раздаётся с nginx, развёрнутого на Proxmox — со **версионированием по каталогам** (`/<номер>/`).
|
||||
|
||||
**Решение:**
|
||||
1. **nginx на Proxmox** — новый LXC **152** (`game-web`, 192.168.76.152, Ubuntu 24.04, 2 ядра,
|
||||
1 ГБ RAM, диск 8 GB на `local-lvm`, `onboot=1`, unprivileged). Отдельный LXC потому, что
|
||||
статика игры — «10 строк конфига и каталог», держать её в кубе рядом с бэком смысла нет.
|
||||
2. **Версионирование каталогами:**
|
||||
- `/opt/game/releases/<N>/` — файлы сборки N (`Build/`, `TemplateData/`, `index.html`);
|
||||
- `/opt/game/current` — симлинк на активную сборку;
|
||||
- `https://smart-updown.binom.pw/` → активная сборка, `/28/…` → конкретная сборка.
|
||||
3. **Маршрутизация на внешнем Traefik (VDS)** — два router'а на один host, вместо одного:
|
||||
- `smart-updown-api-router`: `Host(...) && (PathPrefix('/api') || PathPrefix('/ws'))` → `192.168.76.120` (куб);
|
||||
- `smart-updown-router`: `Host(...)` → `192.168.76.152` (nginx на проксмоксе).
|
||||
PathPrefix-роутер специфичнее Host-роутера, поэтому `/api`,`/ws` **не перехватываются статикой**.
|
||||
IP LXC 152 достижим с VDS через wg-туннель (192.168.76.0/22 dev wg0).
|
||||
4. **В кубе ничего не менялось**: `ingress smart-updown-api` (`/api`,`/ws` → шлюз) как был, вне helm.
|
||||
Под `fun-game-front2` остался жив, но домен он больше не обслуживает (статика ушла на nginx) —
|
||||
в куб его релизить больше не обязательно; релизы — только доставка статики на nginx.
|
||||
5. **Инструменты** (`tools/proxmox-nginx/`): `unpack-release.sh` (распаковка dir-дампа образа в
|
||||
`releases/<N>`), `publish-release.sh` (тянет образ из реестра, раскладывает, по `--activate`
|
||||
переключает `current`), `game.nginx.conf`, `smart-updown.traefik.yaml`.
|
||||
|
||||
**Питфоллы, пойманные живьём:**
|
||||
- `skopeo copy docker://… dir:` кладёт слои по **sha256-digest**, а `manifest.json` — это **OCI-манифест**
|
||||
(словарь `layers[].digest`, не список строк как в docker-archiv). Парсить `json['layers'][i]['digest']`,
|
||||
а не печатать элемент целиком (иначе `tar: Cannot connect to {'mediaType': ...}`).
|
||||
- Голый шаблон `/28` (без слэша) отдаёт **301** — это `try_files ... /$build$subpath/`, т.е. редирект
|
||||
на `/28/`. Для относительных путей Unity (`src="Build/WebGL.loader.js"`) важно, чтобы **браузерный
|
||||
URL заканчивался слэшем**; иначе `Build/...` уедет в `/Build/...` и вернётся 404. Ссылаться на
|
||||
версии только со слэшем (`/28/`), либо ставить редирект в nginx (`return 301 /$build/`).
|
||||
- `/solana-rpc/` **не** перехватывается PathPrefix `/api` — это отдельный path, и на VDS он уходит
|
||||
в корневой router (nginx). Поэтому страховочный `location /solana-rpc/` в nginx нужен: старые сборки
|
||||
игры стучатся именно туда (проверено: `getHealth` → `ok` через домен).
|
||||
- Имена ассетов Unity внутри сборки не меняются (`WebGL.data`/`.wasm`/`.framework.js`), но теперь
|
||||
URL содержит номер сборки → `immutable`-кэш больше не «прилипает» между релизами (закрыт остаточный
|
||||
риск из ADR-010). Внутри одной версии ассеты неизменяемы, т.к. каталог версии не перезаписывается.
|
||||
|
||||
**Приёмка (живой домен, 2026-09-15):** корень `/` → 200 от `nginx/1.24.0 (Ubuntu)` (LXC 152);
|
||||
`/27/`,`/28/` → 200, ассеты версий различаются (md5 `WebGL.data`: `76b6f3…` vs `47453d…`);
|
||||
`/api/state` → 200 JSON (куб), `/api/ws` → `[open]` + `{"type":"price"}`; сквозной
|
||||
`tools/autoclose-check.cjs` на `BASE=https://smart-updown.binom.pw/api` — **9/9**; `testfront` не задет.
|
||||
Откат: вернуть `/opt/traefik/static/smart-updown.yaml` из бэкапа VDS
|
||||
(`/root/bak-smart-updown-nginx-2026-09-15/`) — домен снова целиком уйдёт в куб.
|
||||
|
||||
**Альтернативы:** (а) оставить статику в кубе и версионировать каталогами внутри образа — тянет
|
||||
пересборку образа на каждый билд игры и не решает вопрос кэша; (б) поднять в LXC не nginx, а
|
||||
podman-контейнер с nginx — лишний слой на 10 строках конфига; (в) отдавать статику прямо с k3s-Traefik
|
||||
по PVC — не то, о чём просил владелец (он хотел nginx на проксмоксе).
|
||||
|
||||
Reference in New Issue
Block a user