- 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
6.4 KiB
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
helmnainstalovaný- Redis Stack image přístupný z clusteru (
redis/redis-stack-server:7.2.0-v14) - Obraz
luncher:ha-testnačtený do clusteru (viz níže)
Lokální kind cluster (testik) — setup
1. Smazat a znovu vytvořit cluster s port mappings
$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
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:rdctl set --kubernetes.options.traefik=falsePrerekvizita — 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.confpro trvalost):wsl -d rancher-desktop -- sysctl -w fs.inotify.max_user_instances=1280
# 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):
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 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:
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
# 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
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:
# 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:
kubectl rollout restart deploy/luncher -n luncher
Kritérium: 0 non-2xx odpovědí, 0 connection errors.
Node drain
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
- Otevři dvě záložky prohlížeče na
http://luncher.localhost - Z jednoho podu vyvolej změnu:
kubectl exec -it deploy/luncher -n luncher -- curl -s -X POST localhost:3001/api/... - Ověř, že druhá záložka (pravděpodobně jiný pod) obdrží WebSocket event
Concurrent write test
- Otevři stejnou Pizza day objednávku ve dvou záložkách
- Simuluj souběžné odeslání (otevřít DevTools → síť → odeslat obě požadavky současně)
- 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:
# 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ů
reloader.yaml(dodefaultnamespace — musí být před Deployment)namespace.yamlredis-statefulset.yaml+redis-service.yamlserver-configmap.yaml+server-secret.yamlserver-deployment.yaml+server-service.yaml+server-pdb.yamlingressroute.yaml