Docker er driftsformen, ikke bare en testrigg

Announcer skal kjøre standalone på klienten som er koblet til anlegget, i
Docker – aldri på utviklingsmaskina. install.sh installerte nativt med apt
og uv, og det passer ikke lenger.

- install.sh er nå en Docker-bootstrap: installerer Docker om den mangler,
  lager .env med riktig bruker-ID og portbinding, oppretter data/, bygger,
  starter, og setter ufw. Den rydder også bort gamle native enheter, både
  announcer.service og sg-announcer.service.
- Dockerfile kopierer koden inn istedenfor å låne den fra et bind-mount, så
  det som kjører i drift er uavhengig av hva som ligger i mappa.
- Alt som skal overleve en ny container ligger i data/ på verten. Bind-mount
  og ikke navngitt volum, med vilje: da kan man lese
  data/logs/announcements.jsonl og slippe egne jingler i data/chimes/ uten å
  gå inn i containeren, og eierskapet følger brukeren istedenfor root.
- Testriggen er flyttet til compose.test.yaml, med eget prosjektnavn, så den
  ikke kan forveksles med eller forstyrre drift.

Lyden ut av containeren krever tre ting, og de er dokumentert i AGENTS.md:
hele XDG_RUNTIME_DIR montert inn (ikke bare pipewire-socketen – PulseAudio
trenger pulse/native og en cookie i samme mappe, og da virker begge
lydservere), user: PUID:PGID lik eieren av socketen, og en innlogget grafisk
økt. Containeren starter ved boot, altså før innlogging, så avspilling feiler
til noen logger inn – det retter seg selv, siden player_cmd() slås opp per
melding. Verifisert: lyden spiller fra driftscontaineren.

Brannmuren er den viktige endringen fra nativ tid. Dockers publiserte porter
settes opp i nat-tabellen, før ufws regler, så en ufw-regel på porten gjør
ingenting. Tilgangen styres nå av BIND_IP i .env, og install.sh setter den til
NetBird-adressen når wt0 finnes. ufw settes fortsatt for ssh, men er ikke
involvert i tilgangen til announcer.

Testriggen bindes nå til 127.0.0.1. Den sto med PIN 1234 publisert på
0.0.0.0, og gikk altså forbi ufw ut på LAN-et.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kent 2026-10-08 16:07:59 +02:00
parent 6aaa98d8b1
commit 6c1253f54c
7 changed files with 372 additions and 177 deletions

View file

@ -1,45 +1,53 @@
# Testoppsett, ikke produksjon: docker compose up --build
# Announcer i drift på klienten ved anlegget.
#
# http://localhost:8091 announcer (PIN + JWT + OIDC slått på)
# http://localhost:9000 dummy-IdP som later som den er crew-panelet
# ./install.sh setter opp alt, inkludert .env
# docker compose up -d senere, for hånd
#
# Porten er 8091 med vilje, så den ikke kolliderer med tjenesten på 8090.
name: announcer-test
# Testoppsettet med dummy-IdP ligger i compose.test.yaml, ikke her.
name: announcer
services:
announcer:
build: .
ports: ["8091:8090"]
user: "1000:1000"
environment:
ANNOUNCER_CONFIG: /app/docker/config.test.toml
# Buffer, logg og sesjonsnøkkel holdes utenfor repoet, så testing ikke
# blander seg med det den kjørende tjenesten eier.
ANNOUNCER_CACHE: /data/cache
ANNOUNCER_LOG: /data/logs/announcements.jsonl
ANNOUNCER_STATE: /data/instance
ANNOUNCER_VOICES: /app/voices
ANNOUNCER_JWT_SECRET: test-hemmelighet-kun-for-docker-ikke-bruk-ekte
ANNOUNCER_OIDC_CLIENT_SECRET: test-client-secret-kun-for-docker
# Må peke dit nettleseren ser appen, ellers blir OIDC-redirecten feil.
ANNOUNCER_PUBLIC_URL: http://localhost:8091
XDG_RUNTIME_DIR: /run/user/1000
volumes:
- .:/app
- ./.docker-data:/data
# Lyd: gir containeren vertens PipeWire. Kommenter ut hvis du bare
# skal teste innlogging og UI – da feiler avspilling, men ikke annet.
- /run/user/1000:/run/user/1000
depends_on: [idp]
image: announcer:local
restart: unless-stopped
# BIND_IP er sikkerhetsmekanismen her, ikke ufw. Dockers publiserte
# porter går forbi ufw, så en ufw-regel ville ikke stengt noen ute.
# install.sh setter den til NetBird-adressen når wt0 finnes.
ports:
- "${BIND_IP:-0.0.0.0}:${ANNOUNCER_PORT:-8090}:8090"
# Må være brukeren som eier lydsocketen på verten, ellers kommer det
# ingen lyd. install.sh fyller inn id -u / id -g.
user: "${PUID:-1000}:${PGID:-1000}"
idp:
build: .
ports: ["9000:9000"]
user: "1000:1000"
environment:
IDP_ISSUER: http://localhost:9000
IDP_CLIENT_ID: announcer
IDP_CLIENT_SECRET: test-client-secret-kun-for-docker
ANNOUNCER_SINK: ${ANNOUNCER_SINK:-}
ANNOUNCER_TITLE: ${ANNOUNCER_TITLE:-}
ANNOUNCER_PUBLIC_URL: ${ANNOUNCER_PUBLIC_URL:-}
# Hemmeligheter: hører i .env, ikke i config.toml.
ANNOUNCER_PIN: ${ANNOUNCER_PIN:-}
ANNOUNCER_JWT_SECRET: ${ANNOUNCER_JWT_SECRET:-}
ANNOUNCER_OIDC_CLIENT_SECRET: ${ANNOUNCER_OIDC_CLIENT_SECRET:-}
ANNOUNCER_SECRET_KEY: ${ANNOUNCER_SECRET_KEY:-}
XDG_RUNTIME_DIR: ${XDG_RUNTIME_DIR:-/run/user/1000}
volumes:
- .:/app
command: ["python", "docker/dummy_idp.py"]
# Stemmer, buffer, logg, sesjonsnøkkel, egne jingler og config.toml.
- ./data:/data
# Lyden. Hele XDG_RUNTIME_DIR, ikke bare én socket, så både
# PipeWire (pipewire-0) og PulseAudio (pulse/native + cookie) virker.
- ${XDG_RUNTIME_DIR:-/run/user/1000}:${XDG_RUNTIME_DIR:-/run/user/1000}
# Containeren starter ved boot, altså før noen er logget inn grafisk.
# Da finnes ikke lydsocketen ennå, og avspilling feiler. Det retter seg
# selv: player_cmd() slås opp per melding, så første utrop etter
# innlogging virker uten at noe må startes om.
healthcheck:
test: ["CMD", "python", "-c",
"import urllib.request;urllib.request.urlopen('http://127.0.0.1:8090/api/config',timeout=5)"]
interval: 30s
timeout: 10s
start_period: 180s # første oppstart laster ned ~670 MB stemmer
retries: 3