Manifest, wpięcie w kustomization i runbook krok po kroku.
DECYZJE ZAPISANE W MANIFEŚCIE, ŻEBY NIE TRZEBA ICH BYŁO ODTWARZAĆ Z GŁOWY:
local-path, NIE NFS. Postgres zakłada semantykę blokad i fsync, której NFS nie
gwarantuje — to klasyczne źródło uszkodzenia bazy przy nagłym restarcie. Ceną
jest przywiązanie do węzła; przy luście odtwarzalnym z Excela to akceptowalne.
strategy: Recreate. Wolumen jest ReadWriteOnce, a dwa procesy Postgresa na jednym
katalogu danych to uszkodzona baza — rolling próbowałby wstać z nowym podem,
zanim stary zejdzie.
PGDATA w PODKATALOGU wolumenu: katalog główny potrafi zawierać wpisy systemu
plików, a initdb odmawia pracy w niepustym katalogu.
Wersja PRZYPIĘTA i poza image-updaterem: podbicie majora wymaga migracji katalogu
danych, więc nie może się zdarzyć samo, w nocy, przy okazji builda aplikacji.
C.UTF-8 zamiast pl_PL.UTF-8: dopasowanie tekstu robimy przez unaccent i pg_trgm,
nie przez collation, a pl_PL wymagałby obrazu z wygenerowanymi lokalizacjami.
DATA_PROVIDER zostaje na `excel`. Postgres można wdrożyć i obejrzeć BEZ ryzyka
dla działającego wyszukiwania; przełączenie to osobna, późniejsza decyzja.
SPRAWDZONE PRZED ODDANIEM: `kubectl kustomize astrololo` składa komplet 21
zasobów bez błędu, YAML parsuje się poprawnie, audyt odwołań potwierdza, że
jedynym brakującym sekretem jest astrololo-postgres (oba klucze), a DSN
postgresql+psycopg:// jest rozpoznawany przez SQLAlchemy z psycopg 3.
NIE SPRAWDZONE: skrypt inicjalizujący nie biegł przeciwko prawdziwemu Postgresowi
— na maszynie, na której to powstawało, nie ma Dockera. Zapisane wprost
w runbooku; krok 4 jest tam prawdziwym testem.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ekran „Konta" zapisuje konta do pliku, więc prezentacja potrzebuje trwałego
miejsca — inaczej wszystkie konta znikałyby przy restarcie poda.
subPath, NIE cały udział: prezentacja dostaje wyłącznie własny podkatalog
`presentation-state` i nie widzi baz interpretacyjnych. Zamontowanie tu całego
/mnt/Tank1/astrololo dałoby jej wgląd w bazy i obeszłoby bokiem zamknięcie
dostępu z DAN-25.
Konto administracyjne zostaje w APP_USER/APP_PASSWORD z sekretu — celowo poza
plikiem, żeby nie dało się go skasować ani ograniczyć z aplikacji.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
updates image gitea/astrololo-data tag 'aec3f843' to 'baf4e0e3'
updates image gitea/astrololo-logic tag '8b6ecc72' to 'baf4e0e3'
updates image gitea/astrololo-presentation tag '8b6ecc72' to 'baf4e0e3'
updates image gitea/astrololo-data tag '40f5e459' to 'aec3f843'
updates image gitea/astrololo-logic tag '1be57a47' to 'aec3f843'
updates image gitea/astrololo-presentation tag '40f5e459' to 'aec3f843'
updates image gitea/astrololo-render tag 'latest' to 'aec3f843'
updates image gitea/astrololo-data tag 'e3114f3e' to '40f5e459'
updates image gitea/astrololo-logic tag '86a0f16f' to '40f5e459'
updates image gitea/astrololo-presentation tag 'e3114f3e' to '40f5e459'
updates image gitea/astrololo-data tag 'bc80745a' to 'e3114f3e'
updates image gitea/astrololo-logic tag 'bc80745a' to 'e3114f3e'
updates image gitea/astrololo-presentation tag 'bc80745a' to 'e3114f3e'
updates image gitea/astrololo-data tag '70c83cfc' to 'bc80745a'
updates image gitea/astrololo-logic tag '70c83cfc' to 'bc80745a'
updates image gitea/astrololo-presentation tag '70c83cfc' to 'bc80745a'
Wszystkie cztery usługi biegły na koncie `default` z AUTOMATYCZNIE montowanym
tokenem API Kubernetesa. Żadna z nich nie rozmawia z API klastra — sekrety dostają
przez `secretKeyRef`, który wstrzykuje kubelet, nie pod. Token był więc zbędny,
a leżał w każdym kontenerze jako gotowy punkt wyjścia do klastra dla kogoś, kto
przejmie proces (np. przez lukę w zależności).
`automountServiceAccountToken: false` w szablonie poda data/logic/presentation/
render. Zweryfikowane `kubectl kustomize` — pole trafia do `.spec.template.spec`,
nie do specu Deploymentu (tam byłoby ciche i bez efektu).
Zero wpływu na działanie: nic w kodzie nie woła API Kubernetesa.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updates image gitea/astrololo-data tag '4c1e7f88' to '70c83cfc'
updates image gitea/astrololo-logic tag '4c1e7f88' to '70c83cfc'
updates image gitea/astrololo-presentation tag '4c1e7f88' to '70c83cfc'
updates image gitea/astrololo-data tag 'dd32f7e8' to '4c1e7f88'
updates image gitea/astrololo-logic tag 'dd32f7e8' to '4c1e7f88'
updates image gitea/astrololo-presentation tag 'd3d9b365' to '4c1e7f88'
updates image gitea/astrololo-data tag '78af6d47' to 'dd32f7e8'
updates image gitea/astrololo-logic tag '7b435d42' to 'dd32f7e8'
updates image gitea/astrololo-presentation tag '7b435d42' to 'dd32f7e8'
The production bot now tracks conjurer-bot-deploy instead of conjurer-bot,
so it updates only when the conjurer CI promotes a build (commit message
contains [deploy]). Adds the image-updater 'deploy-bot' alias and the
kustomization images entry for it; DEPLOY-BOT.md documents the channel and
the one-time bootstrap. Test bot + librarian keep tracking every build.
Pairs with conjurer#20 (the CI promotion step).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pairs with conjurer#18: each bot advertises its own callback so the shared
librarian answers results/pongs back to the bot that asked - test bot
http://192.168.1.73:32442, deploy bot :32443. No CONJURER_MAIN_BOT
repointing needed for the librarian anymore; DEPLOY-BOT.md updated (only
the musician stays single-target).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A second Conjurer bot alongside the test one, sharing librarian/musician/
radio and the API key, differing only in:
* Discord token from the deploy-conjurer-netrc secret,
* distinct names/labels (deploy-bot) and NodePort 32443,
* /data on an NFS export (RWX) instead of a block PVC - so config/state
can be uploaded while it runs (copy onto the share) and backed up
concurrently.
deploy-bot-backup: a daily CronJob that mirrors /data and keeps 30 days of
dated snapshots of the critical small state (both memories, settings,
accident log, transcripts) on NFS. Production only - the test bot's
amnesia is fine. DEPLOY-BOT.md documents seeding, backup/restore, and the
librarian/musician callback routing (they push to one bot; repoint
CONJURER_MAIN_BOT to :32443 to feed this one).
kubectl kustomize builds cleanly (10 objects).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updates image gitea/astrololo-data tag 'a0d1135d' to 'b36b3bee'
updates image gitea/astrololo-logic tag 'a0d1135d' to 'b36b3bee'
updates image gitea/astrololo-presentation tag 'a0d1135d' to 'b36b3bee'
The librarian now checkpoints an in-progress search on SIGTERM and exits
within CONJURER_LIBRARIAN_GRACEFUL_TIMEOUT (default 45s). Raise k8s
terminationGracePeriodSeconds to 60 so that graceful checkpoint isn't cut
short by SIGKILL - otherwise the long DB scan restarts instead of resuming.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updates image gitea/astrololo-data tag '8ebce816' to 'a0d1135d'
updates image gitea/astrololo-logic tag '8ebce816' to 'a0d1135d'
updates image gitea/astrololo-presentation tag '8ebce816' to 'a0d1135d'
The work-queue OOM is fixed in code (bounded queue), but a deep search
still loads up to 15000 Crossref records and the accumulating result
JSONs into RAM. Give 2Gi of headroom so a big search isn't OOM-killed;
raise the request to 512Mi to match its real baseline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wyniki wyszukań (librarian) i eventy 'now playing' (musician) POST-owane do
bota ginęły, bo droga powrotna do bota była krucha:
* Service 'bot' był NodePort BEZ przypiętego nodePort -> k8s losował port z
30000-32767 przy każdym (od)tworzeniu Service, a musician/betoniarka z
Dockera adresują bota na sztywno http://192.168.1.73:32442. Rozjazd = każdy
POST leci w zamknięty port. Przypinam nodePort: 32442.
* Librarian jest w tym samym klastrze co bot, a mimo to szedł przez nodePort
węzła. Przełączam na DNS Service'u http://bot:5000 - odporne na
przetasowania nodePortu (nodePort zostaje tylko dla zewnętrznych z Dockera).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>