Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b8740cb93 | |||
| 4e3166e1c4 | |||
| 9425c6bd1a | |||
| 47544d1769 | |||
| b0aa55a8b7 | |||
| 3543c4a4be | |||
| a802b90617 | |||
| aeb9bb5940 | |||
| f968eb0340 | |||
| f754831f54 | |||
| ff0a1c8256 | |||
| ffeb639d62 |
+87
-1
@@ -29,6 +29,49 @@ Runbook: **[README-pliki.md](README-pliki.md)**. Ekran „Pliki" wymaga zapisu d
|
||||
udziału z bazami, więc znosi gwarancję z DAN-25, że baz nie da się zmienić przez
|
||||
NFS. Co zostaje z zabezpieczeń i jak to wdrożyć — w runbooku.
|
||||
|
||||
## ⚠️ Wymóg węzłów: klient NFS
|
||||
|
||||
Wszystkie warstwy montują udziały z NAS-a, więc **każdy węzeł, na którym może
|
||||
wylądować pod, musi mieć klienta NFS**. Bez niego kubelet nie zamontuje wolumenu:
|
||||
|
||||
```
|
||||
mount: ... bad option; for several filesystems (e.g. nfs, cifs) you might need
|
||||
a /sbin/mount.<type> helper program
|
||||
```
|
||||
|
||||
Ten komunikat **nie oznacza problemu z udziałem ani z uprawnieniami** — serwer
|
||||
w ogóle nie został zapytany. Jądro nie znalazło programu pomocniczego
|
||||
`/sbin/mount.nfs`.
|
||||
|
||||
### Sprawdzenie
|
||||
|
||||
```bash
|
||||
for N in 192.168.1.73 192.168.1.80 192.168.1.81; do
|
||||
printf "%-15s " "$N"
|
||||
ssh hammer@$N 'test -x /sbin/mount.nfs && echo MA-KLIENTA || echo BRAK-KLIENTA'
|
||||
done
|
||||
```
|
||||
|
||||
### Instalacja
|
||||
|
||||
```bash
|
||||
ssh hammer@<węzeł> 'sudo apt-get update && sudo apt-get install -y nfs-common'
|
||||
```
|
||||
|
||||
> **Na WSZYSTKICH węzłach, nie tylko na tym, gdzie pod stoi teraz.** Braku na
|
||||
> pozostałych nie widać, dopóki scheduler tam czegoś nie przeniesie — a wtedy
|
||||
> awaria wygląda na nagłą, choć przyczyna leżała od dawna. Dokładnie tak wyszło
|
||||
> za pierwszym razem: pody działały miesiącami na jednym węźle, aż zejście do
|
||||
> zera replik przy innej naprawie przeplanowało je gdzie indziej.
|
||||
|
||||
### Skąd wiadomo, że to TO
|
||||
|
||||
| komunikat | co znaczy |
|
||||
|---|---|
|
||||
| `bad option ... mount.<type> helper program` | **brak `nfs-common` na węźle** — serwer niepytany |
|
||||
| `access denied by server while mounting` | serwer odmawia: eksport nieprzeładowany, węzła nie ma na liście `hosts`, albo udział wyłączony |
|
||||
| `Permission denied` przy zapisie | montowanie działa, brakuje praw — patrz `mapall_user` i właściciel katalogu |
|
||||
|
||||
## ⚠️ Sekret `astrololo-auth` — utwórz PRZED wdrożeniem
|
||||
|
||||
Aplikacja wystawia treść **oryginalnych baz interpretacyjnych**, dlatego wymaga
|
||||
@@ -47,11 +90,54 @@ read -rs -p "Hasło do aplikacji (APP_PASSWORD): " APP_PASSWORD; echo
|
||||
|
||||
kubectl -n astrololo create secret generic astrololo-auth \
|
||||
--from-literal=APP_PASSWORD="$APP_PASSWORD" \
|
||||
--from-literal=INTERNAL_TOKEN="$(openssl rand -hex 32)"
|
||||
--from-literal=INTERNAL_TOKEN="$(openssl rand -hex 32)" \
|
||||
--from-literal=SESSION_SECRET="$(openssl rand -hex 32)"
|
||||
|
||||
unset APP_PASSWORD
|
||||
```
|
||||
|
||||
`SESSION_SECRET` podpisuje ciasteczka sesji (LOG-34). **Pod bez niego celowo nie
|
||||
wstanie**: usługa z kontami, ale bez klucza, nie odróżniłaby ważnej sesji od
|
||||
podrobionej. Nikt go nigdy nie musi oglądać.
|
||||
|
||||
### ⚠️ Masz już sekret sprzed LOG-34? Dołóż klucz, nie twórz od nowa
|
||||
|
||||
Komenda wyżej zakłada sekret **od zera**. Jeśli `astrololo-auth` już istnieje,
|
||||
merge manifestu sam klucza nie dołoży — pod zgłosi wtedy:
|
||||
|
||||
```
|
||||
Error: couldn't find key SESSION_SECRET in Secret astrololo/astrololo-auth
|
||||
```
|
||||
|
||||
Dokładamy klucz, nie ruszając pozostałych:
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo patch secret astrololo-auth --type=merge \
|
||||
-p "{\"stringData\":{\"SESSION_SECRET\":\"$(openssl rand -hex 32)\"}}"
|
||||
|
||||
kubectl -n astrololo rollout restart deploy/presentation
|
||||
```
|
||||
|
||||
Sprawdzenie, że komplet kluczy jest na miejscu (bez pokazywania wartości):
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo get secret astrololo-auth -o jsonpath='{.data}' \
|
||||
| tr ',' '\n' | grep -o '"[A-Z_]*"'
|
||||
```
|
||||
|
||||
Oczekiwane: `APP_PASSWORD`, `INTERNAL_TOKEN`, `SESSION_SECRET`.
|
||||
|
||||
> `--type=merge` ze `stringData` **dokłada albo nadpisuje** i nie wymaga, żeby
|
||||
> klucz wcześniej istniał — w odróżnieniu od JSON Patch z `op: replace`, który
|
||||
> na brakującej ścieżce po prostu odmawia. Ta sama komenda służy więc i do
|
||||
> dołożenia, i do rotacji.
|
||||
|
||||
### Rotacja klucza sesji
|
||||
|
||||
**Wylogowuje WSZYSTKICH.** To nie usterka, tylko awaryjny wyłącznik: gdy
|
||||
podejrzewasz, że ktoś przechwycił cudzą sesję, podmiana klucza unieważnia je
|
||||
wszystkie naraz. Komenda ta sama, co dołożenie wyżej.
|
||||
|
||||
`INTERNAL_TOKEN` jest losowany i **nikt go nigdy nie musi oglądać** — służy tylko
|
||||
usługom do rozmowy między sobą. `APP_PASSWORD` wpisujesz w przeglądarce
|
||||
(użytkownik: `astrololo`, zmienny przez `APP_USER` w `presentation.yaml`).
|
||||
|
||||
@@ -11,10 +11,10 @@ resources:
|
||||
- ingress.yaml # wejście po https + przekierowanie z http
|
||||
images:
|
||||
- name: gitea.czernobog.pl/gitea/astrololo-data
|
||||
newTag: ee3c515d
|
||||
newTag: 10ade555
|
||||
- name: gitea.czernobog.pl/gitea/astrololo-logic
|
||||
newTag: ee3c515d
|
||||
newTag: 10ade555
|
||||
- name: gitea.czernobog.pl/gitea/astrololo-render
|
||||
newTag: latest
|
||||
- name: gitea.czernobog.pl/gitea/astrololo-presentation
|
||||
newTag: ee3c515d
|
||||
newTag: 10ade555
|
||||
|
||||
@@ -32,6 +32,13 @@ spec:
|
||||
secretKeyRef: { name: astrololo-auth, key: INTERNAL_TOKEN }
|
||||
- name: APP_USER
|
||||
value: "astrololo"
|
||||
# Klucz podpisu ciasteczek sesji (LOG-34). WYMAGANY — pod bez niego
|
||||
# celowo nie wstaje: usługa z kontami, ale bez klucza, nie umiałaby
|
||||
# odróżnić ważnej sesji od podrobionej. Rotacja tego klucza WYLOGOWUJE
|
||||
# WSZYSTKICH, i tak ma być — to jest awaryjny wyłącznik.
|
||||
- name: SESSION_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef: { name: astrololo-auth, key: SESSION_SECRET }
|
||||
- name: RATE_LIMIT_PER_MIN
|
||||
value: "120" # 0 = bez limitu
|
||||
# Aplikacja stoi za Ingressem, więc bezpośrednim rozmówcą jest zawsze
|
||||
|
||||
@@ -31,6 +31,19 @@ spec:
|
||||
# Where the librarian sends THIS bot's results/pongs back to (its own
|
||||
# NodePort). Lets one librarian serve both bots - see deploy-bot.yaml.
|
||||
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32442" }
|
||||
# Self-hosted models (Ollama). No API key - the endpoint IS the
|
||||
# configuration, and the backend stays unselectable while unset.
|
||||
# Pick a model at runtime with: $gadaj_teraz ollama <model>
|
||||
# ($modele_ai lists what the server actually has pulled).
|
||||
- { name: CONJURER_OLLAMA_URL, value: "http://192.168.1.72:11434" }
|
||||
# The server currently has exactly one model pulled (verified via
|
||||
# /v1/models): gemma4:e2b. Without this the built-in default
|
||||
# (llama3.1:8b) would be requested and every reply would fail.
|
||||
- { name: CONJURER_OLLAMA_MODEL, value: "gemma4:e2b" }
|
||||
# Self-hosted generation is far slower than a hosted API, especially
|
||||
# the first request after the model is evicted from VRAM. Applies to
|
||||
# every backend, so keep it only as high as you actually need.
|
||||
- { name: CONJURER_AI_TIMEOUT_SECONDS, value: "240" }
|
||||
volumeMounts:
|
||||
- { name: data, mountPath: /data }
|
||||
- { name: netrc, mountPath: /secrets, readOnly: true }
|
||||
|
||||
@@ -51,6 +51,19 @@ spec:
|
||||
# query and answers results/pongs HERE - so it serves this bot AND the
|
||||
# test bot from one instance, no CONJURER_MAIN_BOT repointing needed.
|
||||
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32443" }
|
||||
# Self-hosted models (Ollama). No API key - the endpoint IS the
|
||||
# configuration, and the backend stays unselectable while unset.
|
||||
# Pick a model at runtime with: $gadaj_teraz ollama <model>
|
||||
# ($modele_ai lists what the server actually has pulled).
|
||||
- { name: CONJURER_OLLAMA_URL, value: "http://192.168.1.72:11434" }
|
||||
# The server currently has exactly one model pulled (verified via
|
||||
# /v1/models): gemma4:e2b. Without this the built-in default
|
||||
# (llama3.1:8b) would be requested and every reply would fail.
|
||||
- { name: CONJURER_OLLAMA_MODEL, value: "gemma4:e2b" }
|
||||
# Self-hosted generation is far slower than a hosted API, especially
|
||||
# the first request after the model is evicted from VRAM. Applies to
|
||||
# every backend, so keep it only as high as you actually need.
|
||||
- { name: CONJURER_AI_TIMEOUT_SECONDS, value: "240" }
|
||||
volumeMounts:
|
||||
- { name: data, mountPath: /data }
|
||||
- { name: netrc, mountPath: /secrets, readOnly: true }
|
||||
|
||||
@@ -8,9 +8,9 @@ resources:
|
||||
- deploy-bot-backup.yaml
|
||||
images:
|
||||
- name: gitea.czernobog.pl/gitea/conjurer-librarian
|
||||
newTag: d0c7ab61
|
||||
newTag: fdc1fa18
|
||||
- name: gitea.czernobog.pl/gitea/conjurer-bot
|
||||
newTag: d0c7ab61
|
||||
newTag: fdc1fa18
|
||||
# Production bot channel - only bumped when a [deploy]-tagged build appears.
|
||||
# Bootstrapped to fbd1ec9f: that's the image the first [deploy] build (merge
|
||||
# of conjurer#20) promoted to conjurer-bot-deploy. From here the image-updater
|
||||
|
||||
Reference in New Issue
Block a user