feat: podpora high-availability a multi-replica nasazení
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 20s
CI / Build server (push) Successful in 26s
CI / Build client (push) Successful in 35s
CI / Playwright E2E tests (push) Failing after 1m56s
CI / Build and push Docker image (push) Has been skipped
CI / Notify (push) Successful in 1s
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 20s
CI / Build server (push) Successful in 26s
CI / Build client (push) Successful in 35s
CI / Playwright E2E tests (push) Failing after 1m56s
CI / Build and push Docker image (push) Has been skipped
CI / Notify (push) Successful in 1s
- Socket.io Redis adapter pro sdílený stav přes repliky - graceful shutdown serveru - WATCH/MULTI v updateData pro race-condition-safe aktualizace - lease mechanismus pro push reminder (zabrání duplicitnímu odesílání) - k8s/ manifesty pro testovací kind cluster - Dockerfile: opraven EXPOSE port na 3001 - .gitignore: ignorovány Claude pracovní soubory
This commit is contained in:
+186
@@ -0,0 +1,186 @@
|
||||
# Kubernetes — Luncher HA
|
||||
|
||||
Manifesty pro nasazení Luncheru na Kubernetes s vysokou dostupností (3 repliky, Redis adapter pro Socket.io, WATCH/MULTI atomické zápisy, graceful shutdown).
|
||||
|
||||
## Prerekvizity
|
||||
|
||||
- kubectl nakonfigurovaný na cílový cluster
|
||||
- `helm` nainstalovaný
|
||||
- Redis Stack image přístupný z clusteru (`redis/redis-stack-server:7.2.0-v14`)
|
||||
- Obraz `luncher:ha-test` načtený do clusteru (viz níže)
|
||||
|
||||
## Lokální kind cluster (testik) — setup
|
||||
|
||||
### 1. Smazat a znovu vytvořit cluster s port mappings
|
||||
|
||||
```powershell
|
||||
$env:KIND_EXPERIMENTAL_PROVIDER = "nerdctl"
|
||||
# Přidat nerdctl do PATH (Rancher Desktop)
|
||||
$env:PATH += ";$env:LOCALAPPDATA\Programs\Rancher Desktop\resources\resources\win32\bin"
|
||||
|
||||
kind delete cluster --name testik
|
||||
kind create cluster --name testik --config k8s/kind/testik.yaml
|
||||
```
|
||||
|
||||
### 2. Sestavit a načíst obraz
|
||||
|
||||
```powershell
|
||||
docker build -t luncher:ha-test .
|
||||
|
||||
# Uložit a načíst přes nerdctl (kind + nerdctl provider)
|
||||
nerdctl save luncher:ha-test -o luncher.tar
|
||||
kind load image-archive luncher.tar --name testik
|
||||
Remove-Item luncher.tar
|
||||
```
|
||||
|
||||
### 3. Nainstalovat Traefik (rke2-traefik)
|
||||
|
||||
> **Prerekvizita (Rancher Desktop):** Pokud Rancher Desktop běží s `kubernetes.options.traefik=true`,
|
||||
> host-switch.exe obsadí port 80 dříve než kind. Vypni traefik v k3s:
|
||||
> ```powershell
|
||||
> rdctl set --kubernetes.options.traefik=false
|
||||
> ```
|
||||
>
|
||||
> **Prerekvizita — inotify limity:** Čtyř-uzlový kind cluster vyčerpá výchozí
|
||||
> `fs.inotify.max_user_instances=128`. kube-proxy pak padá s „too many open files".
|
||||
> Zvyš limit v rancher-desktop WSL2 (přežije restart WSL2, ale ne reboot — přidej do
|
||||
> `/etc/sysctl.d/99-kind.conf` pro trvalost):
|
||||
> ```powershell
|
||||
> wsl -d rancher-desktop -- sysctl -w fs.inotify.max_user_instances=1280
|
||||
> ```
|
||||
|
||||
```powershell
|
||||
# rke2-traefik je v rke2-charts, ne rancher-charts
|
||||
helm repo add rke2-charts https://rke2-charts.rancher.io
|
||||
helm repo update
|
||||
|
||||
# Nejdřív CRD chart, pak samotný chart
|
||||
helm install traefik-crd rke2-charts/rke2-traefik-crd -n kube-system --create-namespace
|
||||
helm install traefik rke2-charts/rke2-traefik -n kube-system `
|
||||
--set "tolerations[0].key=node-role.kubernetes.io/control-plane" `
|
||||
--set "tolerations[0].operator=Exists" `
|
||||
--set "tolerations[0].effect=NoSchedule"
|
||||
```
|
||||
|
||||
Ověř že Traefik DaemonSet běží na control-plane (má hostPort 80):
|
||||
```powershell
|
||||
kubectl get ds -n kube-system traefik-rke2-traefik
|
||||
kubectl get pods -n kube-system -o wide | Select-String traefik
|
||||
```
|
||||
|
||||
### 4. Nainstalovat Reloader
|
||||
|
||||
[stakater/Reloader](https://github.com/stakater/Reloader) sleduje změny Secret a ConfigMap a automaticky spustí rolling restart Deploymentu — odpadá nutnost ručního `kubectl rollout restart` po rotaci `JWT_SECRET` nebo `ADMIN_PASSWORD`.
|
||||
|
||||
Manifest je vendorovaný ve verzi v1.4.16 (`k8s/base/reloader.yaml`). Nasadit do `default` namespace:
|
||||
|
||||
```powershell
|
||||
kubectl apply -f k8s/base/reloader.yaml
|
||||
kubectl rollout status deploy/reloader-reloader
|
||||
```
|
||||
|
||||
Reloader běží cluster-wide díky `ClusterRoleBinding` — nepotřebuje žádnou konfiguraci per-namespace. Deployment Luncheru má anotaci `reloader.stakater.com/auto: "true"`, která říká Reloaderu, ať sleduje všechny Secrety a ConfigMapy odkazované přes `envFrom`.
|
||||
|
||||
### 5. Nasadit Luncher
|
||||
|
||||
```powershell
|
||||
# Namespace + Redis
|
||||
kubectl apply -f k8s/base/namespace.yaml
|
||||
kubectl apply -f k8s/base/redis-statefulset.yaml
|
||||
kubectl apply -f k8s/base/redis-service.yaml
|
||||
|
||||
# Počkat na Redis
|
||||
kubectl rollout status statefulset/redis -n luncher
|
||||
|
||||
# Server secret (nebo použít šablonu server-secret.yaml)
|
||||
kubectl create secret generic luncher-secrets -n luncher `
|
||||
--from-literal=JWT_SECRET=dev-secret-change-me `
|
||||
--from-literal=ADMIN_PASSWORD=admin
|
||||
|
||||
# Server
|
||||
kubectl apply -f k8s/base/server-configmap.yaml
|
||||
kubectl apply -f k8s/base/server-deployment.yaml
|
||||
kubectl apply -f k8s/base/server-service.yaml
|
||||
kubectl apply -f k8s/base/server-pdb.yaml
|
||||
kubectl apply -f k8s/base/ingressroute.yaml
|
||||
|
||||
# Počkat na server
|
||||
kubectl rollout status deploy/luncher -n luncher
|
||||
```
|
||||
|
||||
## Testovací scénáře
|
||||
|
||||
### Baseline
|
||||
|
||||
```powershell
|
||||
kubectl get pods -n luncher -o wide
|
||||
# Ověř: 3 pody na 3 různých worker uzlech, status Running
|
||||
```
|
||||
|
||||
### Rolling update bez výpadku
|
||||
|
||||
V jednom terminálu posílej provoz:
|
||||
```powershell
|
||||
# Nainstaluj hey: go install github.com/rakyll/hey@latest
|
||||
hey -z 60s -c 20 http://luncher.localhost/api/health
|
||||
```
|
||||
|
||||
Ve druhém terminálu spusť rollout:
|
||||
```powershell
|
||||
kubectl rollout restart deploy/luncher -n luncher
|
||||
```
|
||||
|
||||
**Kritérium: 0 non-2xx odpovědí, 0 connection errors.**
|
||||
|
||||
### Node drain
|
||||
|
||||
```powershell
|
||||
kubectl cordon testik-worker2
|
||||
kubectl drain testik-worker2 --ignore-daemonsets --delete-emptydir-data
|
||||
# PDB zabrání souběžnému drainu druhého nodu
|
||||
kubectl get pods -n luncher -o wide # pody se přeplánují
|
||||
kubectl uncordon testik-worker2
|
||||
```
|
||||
|
||||
### Ověření Socket.io cross-pod
|
||||
|
||||
1. Otevři dvě záložky prohlížeče na `http://luncher.localhost`
|
||||
2. Z jednoho podu vyvolej změnu:
|
||||
```powershell
|
||||
kubectl exec -it deploy/luncher -n luncher -- curl -s -X POST localhost:3001/api/...
|
||||
```
|
||||
3. Ověř, že druhá záložka (pravděpodobně jiný pod) obdrží WebSocket event
|
||||
|
||||
### Concurrent write test
|
||||
|
||||
1. Otevři stejnou Pizza day objednávku ve dvou záložkách
|
||||
2. Simuluj souběžné odeslání (otevřít DevTools → síť → odeslat obě požadavky současně)
|
||||
3. Ověř Redis: `kubectl exec -it redis-0 -n luncher -- redis-cli JSON.GET luncher:<datum>`
|
||||
— oba zápisy musí být zachovány (WATCH/MULTI retry)
|
||||
|
||||
### Auto-rollout při změně Secret / ConfigMap
|
||||
|
||||
Reloader automaticky spustí rolling restart, kdykoli se změní `luncher-secrets` nebo `luncher-config`:
|
||||
|
||||
```powershell
|
||||
# Příklad: rotace admin hesla
|
||||
kubectl -n luncher patch secret luncher-secrets --type=merge `
|
||||
-p '{"stringData":{"ADMIN_PASSWORD":"nove-heslo"}}'
|
||||
|
||||
# Reloader detekuje změnu resourceVersion a patchne pod template
|
||||
kubectl rollout status deploy/luncher -n luncher
|
||||
|
||||
# Ověř anotaci přidanou Reloaderem na pod template
|
||||
kubectl get deploy luncher -n luncher -o yaml | Select-String "STAKATER"
|
||||
```
|
||||
|
||||
**Kritérium: pody se automaticky vyrolují bez ručního restartu. PDB zajistí, že alespoň jeden pod zůstane dostupný.**
|
||||
|
||||
## Pořadí aplikace manifestů
|
||||
|
||||
1. `reloader.yaml` (do `default` namespace — musí být před Deployment)
|
||||
2. `namespace.yaml`
|
||||
3. `redis-statefulset.yaml` + `redis-service.yaml`
|
||||
4. `server-configmap.yaml` + `server-secret.yaml`
|
||||
5. `server-deployment.yaml` + `server-service.yaml` + `server-pdb.yaml`
|
||||
6. `ingressroute.yaml`
|
||||
Reference in New Issue
Block a user