786462ac9c
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.
71 lines
3.4 KiB
YAML
71 lines
3.4 KiB
YAML
# 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
|