data-demo wpadał w pętlę restartów na k3s-agent3:
RuntimeError: NumPy was built with baseline optimizations:
(X86_V2) but your machine doesn't support: (X86_V2).
DIAGNOZA — to NIE jest różnica sprzętu. Wszystkie cztery węzły to maszyny
wirtualne. Trzy widzą procesor jako „QEMU Virtual CPU 2.5+" i mają komplet
rozszerzeń x86-64-v2; agent3 widzi „Common KVM processor" (kvm64) i nie ma
popcnt, ssse3, sse4_1 ani sse4_2. Fizyczny i7-3770 pod spodem obsługuje nawet
x86-64-v3 — te flagi są MASKOWANE przez domyślny model CPU w Proxmoksie.
agent3 ma 14 dni, pozostałe 52. Został dołożony później i pominięto przy nim
krok `--cpu host`, odnotowany w pamięci projektu 2 sierpnia. Nikt tego nie
zauważył, dopóki scheduler nie postawił tam akurat warstwy danych — jedynej,
która ciągnie pandas, a przez nią NumPy.
ZABEZPIECZENIE: data i data-demo wymagają etykiety
`astrololo.czernobog.pl/cpu-x86-64-v2`. Świadomie ETYKIETA, a nie wykluczenie
agent3 po nazwie: wykluczanie po nazwie znaczyłoby, że każdy KOLEJNY źle
postawiony węzeł znów zbiera się przez awarię. Nowy węzeł jest domyślnie
nieoznaczony, więc nie dostanie tych podów, dopóki ktoś go nie sprawdzi
i nie oznaczy. Pending z czytelnym powodem bije pętlę restartów z komunikatem
o „baseline optimizations".
KOLEJNOŚĆ: węzły trzeba oznaczyć PRZED wdrożeniem tej zmiany. Dziś etykietę ma
zero węzłów, więc samo zmergowanie posłałoby data w Pending.
RUNBOOK: skrypt sprawdzający węzły, naprawa u źródła (`qm set --cpu host` plus
pełne wyłączenie i włączenie maszyny — sam restart z gościa nie wystarcza),
oraz zastrzeżenie, że `--cpu host` blokuje migrację na żywo między hostami
o różnych procesorach.
PUŁAPKA PRZY CZYTANIU FLAG, udokumentowana bo kosztowała fałszywą diagnozę:
Linux raportuje SSE3 jako „pni", nie „sse3". Pierwsza wersja kontroli wskazała
przez to trzy zdrowe węzły jako niesprawne.
Przy okazji: lista węzłów w eksportach NFS obejmuje wszystkie cztery. Runbooki
wymieniały trzy, a klaster ma cztery — ten sam mechanizm, ta sama przyczyna.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 „Pliki" pozwala wgrywać bazy, archiwizować je i (dla administratora)
kasować, a stan użycia jest klikany, więc musi przetrwać restart poda. Warstwa
danych musi zatem móc pisać na udziale — dotąd był montowany read-only.
ŚWIADOMY KOSZT: znika jedna warstwa obrony w głąb. Przejęcie warstwy danych
pozwala teraz nie tylko odczytać bazy, ale i je zmienić. Zostaje reszta: token
międzywarstwowy, szyfrowane łącze, ograniczenie eksportu NFS do konkretnych
hostów (DAN-25) oraz to, że kasować może wyłącznie konto administracyjne (PRE-27).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Domyka PRE-16 po stronie manifestow. Kod (astrololo#21) potrafi juz szyfrowac
ruch miedzy warstwami AES-256-GCM; tu dokladamy klucze i wymuszenie.
- astrololo-link: nowy sekret z dwoma kluczami (LINK_KEY_PRESENTATION_LOGIC,
LINK_KEY_LOGIC_DATA), tworzony POZA repo jak pozostale. Osobny klucz na pare
rozmowcow: przejecie klucza prezentacji nie otwiera warstwy danych. Logika
bierze oba, prezentacja i dane wylacznie swoj (secretKeyRef).
- LINK_ENCRYPTION_REQUIRED=true we wszystkich trzech: bez klucza pod NIE wstaje,
a klient nie wysyla niczego. Fail-closed w obie strony jest celowy — usluga,
ktora wstala i po cichu nie szyfruje, jest gorsza niz CrashLoop, bo awarii
nie widac.
README: sekcja o sekrecie astrololo-link (tworzenie, wymiana, restart calej
trojki naraz) oraz uczciwa nota, ze szyfrowane sa ciala, nie naglowki — sciezka
i token jada czytelnie, ale sam token bez klucza nic nie daje.
Sprawdzone: kubectl kustomize + apply --dry-run=server przechodza dla obu
profili. Pelna instrukcja wdrozenia: docs/wdrozenie-pre16.md w repo astrololo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Domyka od strony wdrozenia ochrone dodana w aplikacji (PR #10 w repo astrololo).
Bez tych zmiennych aplikacja startuje OTWARTA, a wystawia tresc oryginalnych
baz interpretacyjnych.
- presentation: APP_PASSWORD + INTERNAL_TOKEN z sekretu, APP_USER i
RATE_LIMIT_PER_MIN jawnie (nie sa tajne).
- logic, data: INTERNAL_TOKEN z sekretu — bez niego da sie ominac logowanie,
uderzajac wprost w warstwe nizej. Warstwa danych oddaje SUROWE wiersze,
wiec to najwrazliwszy punkt.
WARTOSCI SEKRETOW CELOWO NIE TRAFIAJA DO REPO — to GitOps, wiec zostalyby
w historii gita na zawsze i przekreslily caly sens tej zmiany. Manifesty
tylko odwoluja sie do sekretu `astrololo-auth`, tworzonego poza repo — ta sama
konwencja co istniejacy `gitea-registry`.
UWAGA: sekret jest WYMAGANY (bez `optional: true`), wiec pody nie wstana,
dopoki go nie utworzysz. To swiadome: lepsza widoczna awaria niz cichy start
bez ochrony. Instrukcja tworzenia i zmiany hasla w astrololo/README.md.
Przy okazji: poprawiony mylacy komentarz przy EXCEL_DIR — pliki baz ida
z NFS, nie z obrazu (montaz je nadpisuje).
Zwalidowane `kubectl kustomize` dla bazy i profilu swisseph: sekrety trafiaja
do wlasciwych uslug, a w wyniku nie ma zadnego `kind: Secret`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>