refactor(prometheus,stoat): prefix service names so instances are possible
Both apps were barred from multiple instances by the same rule: a service or container name with no <app> prefix cannot be made unique per instance, so a second copy would fight the first for it. Prometheus is now fully unblocked. node-exporter and cadvisor became prometheus-node-exporter and prometheus-cadvisor — service key, container_name and SERVICE_TAG default together — and prometheus.yml's scrape targets follow them. The image references (prom/node-exporter, gcr.io/cadvisor/cadvisor) and the job_name labels are deliberately untouched: the first are upstream coordinates, the second are labels dashboards and alert rules key off, and renaming either would break something to fix nothing. Stoat's sixteen services are now all stoat-prefixed. Its container_names already were, so only the service keys and their depends_on references moved. The subtlety is DNS: compose registers the service name as a network alias, so renaming a key silently retires the name anything else resolves it by — Revolt.toml reaches the broker as "rabbit", the Caddyfile proxies to api, events, autumn, january and gifbox, and the bucket job talks to http://minio:9000. Ten services already carried an explicit alias that survives the rename; the six that did not (database, redis, rabbit, createbuckets, crond, pushd) have been given one holding their old short name. Every name that resolved before still resolves. Verified by parsing the result: 16 services, every one keeping its short alias, and no dangling depends_on in either app. Stoat stays non-instanceable, but for one narrower reason now, recorded in its config: LiveKit advertises its own tcp_port 7881 and UDP range 50000-50100 to clients from livekit.yml, so those cannot be randomised per instance without generating that file per instance and allocating a range for each. Stoat's port descriptors name their parent service, so they follow the rename too: caddy -> stoat-caddy, livekit -> stoat-livekit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3ebd4ee5bb
commit
acc91777c4
@ -44,8 +44,8 @@ services:
|
||||
# network_mode: "container:gluetun-service"
|
||||
# GLUETUN_ON_END
|
||||
|
||||
node-exporter: #LIBREPORTAL|SERVICE_TAG_2|node-exporter
|
||||
container_name: node-exporter
|
||||
prometheus-node-exporter: #LIBREPORTAL|SERVICE_TAG_2|prometheus-node-exporter
|
||||
container_name: prometheus-node-exporter
|
||||
image: prom/node-exporter
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@ -57,8 +57,8 @@ services:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_2 #LIBREPORTAL|IP_TAG_2|IP_DATA_2
|
||||
|
||||
cadvisor: #LIBREPORTAL|SERVICE_TAG_3|cadvisor
|
||||
container_name: cadvisor
|
||||
prometheus-cadvisor: #LIBREPORTAL|SERVICE_TAG_3|prometheus-cadvisor
|
||||
container_name: prometheus-cadvisor
|
||||
image: gcr.io/cadvisor/cadvisor
|
||||
restart: unless-stopped
|
||||
privileged: true
|
||||
|
||||
@ -15,8 +15,7 @@ CFG_PROMETHEUS_APP_NAME=prometheus
|
||||
# (own data/DB/subdomain/backups) via `libreportal instance create`. Only set on
|
||||
# apps whose compose identity (container_name, Traefik routers, backup labels)
|
||||
# is instance-safe — see scripts/instance/instance_create.sh.
|
||||
# Not instance-safe. Declares node-exporter and cadvisor, names with no "prometheus" prefix, which cannot be made unique per instance.
|
||||
CFG_PROMETHEUS_MULTI_INSTANCE=false
|
||||
CFG_PROMETHEUS_MULTI_INSTANCE=true
|
||||
CFG_PROMETHEUS_BACKUP=true
|
||||
CFG_PROMETHEUS_BACKUP_STRATEGY=auto
|
||||
CFG_PROMETHEUS_UPDATE_TYPE=auto
|
||||
|
||||
@ -16,8 +16,8 @@ scrape_configs:
|
||||
|
||||
- job_name: 'node-exporter'
|
||||
static_configs:
|
||||
- targets: ['node-exporter:9100']
|
||||
- targets: ['prometheus-node-exporter:9100']
|
||||
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
- targets: ['prometheus-cadvisor:8080']
|
||||
|
||||
@ -35,7 +35,7 @@ services:
|
||||
# Upstream's healthcheck is kept rather than the LibrePortal HEALTHCHECK_TAG:
|
||||
# half the stack uses `depends_on: condition: service_healthy` against it, so
|
||||
# disabling the healthcheck would deadlock the boot order. Same for rabbit.
|
||||
database: #LIBREPORTAL|SERVICE_TAG_1|database
|
||||
stoat-database: #LIBREPORTAL|SERVICE_TAG_1|stoat-database
|
||||
container_name: stoat-database
|
||||
image: mongo:8.0 #LIBREPORTAL|STOAT_MONGO_VERSION_TAG|8.0
|
||||
restart: unless-stopped
|
||||
@ -58,9 +58,11 @@ services:
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_1 #LIBREPORTAL|IP_TAG_1|IP_DATA_1
|
||||
aliases:
|
||||
- database
|
||||
|
||||
# Valkey — event message broker and KV store.
|
||||
redis: #LIBREPORTAL|SERVICE_TAG_2|redis
|
||||
stoat-redis: #LIBREPORTAL|SERVICE_TAG_2|stoat-redis
|
||||
container_name: stoat-redis
|
||||
image: valkey/valkey:9-alpine #LIBREPORTAL|STOAT_VALKEY_VERSION_TAG|9-alpine
|
||||
restart: unless-stopped
|
||||
@ -69,9 +71,11 @@ services:
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_2 #LIBREPORTAL|IP_TAG_2|IP_DATA_2
|
||||
aliases:
|
||||
- redis
|
||||
|
||||
# RabbitMQ — internal message broker (push notifications, voice events).
|
||||
rabbit: #LIBREPORTAL|SERVICE_TAG_3|rabbit
|
||||
stoat-rabbit: #LIBREPORTAL|SERVICE_TAG_3|stoat-rabbit
|
||||
container_name: stoat-rabbit
|
||||
image: rabbitmq:4-alpine #LIBREPORTAL|STOAT_RABBITMQ_VERSION_TAG|4-alpine
|
||||
restart: unless-stopped
|
||||
@ -90,13 +94,15 @@ services:
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_3 #LIBREPORTAL|IP_TAG_3|IP_DATA_3
|
||||
aliases:
|
||||
- rabbit
|
||||
|
||||
# MinIO — S3-compatible object storage for uploads and avatars.
|
||||
#
|
||||
# The bucket-name aliases are load-bearing: the file server addresses
|
||||
# buckets virtual-host style (<bucket>.minio), so without these the DNS
|
||||
# lookup fails and every upload errors.
|
||||
minio: #LIBREPORTAL|SERVICE_TAG_4|minio
|
||||
stoat-minio: #LIBREPORTAL|SERVICE_TAG_4|stoat-minio
|
||||
container_name: stoat-minio
|
||||
image: minio/minio:latest #LIBREPORTAL|STOAT_MINIO_VERSION_TAG|latest
|
||||
restart: unless-stopped
|
||||
@ -125,11 +131,11 @@ services:
|
||||
|
||||
# One-shot: creates the uploads bucket, then exits. Not a failure when you
|
||||
# see it stopped.
|
||||
createbuckets: #LIBREPORTAL|SERVICE_TAG_5|createbuckets
|
||||
stoat-createbuckets: #LIBREPORTAL|SERVICE_TAG_5|stoat-createbuckets
|
||||
container_name: stoat-createbuckets
|
||||
image: minio/mc:latest #LIBREPORTAL|STOAT_MINIO_MC_VERSION_TAG|latest
|
||||
depends_on:
|
||||
- minio
|
||||
- stoat-minio
|
||||
# Credentials come in through the environment rather than being written
|
||||
# into the entrypoint: a #LIBREPORTAL annotation only substitutes on the
|
||||
# line it sits on, and inside a folded block scalar it would end up as
|
||||
@ -150,10 +156,12 @@ services:
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_5 #LIBREPORTAL|IP_TAG_5|IP_DATA_5
|
||||
aliases:
|
||||
- createbuckets
|
||||
|
||||
# Caddy — internal path router for the whole stack. This is the only service
|
||||
# Traefik talks to, and the only one carrying a Traefik router.
|
||||
caddy: #LIBREPORTAL|SERVICE_TAG_6|caddy
|
||||
stoat-caddy: #LIBREPORTAL|SERVICE_TAG_6|stoat-caddy
|
||||
container_name: stoat-caddy
|
||||
image: caddy:2-alpine #LIBREPORTAL|STOAT_CADDY_VERSION_TAG|2-alpine
|
||||
restart: unless-stopped
|
||||
@ -198,17 +206,17 @@ services:
|
||||
# GLUETUN_ON_END
|
||||
|
||||
# API server.
|
||||
api: #LIBREPORTAL|SERVICE_TAG_7|api
|
||||
stoat-api: #LIBREPORTAL|SERVICE_TAG_7|stoat-api
|
||||
container_name: stoat-api
|
||||
image: ghcr.io/stoatchat/api:v0.15.1 #LIBREPORTAL|STOAT_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
stoat-redis:
|
||||
condition: service_started
|
||||
rabbit:
|
||||
stoat-rabbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
@ -219,15 +227,15 @@ services:
|
||||
- api
|
||||
|
||||
# Websocket / events service.
|
||||
events: #LIBREPORTAL|SERVICE_TAG_8|events
|
||||
stoat-events: #LIBREPORTAL|SERVICE_TAG_8|stoat-events
|
||||
container_name: stoat-events
|
||||
image: ghcr.io/stoatchat/events:v0.15.1 #LIBREPORTAL|STOAT_EVENTS_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
stoat-redis:
|
||||
condition: service_started
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
@ -238,15 +246,15 @@ services:
|
||||
- events
|
||||
|
||||
# Autumn — file server.
|
||||
autumn: #LIBREPORTAL|SERVICE_TAG_9|autumn
|
||||
stoat-autumn: #LIBREPORTAL|SERVICE_TAG_9|stoat-autumn
|
||||
container_name: stoat-autumn
|
||||
image: ghcr.io/stoatchat/file-server:v0.15.1 #LIBREPORTAL|STOAT_AUTUMN_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
createbuckets:
|
||||
stoat-createbuckets:
|
||||
condition: service_started
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
@ -257,7 +265,7 @@ services:
|
||||
- autumn
|
||||
|
||||
# January — link metadata and image proxy.
|
||||
january: #LIBREPORTAL|SERVICE_TAG_10|january
|
||||
stoat-january: #LIBREPORTAL|SERVICE_TAG_10|stoat-january
|
||||
container_name: stoat-january
|
||||
image: ghcr.io/stoatchat/proxy:v0.15.1 #LIBREPORTAL|STOAT_JANUARY_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
@ -272,7 +280,7 @@ services:
|
||||
|
||||
# Gifbox — Tenor proxy for the GIF picker. Inert until a Tenor API key is
|
||||
# added to secrets.env; see the upstream Guides.md.
|
||||
gifbox: #LIBREPORTAL|SERVICE_TAG_11|gifbox
|
||||
stoat-gifbox: #LIBREPORTAL|SERVICE_TAG_11|stoat-gifbox
|
||||
container_name: stoat-gifbox
|
||||
image: ghcr.io/stoatchat/gifbox:v0.15.1 #LIBREPORTAL|STOAT_GIFBOX_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
@ -286,51 +294,55 @@ services:
|
||||
- gifbox
|
||||
|
||||
# Scheduled task daemon.
|
||||
crond: #LIBREPORTAL|SERVICE_TAG_12|crond
|
||||
stoat-crond: #LIBREPORTAL|SERVICE_TAG_12|stoat-crond
|
||||
container_name: stoat-crond
|
||||
image: ghcr.io/stoatchat/crond:v0.15.1 #LIBREPORTAL|STOAT_CROND_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
stoat-minio:
|
||||
condition: service_started
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_12 #LIBREPORTAL|IP_TAG_12|IP_DATA_12
|
||||
aliases:
|
||||
- crond
|
||||
|
||||
# Push notification daemon.
|
||||
pushd: #LIBREPORTAL|SERVICE_TAG_13|pushd
|
||||
stoat-pushd: #LIBREPORTAL|SERVICE_TAG_13|stoat-pushd
|
||||
container_name: stoat-pushd
|
||||
image: ghcr.io/stoatchat/pushd:v0.15.1 #LIBREPORTAL|STOAT_PUSHD_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
stoat-redis:
|
||||
condition: service_started
|
||||
rabbit:
|
||||
stoat-rabbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_13 #LIBREPORTAL|IP_TAG_13|IP_DATA_13
|
||||
aliases:
|
||||
- pushd
|
||||
|
||||
# Voice ingress daemon — receives LiveKit's webhooks.
|
||||
voice-ingress: #LIBREPORTAL|SERVICE_TAG_14|voice-ingress
|
||||
stoat-voice-ingress: #LIBREPORTAL|SERVICE_TAG_14|stoat-voice-ingress
|
||||
container_name: stoat-voice-ingress
|
||||
image: ghcr.io/stoatchat/voice-ingress:v0.15.1 #LIBREPORTAL|STOAT_VOICE_INGRESS_VERSION_TAG|v0.15.1
|
||||
restart: unless-stopped
|
||||
env_file: secrets.env
|
||||
depends_on:
|
||||
database:
|
||||
stoat-database:
|
||||
condition: service_healthy
|
||||
rabbit:
|
||||
stoat-rabbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./Revolt.toml:/Revolt.toml:ro
|
||||
@ -351,13 +363,13 @@ services:
|
||||
# to work from outside the LAN:
|
||||
# sudo ufw allow 50000:50100/udp
|
||||
# Voice still falls back to TCP 7881 without it, at the cost of latency.
|
||||
livekit: #LIBREPORTAL|SERVICE_TAG_15|livekit
|
||||
stoat-livekit: #LIBREPORTAL|SERVICE_TAG_15|stoat-livekit
|
||||
container_name: stoat-livekit
|
||||
image: ghcr.io/stoatchat/livekit-server:v1.9.13 #LIBREPORTAL|STOAT_LIVEKIT_VERSION_TAG|v1.9.13
|
||||
restart: unless-stopped
|
||||
command: --config /etc/livekit.yml
|
||||
depends_on:
|
||||
redis:
|
||||
stoat-redis:
|
||||
condition: service_started
|
||||
ports:
|
||||
- "PORTS_DATA_2" #LIBREPORTAL|PORTS_TAG_2|PORTS_DATA_2
|
||||
@ -371,7 +383,7 @@ services:
|
||||
- livekit
|
||||
|
||||
# The web client itself. Served by Caddy at /.
|
||||
web: #LIBREPORTAL|SERVICE_TAG_16|web
|
||||
stoat-web: #LIBREPORTAL|SERVICE_TAG_16|stoat-web
|
||||
container_name: stoat-web
|
||||
image: ghcr.io/stoatchat/for-web:0c31cf0 #LIBREPORTAL|STOAT_WEB_VERSION_TAG|0c31cf0
|
||||
restart: unless-stopped
|
||||
|
||||
@ -18,7 +18,12 @@ CFG_STOAT_APP_NAME=stoat
|
||||
# (own data/DB/subdomain/backups) via `libreportal instance create`. Only set on
|
||||
# apps whose compose identity (container_name, Traefik routers, backup labels)
|
||||
# is instance-safe — see scripts/instance/instance_create.sh.
|
||||
# Not instance-safe. Pins LiveKit to host port 7881, and declares database/redis/rabbit/minio and friends — names with no "stoat" prefix that cannot be made unique per instance.
|
||||
# Not instance-safe, for ONE remaining reason. The service names are now all
|
||||
# stoat-prefixed, so compose identity is no longer the blocker. What is: LiveKit
|
||||
# advertises its own tcp_port (7881) and UDP range (50000-50100) to clients from
|
||||
# livekit.yml, so those cannot be randomised per instance without generating that
|
||||
# file per instance and allocating a UDP range for each. Until then a second copy
|
||||
# could not bind 7881.
|
||||
CFG_STOAT_MULTI_INSTANCE=false
|
||||
# No prerequisites. Stoat bakes its public URL into the client bundle, but that
|
||||
# URL can just as well be http://<lan-ip>:<port> — text chat, channels, roles
|
||||
@ -97,12 +102,12 @@ CFG_STOAT_NETWORK=default
|
||||
#
|
||||
# Only one HTTP port: Caddy fronts the entire stack internally, so /api, /ws,
|
||||
# /autumn and the rest all arrive on this single host.
|
||||
CFG_STOAT_PORT_1="caddy|webui|random:80|public|tcp|false|true|true|Web Interface||stoat"
|
||||
CFG_STOAT_PORT_1="stoat-caddy|webui|random:80|public|tcp|false|true|true|Web Interface||stoat"
|
||||
# LiveKit's TCP fallback. Pinned rather than random on purpose: LiveKit
|
||||
# advertises this exact port number to clients from livekit.yml, so a randomised
|
||||
# external port would be advertised wrongly and voice would fail to connect.
|
||||
# Not Traefik-managed — WebRTC is not HTTP.
|
||||
CFG_STOAT_PORT_2="livekit|voice-tcp|7881:7881|public|tcp|false|false|false|LiveKit voice/video (TCP fallback)|"
|
||||
CFG_STOAT_PORT_2="stoat-livekit|voice-tcp|7881:7881|public|tcp|false|false|false|LiveKit voice/video (TCP fallback)|"
|
||||
|
||||
# Stoat exposes no safe way to set a password or grant a role from outside the
|
||||
# app, so these tools list and enable/disable only — see scripts/stoat_auth.sh.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user