39da1d4a97
The board mixed tools with endpoints. A vLLM seat whose href is a /docs page
sat in the same band as ComfyUI; the MQTT broker and the RustDesk relay, which
have no page at all, sat in Apps; and `Service Networking` was thirteen members
spanning three AdGuards, five Dockges, two Traefiks and four headless agents.
Every group is now one of two kinds and they never mix. TOOLS are expanded and
sit at the top of their tab. ENDPOINTS — an API, a broker, a background agent,
an href that is /docs or /ping or nothing — carry `initiallyCollapsed: true`
and sit at the bottom. Collapsed is not hidden: the eyebrow and its rule still
render, so the tab still says the thing exists and one click expands it.
A second rule fell out of the same pass and now shapes the group boundaries: a
group's members should all carry a widget or none should. A stat strip makes a
card ~50px taller, so one widget card in a row of plain ones opens a void under
the plain ones. That is why AdGuard and Traefik get their own groups rather
than sharing one with Dockge, and it is most of why the old Service Networking
band looked broken. AdGuard (ANA) was the last short card in its row and now
carries the same query/blocked/latency strip as its two siblings — one
infra-ops AdGuard login authenticates against all three instances, verified
against each; it lives in that stack's .env on the host and is vaulted.
The sixteen GPU-backed model seats were deliberately NOT relabelled.
`homepage.group` is read at container creation, so clearer names for
`AI - Inference` and friends would have cost a recreate on six vLLM seats, four
eval seats and four TTS engines — multi-minute model reloads on endpoints peers
reach through the gateway. Order plus `initiallyCollapsed` buys the same
separation for nothing, so those names stay as they are on purpose.
28 containers that ARE cheap to bounce were relabelled, across five hosts, via
rerunnable elway playbooks. Their label steps are gated on the old value still
being present, so a second run reports skipped rather than churning. Two verify
steps were wrong on first contact and are fixed with the reason recorded: the
traefik check raced its own recreate, and asserting a model seat is "running"
cannot answer "did I bounce it" when a seat may be legitimately stopped —
container age can, and now does.
The canonical stacks/ tree was synced to the deployed labels afterwards, so
intent and reality agree again on all fourteen tracked stacks.
Also documents the real nature of the post-recreate blank dashboard, which cost
~25 minutes here and an hour on 2026-08-19. `initialSettings":{}` in the served
HTML is the catch branch of the page's data loader, not a warm-up and not a
cache — and the error can vanish entirely, because the logger is assigned inside
the same try and the catch only logs if the logger exists. Ruled out by
measurement this time: all four API routes return 200 with correct content while
the page serves {}, and the previous known-good settings.yaml reproduces it
identically. The README now carries the one-command test and the next lead.
Before/after, all four tabs: http://10.100.10.50:8090/b/homepage-relayout/
104 lines
5.1 KiB
YAML
104 lines
5.1 KiB
YAML
# Arbo (catalog) engine — FastAPI sidecar that drives ComfyUI from a
|
|
# versioned workflow catalog. Serves the SPA + /workflows + /run.
|
|
#
|
|
# Co-located on irv-ml1 BESIDE the comfyui stack (ADR-0001 / D3). This
|
|
# collapses the engine<->ComfyUI link to the shared traefik-net + the
|
|
# local filesystem and ELIMINATES the old SSH/WireGuard dependency:
|
|
# - generation : COMFYUI_URL=http://comfyui:8188 (container DNS on
|
|
# traefik-net — the "localhost-equivalent"; no scp, no WG hop)
|
|
# - file ops : ARBO_COMFY_INPUT_DIR / ARBO_COMFY_OUTPUT_DIR bind the
|
|
# SAME host dirs comfyui mounts (/worktank/comfyui/basedir/{input,
|
|
# output}), so to-input / upload-input / artifact-wipe are local fs
|
|
# ops. ARBO_COMFY_SSH_HOST is left UNSET on purpose → the engine's
|
|
# local-cp/shutil path (comfy-dev's D3 follow-on) takes over.
|
|
#
|
|
# State that MUST survive restarts (named volumes, local disk — NOT NFS,
|
|
# per the DB-off-NFS rule; SQLite-on-NFS locking is a known foot-gun):
|
|
# - arbo_db -> the gallery/history SQLite (ARBO_DB)
|
|
# - arbo_heroes -> runtime hero images (ARBO_HEROES_DIR)
|
|
# The catalog is a comfy-dev git checkout bind-mounted read-only (D2):
|
|
# a workflow update = `git pull` on the host + restart, no image rebuild.
|
|
#
|
|
# IMAGE + CATALOG TARGET are owned by comfy-dev (they build the image +
|
|
# add /healthz). Two items marked CONFIRM below need their image layout.
|
|
# All tunables live in .env — edit that, not this file.
|
|
|
|
services:
|
|
engine:
|
|
image: ${ARBO_IMAGE} # CONFIRM: gitea.phasefinal.com/vh/arbo:<tag>, comfy-dev builds
|
|
container_name: arbo
|
|
restart: unless-stopped
|
|
# Run as the host owner of /worktank (1000:1000 = lkraven) so writes
|
|
# into comfyui's basedir/input + the named volumes land with the
|
|
# right ownership (matches the comfyui stack's WANTED_UID posture).
|
|
user: "${ARBO_UID:-1000}:${ARBO_GID:-1000}"
|
|
ports:
|
|
- "${ARBO_BIND:-0.0.0.0}:${ARBO_PORT:-8200}:8200"
|
|
env_file: .env
|
|
environment:
|
|
- ARBO_HOST=0.0.0.0
|
|
- ARBO_PORT=8200
|
|
- ARBO_DB=/data/gallery.sqlite
|
|
- ARBO_HEROES_DIR=/heroes
|
|
# engine<->ComfyUI over the shared network (no SSH):
|
|
- COMFYUI_URL=http://comfyui:8188
|
|
- ARBO_COMFY_INPUT_DIR=/comfy/input
|
|
- ARBO_COMFY_OUTPUT_DIR=/comfy/output
|
|
# ARBO_COMFY_SSH_HOST intentionally UNSET -> local-cp path (D3 follow-on)
|
|
# LiteLLM gateway for the granite hero/metadata calls:
|
|
- GRANITE_ENDPOINT=http://10.250.50.70:4000/v1
|
|
- GRANITE_KEY=${GRANITE_KEY} # arbo-prompt-enhance scoped vkey (.env)
|
|
# ENGINE_TOKEN intentionally NOT injected — bearer auth is OFF on prod by
|
|
# operator decision (2026-06-13); WireGuard is the access boundary. The
|
|
# app's protected-gate no-ops only when the var is ABSENT — an empty string
|
|
# still gates — so it must not be set here OR in .env. Re-enable: restore
|
|
# this line + set ENGINE_TOKEN in .env, then `compose up -d`. Reverses ADR-0001.
|
|
#- ENGINE_TOKEN=${ENGINE_TOKEN}
|
|
volumes:
|
|
- arbo_db:/data
|
|
- arbo_heroes:/heroes
|
|
# comfyui's input/output, shared on the host (rw: upload-input writes
|
|
# input, artifact-wipe deletes output):
|
|
- /worktank/comfyui/basedir/input:/comfy/input
|
|
- /worktank/comfyui/basedir/output:/comfy/output
|
|
# comfy-dev checkout on the host (D2 git-pull target), read-only. catalog +
|
|
# graphs + frontend all ride the mount, so a catalog OR SPA change reaches
|
|
# prod via `git pull + restart` — no image rebuild (ADR-0001 D2, extended to
|
|
# the frontend per the v0.11.2 prod fix). Baked image copies are the fallback.
|
|
- ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/catalog:/app/catalog:ro
|
|
- ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/graphs:/app/graphs:ro
|
|
- ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/frontend:/app/frontend:ro
|
|
# pyproject.toml rides the same checkout mount so /healthz catalog_version
|
|
# reports the MOUNTED repo version (read from /app/pyproject.toml), not the
|
|
# baked importlib.metadata one — otherwise a catalog/frontend-only webhook
|
|
# deploy (no image rebuild) leaves the reported version stale (comfy-dev
|
|
# v0.12.5 observability fix, 2026-06-16). Activated on the next engine
|
|
# recreate; the code falls back cleanly if the file is absent.
|
|
- ${ARBO_CATALOG_DIR:-/worktank/arbo/repo}/pyproject.toml:/app/pyproject.toml:ro
|
|
# python-based (the slim image ships no curl/wget; python is always present):
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8200/healthz').status==200 else 1)\""]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
networks:
|
|
- tnet
|
|
labels:
|
|
- homepage.group=AI - Studios
|
|
- homepage.name=Arbo
|
|
- homepage.icon=mdi-image-multiple-outline
|
|
- homepage.description=Catalog-driven ComfyUI engine (irv-ml1)
|
|
- homepage.href=http://10.100.79.3:${ARBO_PORT:-8200}
|
|
|
|
volumes:
|
|
arbo_db:
|
|
name: arbo_db
|
|
arbo_heroes:
|
|
name: arbo_heroes
|
|
|
|
networks:
|
|
tnet:
|
|
name: traefik-net
|
|
external: true
|