feat(muninn-gate): WG-internal Muninn ingestion front door stack (#377)
Deployed on corviduo-dev, co-located with the worldtree-personal muninn
watcher. ingestion_root=/data/state/ingestion (shared state volume, byte-
identical to the watcher); runs as uid 1000 to write the queue; staging
bound :ro at the ratified /mnt/muninn-staging/mimir-inbox (local placeholder
until the shared mount + mimir-inbox writer land). Boot verified: /ping
{"service":"ok"}, /health watcher.running=true (byte-identity proven).
Image built out-of-band with the Gitea read token as a BuildKit secret.
Real config (bearer keys) lives on-server at /opt/docker/conf 0600.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# muninn-gate — WG-internal HTTP front door for the Muninn ingestion queue (#377).
|
||||
# Deployed on corviduo-dev (10.250.50.152), co-located with the worldtree-personal
|
||||
# muninn watcher (worldtree-personal-worldtree-muninn-1). infra-ops-managed stack,
|
||||
# separate from the worldtree CI/CD compose.
|
||||
#
|
||||
# Image is built out-of-band (the Gitea read token rides as a BuildKit secret, so
|
||||
# it never lands in a layer) — see README.md:
|
||||
# DOCKER_BUILDKIT=1 docker build --secret id=gitea_pw,src=<token> -t muninn-gate:0.0.14 .
|
||||
#
|
||||
# Real config (with bearer-key secrets) lives on the server at
|
||||
# /opt/docker/conf/muninn-gate/muninn-gate.yaml (gitignored); repo carries the
|
||||
# redacted conf/muninn-gate.example.yaml.
|
||||
services:
|
||||
muninn-gate:
|
||||
image: muninn-gate:0.0.14
|
||||
container_name: muninn-gate
|
||||
restart: unless-stopped
|
||||
# Run as the ingestion-owner uid (vh, 1000:1000) so the gate can WRITE the
|
||||
# queue (ingestion dir is 1000:1000 0755). Overrides the image's build user;
|
||||
# non-root, least-privilege (no root needed — binds :8090, reads config +
|
||||
# staging, writes only ingestion). The mounted config is chowned 1000:1000 0600.
|
||||
user: "1000:1000"
|
||||
# WG-internal bind straight to the host WG address; the launcher owns the bind
|
||||
# (the app's `bind` field is observability-only). Host networking so --host/--port
|
||||
# land directly on corviduo-dev.
|
||||
network_mode: host
|
||||
command:
|
||||
- uvicorn
|
||||
- muninn_gate.entrypoint:app_factory
|
||||
- --factory
|
||||
- --host
|
||||
- "10.250.50.152"
|
||||
- --port
|
||||
- "8090"
|
||||
environment:
|
||||
MUNINN_GATE_CONFIG: /app/config/muninn-gate.yaml
|
||||
volumes:
|
||||
# ingestion_root = /data/state/ingestion — the SAME volume the personal muninn
|
||||
# watcher uses, byte-identical path in both containers (absolute-path agreement).
|
||||
# NOTE (hardening candidate): whole state volume per muninn-dev's spec; a subpath
|
||||
# mount of just `ingestion` -> /data/state/ingestion would be tighter (gate only
|
||||
# needs RW on ingestion). Flag to muninn-dev before adopting.
|
||||
- worldtree-personal_worldtree-state:/data/state
|
||||
# single-writer mounted config (bearer-key secrets), read-only:
|
||||
- /opt/docker/conf/muninn-gate/muninn-gate.yaml:/app/config/muninn-gate.yaml:ro
|
||||
# shared staging root — SAME absolute path as the watcher's bind, read-only
|
||||
# (gate only resolves + reads staging; never writes there):
|
||||
- /mnt/muninn-staging/mimir-inbox:/mnt/muninn-staging/mimir-inbox:ro
|
||||
healthcheck:
|
||||
# /ping is the one anonymous route; returns {"service":"ok"}. NB /health must
|
||||
# NOT be the liveness probe — it is always-200 by design even when the watcher
|
||||
# is down, so it would never restart the gate (it would wrongly signal the
|
||||
# watcher's container).
|
||||
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if b'ok' in urllib.request.urlopen('http://10.250.50.152:8090/ping', timeout=3).read() else 1)"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
labels:
|
||||
- homepage.group=Worldtree
|
||||
- homepage.name=Muninn Gate
|
||||
- homepage.icon=mdi-gate-arrow-right
|
||||
- homepage.description=Muninn ingestion queue front door (#377)
|
||||
- homepage.href=http://10.250.50.152:8090/ping
|
||||
|
||||
volumes:
|
||||
# The worldtree-personal muninn watcher's state volume — external, managed by the
|
||||
# worldtree-personal compose. We attach to it read/write for the ingestion queue.
|
||||
worldtree-personal_worldtree-state:
|
||||
external: true
|
||||
Reference in New Issue
Block a user