Files
deploy/astrololo/README-stan-prezentacji.md
T
gitea eff9d206ac data: wymagaj węzła z x86-64-v2; runbook maskowania CPU i lista czterech węzłów
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>
2026-08-26 21:44:02 +02:00

4.1 KiB

Udział na stan prezentacji — astrololo-state

Potrzebny do kont zakładanych z ekranu „Konta" (PRE-27). Bez niego pod presentation nie wstanie.


Dlaczego osobny udział, a nie podkatalog

Pierwsza wersja montowała /mnt/Tank1/astrololo z subPath: presentation-state i pod stanął w CreateContainerConfigError:

failed to create subPath directory for volumeMount "state" of container "presentation"

Przyczyna była podwójna i za każdym razem ta sama: udział z bazami jest wyeksportowany ro: true z root_squash (patrz runbook DAN-25 w repo aplikacji). Zatem:

  1. kubelet nie mógł utworzyć podkatalogu — bo udział jest tylko do odczytu,
  2. a gdyby nawet mógł, aplikacja i tak nie zapisałaby tam pliku kont.

Osobny udział rozwiązuje to bez ruszania DAN-25. Udział z bazami zostaje tylko do odczytu; konta dostają własne, małe miejsce. Przy okazji znika subPath, czyli znika potrzeba, żeby kubelet cokolwiek zakładał — katalog istnieje, bo jest korzeniem udziału.


Krok 1 — dataset i udział na TrueNAS

Po SSH na NAS (192.168.1.34). Konwencja jak w DAN-25: nie edytujemy /etc/exports ręcznie, tylko przez midclt.

# dataset
sudo zfs create Tank1/astrololo-state

Jeśli Tank1 nie jest pulą ZFS albo wolisz zwykły katalog:

sudo mkdir -p /mnt/Tank1/astrololo-state

Właściciel i prawa

Kontenery aplikacji działają jako root, a eksport ma root_squash, więc root z klienta NIE jest rootem na udziale. Żeby zapis działał, przypinamy cały ruch z tych hostów do jednego, nieuprzywilejowanego użytkownika — to bezpieczniejsze niż no_root_squash, bo nie oddaje roota.

# użytkownik, na którego mapujemy (jeśli nie istnieje — utwórz w UI TrueNAS)
sudo chown -R apps:apps /mnt/Tank1/astrololo-state
sudo chmod 770 /mnt/Tank1/astrololo-state

Podstaw swojego użytkownika w miejsce apps. Sprawdzisz istniejących: midclt call user.query | python3 -c "import sys,json;[print(u['uid'], u['username']) for u in json.load(sys.stdin)]"

Eksport NFS

midclt call sharing.nfs.create '{
  "path": "/mnt/Tank1/astrololo-state",
  "comment": "astrololo — stan prezentacji (konta PRE-27)",
  "hosts": ["192.168.1.73", "192.168.1.80", "192.168.1.81", "192.168.1.82"],
  "ro": false,
  "mapall_user": "apps",
  "mapall_group": "apps"
}'
ustawienie po co
hosts zawężone te same trzy węzły k8s co w DAN-25 — nikt inny nie zamontuje
ro: false musi być zapisywalny, inaczej konta się nie zapiszą
mapall_user cały ruch pisze jako jeden nieuprzywilejowany użytkownik, niezależnie od UID w kontenerze

Podstaw swoje adresy węzłów, jeśli się zmieniły. Aktualne: kubectl get nodes -o wide


Krok 2 — sprawdź z węzła, ZANIM wdrożysz

To jest ten test, którego zabrakło za pierwszym razem:

ssh 192.168.1.73 'sudo mount -t nfs 192.168.1.34:/mnt/Tank1/astrololo-state /mnt/test \
  && sudo touch /mnt/test/proba && echo "ZAPIS DZIAŁA" \
  && sudo rm /mnt/test/proba; sudo umount /mnt/test'

Musi wypisać ZAPIS DZIAŁA. Jeśli zamiast tego widzisz Permission denied — wróć do praw katalogu i mapall_user w kroku 1.


Krok 3 — wdróż i sprawdź

kubectl apply -k astrololo
kubectl -n astrololo rollout status deploy/presentation

Sprawdź, że aplikacja faktycznie umie tam zapisać — załóż konto testowe na ekranie „Konta", a potem:

kubectl -n astrololo exec deploy/presentation -- ls -l /app/state/

Oczekiwane: plik accounts.json.


Odkręcenie

# ID udziału
midclt call sharing.nfs.query | python3 -c "import sys,json;[print(s['id'], s.get('path')) for s in json.load(sys.stdin)]"
midclt call sharing.nfs.delete <ID>

Uwaga na przyszłość: DAN-27 uderzy w tę samą ścianę

Zarządzanie plikami baz (wgrywanie, archiwizacja, kasowanie) wymaga zapisu do udziału z bazami — a ten jest ro: true. Ten runbook tego nie rozwiązuje i celowo nie rusza DAN-25: to osobna decyzja, bo oznacza rezygnację z gwarancji, że baz nie da się zmienić przez NFS. Patrz PR feat/pliki-zapis.