Inbetriebnahme auf Prod: Checkliste und zwei Umgebungsdateien
Die Unit las bisher nur p2.env. Auf Prod steht die Datenbankverbindung
schon in ~/.config/wurzelwerk/database.env und gehoert Phase 1 mit; die
Unit liest jetzt beide, database.env zuerst. p2.env kann DATABASE_URL
ueberschreiben, falls database.env auf 127.0.0.1 zeigt - aus dem
Container heraus laeuft das ins Leere, dort muss
host.containers.internal stehen.
deploy/INBETRIEBNAHME.md haelt die Reihenfolge fest. Zwei Schritte darin
sind nicht offensichtlich und beide teuer, wenn man sie auslaesst:
lexikon.py --laden akteure.py liest aus den Tabellen, nicht aus den
JSON-Dateien. Ohne diesen Schritt laeuft Modul 4
durch und loest nichts auf, ohne zu scheitern.
Erstbestand von Hand Der erste Lauf laedt 2,2 GB Modellgewichte und
kodiert den gesamten Korpus, ~17 min je 5000
Items. Aus dem Timer heraus liefe er in
TimeoutStartSec=1800.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NupWEBPzsyohVPG47HsTz8
This commit is contained in:
co-authored by
Claude Opus 5
parent
3a9c000a0e
commit
7cecc5c0cd
@@ -0,0 +1,140 @@
|
||||
# Phase 2 auf Prod in Betrieb nehmen
|
||||
|
||||
Reihenfolge ist verbindlich. Jeder Schritt hat eine Prüfung; schlägt sie
|
||||
fehl, hilft der nächste Schritt nicht.
|
||||
|
||||
Alles läuft als Benutzer `podman`, dessen Home `/home/podman` ist — `%h` in
|
||||
den Units löst dorthin auf. Die Datenbankverbindung steht bereits in
|
||||
`~/.config/wurzelwerk/database.env`.
|
||||
|
||||
## 0. Migrationen — erledigt
|
||||
|
||||
```sh
|
||||
psql "$DATABASE_URL" -c 'select name, angewandt_am from schema_migrationen order by name'
|
||||
```
|
||||
|
||||
Sechs Zeilen, `p2-000` bis `p2-005`. Fehlt eine, siehe README, Abschnitt
|
||||
„Migrationen" — `p2-002` und `p2-003` brauchen einen Superuser.
|
||||
|
||||
## 1. Abbild bauen
|
||||
|
||||
```sh
|
||||
cd /pfad/zum/repo && git pull
|
||||
podman build -t wurzelwerk-p2 .
|
||||
```
|
||||
|
||||
2,12 GB, davon 568 MB spaCy-Modell und 196 MB torch. Prüfung:
|
||||
|
||||
```sh
|
||||
podman run --rm --entrypoint ls localhost/wurzelwerk-p2 /app/lexikon/
|
||||
```
|
||||
|
||||
Zwölf Dateien. Fehlen `landtage.json`, `regierung.json` oder
|
||||
`sondergesandte.json`, ist das Abbild älter als der Stand vom 08.09.2026.
|
||||
|
||||
## 2. Lexikon in die Tabellen laden
|
||||
|
||||
`akteure.py` liest aus `akteure` und `amtsinhaber`, nicht aus den
|
||||
JSON-Dateien. Ohne diesen Schritt läuft Modul 4 durch und löst nichts auf,
|
||||
**ohne zu scheitern** — der teuerste stille Fehler der ganzen Einrichtung.
|
||||
|
||||
```sh
|
||||
podman run --rm --network=pasta \
|
||||
--env-file ~/.config/wurzelwerk/database.env \
|
||||
localhost/wurzelwerk-p2 lexikon.py --laden
|
||||
```
|
||||
|
||||
Erwartet: `person 5631`, `organisation 2319`, `partei 682`, `staat 195`,
|
||||
`amt 29`, `amtsinhaber 418`. Die `Ueberschneidung:`-Zeilen sind die
|
||||
Betriebssicht auf Doppelspitzen und Bremer Bürgermeister, kein Fehler.
|
||||
|
||||
Läuft der Container hier in einen Verbindungsfehler, zeigt `DATABASE_URL`
|
||||
vermutlich auf `127.0.0.1`. Aus dem Container heraus ist das der Container
|
||||
selbst; nötig ist `host.containers.internal`. Dann in `p2.env` überschreiben
|
||||
(Schritt 4), statt `database.env` anzufassen — die gehört Phase 1 mit.
|
||||
|
||||
## 3. Modell-Volume anlegen und einmal füllen
|
||||
|
||||
```sh
|
||||
podman volume create wurzelwerk-modelle
|
||||
```
|
||||
|
||||
Der erste Lauf braucht Netz und lädt 2,2 GB. Er muss **von Hand** laufen,
|
||||
nicht aus dem Timer: der Erstbestand über den gesamten Korpus dauert etwa
|
||||
17 Minuten je 5000 Items, und `TimeoutStartSec=1800` ist dafür knapp.
|
||||
|
||||
```sh
|
||||
podman run --rm --network=pasta --memory=8g --shm-size=1g \
|
||||
--volume wurzelwerk-modelle:/cache:U \
|
||||
--env-file ~/.config/wurzelwerk/database.env \
|
||||
--env OMP_NUM_THREADS=4 --env HF_HUB_OFFLINE=0 \
|
||||
localhost/wurzelwerk-p2 phase2.py --backfill
|
||||
```
|
||||
|
||||
Prüfung — vier Ebenen, je eine `coder_version`, alle gleich hoch:
|
||||
|
||||
```sh
|
||||
psql "$DATABASE_URL" -c \
|
||||
'select ebene, coder_version, count(*) from codings group by 1,2 order by 1'
|
||||
psql "$DATABASE_URL" -c 'select count(*) from item_embeddings'
|
||||
```
|
||||
|
||||
Stehen für eine Ebene zwei Versionen nebeneinander, ist der Lauf
|
||||
unterbrochen worden und wurde mit geändertem Code fortgesetzt. Dann die
|
||||
ältere löschen und den Backfill wiederholen.
|
||||
|
||||
## 4. Umgebung für Phase 2
|
||||
|
||||
```sh
|
||||
cp deploy/p2.env.beispiel ~/.config/wurzelwerk/p2.env
|
||||
chmod 600 ~/.config/wurzelwerk/p2.env
|
||||
$EDITOR ~/.config/wurzelwerk/p2.env # HF_HUB_OFFLINE=1 setzen
|
||||
```
|
||||
|
||||
`HF_HUB_OFFLINE=1` erst jetzt, nach dem erfolgreichen Erstlauf. Danach geht
|
||||
das Modell nie wieder ins Netz und lädt in zwei Sekunden aus dem Volume.
|
||||
|
||||
## 5. Units einhängen
|
||||
|
||||
```sh
|
||||
cp deploy/wurzelwerk-p2.{service,timer} ~/.config/systemd/user/
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user start wurzelwerk-p2.service # ein Lauf von Hand
|
||||
journalctl --user -u wurzelwerk-p2 -n 40
|
||||
```
|
||||
|
||||
Erst wenn dieser eine Lauf sauber durchgeht — er sollte `kein offener Slot`
|
||||
melden, weil der Backfill alles kodiert hat —, den Timer scharfstellen:
|
||||
|
||||
```sh
|
||||
systemctl --user enable --now wurzelwerk-p2.timer
|
||||
systemctl --user list-timers wurzelwerk-p2.timer
|
||||
```
|
||||
|
||||
Feuert `*:03,18,33,48`, versetzt zum 15-Minuten-Raster von Phase 1.
|
||||
|
||||
Damit die Units auch ohne angemeldete Sitzung laufen:
|
||||
|
||||
```sh
|
||||
loginctl enable-linger podman
|
||||
```
|
||||
|
||||
## 6. Nach der ersten Stunde
|
||||
|
||||
```sh
|
||||
psql "$DATABASE_URL" -c \
|
||||
"select modul, coder_version, items_gesehen, items_kodiert, items_fehler,
|
||||
begonnen_am
|
||||
from p2_laeufe order by begonnen_am desc limit 12"
|
||||
```
|
||||
|
||||
Vier Zeilen je Slot, `items_fehler = 0`. Ein Modul, das dauerhaft fehlt,
|
||||
ist abgestürzt, ohne die anderen mitzureissen — genau dafür ist die
|
||||
Schichtung da, aber es fällt dann eben auch nur hier auf.
|
||||
|
||||
## Was diese Phase nicht tut
|
||||
|
||||
`raw_items` wird nie geschrieben. Der gesamte Phase-2-Bestand — `codings`,
|
||||
`item_embeddings`, `p2_laeufe` — ist verwerfbar und aus `raw_items` neu
|
||||
herstellbar. Ein Rückbau ist deshalb `truncate`, kein Wiederherstellen aus
|
||||
einem Backup.
|
||||
@@ -1,9 +1,12 @@
|
||||
# Nach ~/.config/wurzelwerk/p2.env kopieren und ausfuellen. chmod 600.
|
||||
# Enthaelt Zugangsdaten und gehoert nicht ins Repo.
|
||||
|
||||
# host.containers.internal zeigt aus dem Container auf den Host, wo Postgres
|
||||
# seinen Port veroeffentlicht.
|
||||
DATABASE_URL=postgresql://wurzelwerk:PASSWORT@host.containers.internal:5432/wurzelwerk
|
||||
# Die Datenbankverbindung steht auf Prod bereits in
|
||||
# ~/.config/wurzelwerk/database.env; die Unit liest beide Dateien. Hier nur
|
||||
# setzen, wenn Phase 2 eine andere braucht - etwa weil database.env auf
|
||||
# 127.0.0.1 zeigt, was aus dem Container heraus ins Leere laeuft.
|
||||
#
|
||||
# DATABASE_URL=postgresql://wurzelwerk:PASSWORT@host.containers.internal:5432/wurzelwerk
|
||||
|
||||
# Threadzahl. Geht in die coder_version ein - eine Aenderung erzeugt einen
|
||||
# neuen Vektorbestand. Prod hat 16 Threads, 4 laeuft ueberall.
|
||||
|
||||
@@ -15,7 +15,16 @@ After=postgres.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
EnvironmentFile=%h/.config/wurzelwerk/p2.env
|
||||
# Zwei Dateien, in dieser Reihenfolge. database.env haelt die
|
||||
# Datenbankverbindung und gehoert nicht Phase 2 allein - sie steht auf Prod
|
||||
# schon da und wird hier nur mitgelesen, nicht angefasst. p2.env traegt, was
|
||||
# nur Phase 2 angeht; wird dort DATABASE_URL noch einmal gesetzt, gewinnt sie,
|
||||
# weil systemd spaetere Dateien spaeter liest.
|
||||
#
|
||||
# Beide muessen aus dem Container heraus aufloesbar sein: der Rechnername in
|
||||
# DATABASE_URL darf nicht 127.0.0.1 sein, sondern host.containers.internal.
|
||||
EnvironmentFile=%h/.config/wurzelwerk/database.env
|
||||
EnvironmentFile=-%h/.config/wurzelwerk/p2.env
|
||||
TimeoutStartSec=1800
|
||||
ExecStart=/usr/bin/podman run --rm \
|
||||
--name wurzelwerk-p2-lauf \
|
||||
|
||||
Reference in New Issue
Block a user