Files
deploy/astrololo/README-stan-prezentacji.md
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

136 lines
4.1 KiB
Markdown

# 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`.
```bash
# dataset
sudo zfs create Tank1/astrololo-state
```
Jeśli `Tank1` nie jest pulą ZFS albo wolisz zwykły katalog:
```bash
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.
```bash
# 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
```bash
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:
```bash
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ź
```bash
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:
```bash
kubectl -n astrololo exec deploy/presentation -- ls -l /app/state/
```
Oczekiwane: plik `accounts.json`.
---
## Odkręcenie
```bash
# 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`.