K8s Upgrade & Storage Migration Plan
Cluster: 3 nody (k8s-master, k8s-1, k8s-2) na vpsfree.cz LXC, k8s v1.26.0, Flannel VXLAN, MetalLB L2, ingress-nginx.
Část 1: NFS multi-mount safety
Co NFS poskytuje
- Více klientů může současně mountovat stejný export v
RWX(ReadWriteMany). - POSIX-like sémantika přes síť (
read,write,rename,mkdir). - NLM / NFSv4 file locking — ale jen pokud ho aplikace explicitně používá (
fcntl,flock). - Atributový cache (mtime, size) je eventually consistent s konfigurovatelným TTL.
Bezpečnost podle scénáře
| Scénář | Bezpečné? |
|---|---|
| Dva pody zapisují různé soubory | ✅ Ano |
| Read-only shared assety, jeden writer | ✅ Ano |
| Aplikace s embedded DB (SQLite, BerkeleyDB) | ❌ Spolehlivě rozbije DB |
| Postgres / MySQL data dir | ❌ Nepodporováno |
Dvě repliky stejné aplikace zapisující do stejných souborů bez flock | ❌ Race conditions, korupce |
| Append-only logy z více writerů do stejného souboru | ⚠️ Krátké zápisy < PIPE_BUF většinou ok, dlouhé se interleavují |
| Aplikace navržené pro shared FS (Nextcloud, file storage apps) | ✅ Ano |
| Cron joby z různých nodů manipulující stejné soubory | ⚠️ Pouze s explicit flock |
Praktická pravidla
- Postgres nikdy na NFS (zůstává hostPath).
- SQLite nikdy na NFS — locking přes NFS je nespolehlivý.
- „Multiple writers" je bezpečné, jen pokud:
- Každý writer píše do vlastního adresáře/souboru, nebo
- Aplikace vědomě používá NFS-aware locking, nebo
- Read-mostly scénář s explicit lockingem.
- Pro současné workloady (krcmar/media, blog, sellapp) — typicky 1 replika nebo read-only, multi-writer není reálně využíván → bezpečné pásmo.
- Při budoucím škálování
replicas: > 1pro app, která zapisuje do shared volume, vždy ověřit concurrent-write chování.
Část 2: NFS PVC plán
Současný stav
- 1× StorageClass
example-nfs(provisionervpsfree.cz). - 1× PV/PVC, používaný jen testovacím podem.
- NFS export:
172.16.129.146:/nas/4721/shared.
Doporučený provisioner
Nasadit nfs-subdir-external-provisioner (upstream, well-maintained):
helm install nfs-subdir nfs-subdir-external-provisioner \
--namespace storage --create-namespace \
--set nfs.server=172.16.129.146 \
--set nfs.path=/nas/4721/shared \
--set storageClass.name=nfs \
--set storageClass.defaultClass=false \
--set storageClass.reclaimPolicy=Retain \
--set storageClass.allowVolumeExpansion=true \
--set nfs.mountOptions="{soft,timeo=100,retrans=3,noatime}"
Důvody pro soft,timeo=100: jinak při výpadku NFS pody zatuhnou v D stavu (uninterruptible sleep). hard mount je v k8s past.
Postup migrace
| Fáze | Workload | Velikost změny | Riziko |
|---|---|---|---|
| 1 | services/blog (media) | malá | nízké, čistý start |
| 2 | krcmar/cityhry (/k8s/cityhry) | střední, kopírování | nízké (read-mostly) |
| 3 | sellapp/uvasinu-test | malá | nízké |
| 4 | services/wireguard config | malá | střední (config-critical) |
| 5 | services/pgadmin data | malá | nízké |
| 6 | services/openldap | dle latence NFS | — (LDAP má rád low-latency I/O) |
| ❌ | services/postgres | zůstává hostPath, fixed node | — |
Per-workload migrace recept
1. kubectl scale deployment X --replicas=0
2. rsync -av /k8s/X/ /mnt/new-pvc/X/ (na nodu, kde data jsou)
3. Upravit deployment: hostPath → PVC
4. kubectl apply
5. kubectl scale deployment X --replicas=1
6. Ověřit, že běží + má data
7. Po týdnu: smazat /k8s/X na původním nodu
Část 3: K8s upgrade plán (1.26 → 1.31)
Klíčový fakt: skew policy
K8s nepovoluje skok přes více než 1 minor verzi v jednom kroku.
1.26 → 1.27 → 1.28 → 1.29 → 1.30 → 1.31 (5 hopů)
Každý hop = ~30-60 min práce + buffer na ověření.
Phase 0: Před prvním upgradem
-
etcd backup automation — cron na masteru:
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ snapshot save /backup/etcd-$(date +%F).dbDaily, retention 14 dní, off-site copy přes rsync.
-
Add IngressClass resource — preventivně:
apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: nginx annotations: ingressclass.kubernetes.io/is-default-class: "true" spec: controller: k8s.io/ingress-nginx -
Deploy NFS provisioner (Část 2).
-
Migrace 2-3 nekritických workloadů na PVC — méně proměnných najednou v upgrade fázi.
-
Dokumentace current state:
kubectl versionkubectl -n ingress-nginx get deploy ingress-nginx-controller -o yaml | grep image:- Stejně pro flannel, metallb, cert-manager, dashboard.
- Snapshot
kubectl get all -A -o yaml > backup.yaml.
Per-hop checklist (opakovat pro každý hop)
1. Přečti CHANGELOG / breaking changes:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.XX.md
2. etcd snapshot
3. Na masteru:
apt update
apt-mark unhold kubeadm
apt install kubeadm=1.XX.x-*
apt-mark hold kubeadm
kubeadm upgrade plan
kubeadm upgrade apply v1.XX.x
4. Drain master, upgrade kubelet+kubectl, uncordon:
kubectl drain k8s-master --ignore-daemonsets --delete-emptydir-data
apt install kubelet=1.XX.x-* kubectl=1.XX.x-*
systemctl daemon-reload && systemctl restart kubelet
kubectl uncordon k8s-master
5. Pro každý worker (k8s-1, pak k8s-2):
kubectl drain k8s-1 --ignore-daemonsets --delete-emptydir-data
# na nodu:
kubeadm upgrade node
apt install kubelet=1.XX.x-* kubectl=1.XX.x-*
systemctl daemon-reload && systemctl restart kubelet
kubectl uncordon k8s-1
6. Ověření:
kubectl get nodes # všechny Ready, správná verze
kubectl get pods -A # žádný CrashLoopBackOff
smoke test: curl jeden ingress endpoint
7. Počkat min. 24-48h před dalším hopem, sledovat
Breaking changes per hop
- 1.26 → 1.27: PSP definitivně pryč (nepoužíváme). Některé
--feature-gateflagy odstraněny. - 1.27 → 1.28:
seccompDefaultGA. Některé legacy auth mechanizmy deprecated. - 1.28 → 1.29: In-tree cloud providers odstraněny (nepoužíváme). Legacy ServiceAccount token secrets už se negenerují by default.
- 1.29 → 1.30: ValidatingAdmissionPolicy GA. Některé kubelet flagy odstraněny.
- 1.30 → 1.31: AppArmor GA, drobné změny PV/CSI.
Pro tento cluster (žádné cloud provider integrace, žádné PSP, standardní flannel/metallb) by žádný hop neměl být dramatický.
Komponenty mimo k8s
| Komponenta | Kdy upgradovat | Jak |
|---|---|---|
| Flannel | Po 1.27 nebo 1.28 | kubectl apply -f nový manifest. Drop-in upgrade, VXLAN config zůstane. |
| MetalLB | Po 1.28 (samostatně) | Větší práce: ConfigMap → CRD migrace. Install nová verze, vyrobit IPAddressPool + L2Advertisement CRD, smazat starý ConfigMap. Krátký výpadek (~30s) public IP. |
| ingress-nginx | Souběžně s 1.28 nebo 1.29 | helm upgrade nebo apply nového manifestu. Verze kompatibilní s aktuální k8s. |
| cert-manager | Souběžně s ingress-nginx | Helm upgrade, CRDs se updatují automaticky. |
| kubernetes-dashboard | Kdykoli (low-priority) | v7+ je Helm-only s odlišnou architekturou. Smazat current, nainstalovat čerstvě. |
| CoreDNS | Automaticky s kubeadm upgrade | Není potřeba ručně. |
Doporučená timeline
| Týden | Co |
|---|---|
| 1 | etcd backup automation, IngressClass resource, NFS provisioner deployment |
| 2 | Migrace 2-3 nekritických workloadů na NFS PVC, validate |
| 3 | Upgrade 1.26 → 1.27, ověřit |
| 4 | Upgrade 1.27 → 1.28, ověřit |
| 5 | Upgrade Flannel + ingress-nginx + cert-manager (spolu) |
| 6 | Upgrade 1.28 → 1.29 |
| 7 | MetalLB ConfigMap → CRD migrace (samostatně) |
| 8 | Upgrade 1.29 → 1.30 |
| 9 | Upgrade 1.30 → 1.31 |
| 10 | Migrace zbylých nekritických workloadů na NFS PVC, redeploy dashboard, cleanup |
Cca 10 týdnů na klidné plynulé tempo. Lze zkrátit minimálně na 5 víkendů (jeden hop za víkend).
Postgres během upgradu
Postgres na hostPath na fixed nodu je v pohodě i během upgradu, jen:
- Před každým drainem nodu, kde Postgres běží, manuálně
pg_dumpa uložit mimo cluster. nodeSelectorna pod, aby se nepřemístil.- Při upgradu konkrétního nodu: scale Postgres na 0, drain, upgrade, scale zpět. Krátký výpadek (~5-10 min). Aplikace musí na to být připravené.
Zero-downtime Postgres = migrace na CloudNativePG s replikami. Samostatný projekt, nedělat během k8s upgradu.
Souvisí s Nextcloud replacement
Nextcloud je v plánu na zrušení (replacement = Rust app na Turris, k8s jen jako public proxy). Pro Nextcloud workload tedy:
- Nemigrovat na NFS PVC (zbytečná práce).
- V plánu počítat s tím, že někde v týdnu 5-7 se Nextcloud namespace smaže a nahradí Service+Endpoints+Ingress směrem na Turris.
/k8s/nextcloudadresář na nodu po vyřazení smazat.