Nextcloud (nextcloud-new) #
Neubau von apps/nextcloud nach Kubernetes-Prinzipien. Kernpunkt: statt eines
Pods mit fünf Containern, die sich localhost und Volumes teilen, ist jede
Komponente ein eigener Workload mit eigenem Lebenszyklus.
Die Ablösung erfolgt in-place: gleicher Namespace nextcloud, gleicher
Gleicher Host, gleiche Volumes. Es gibt keinen Parallelbetrieb —
der Cutover ist ein Wartungsfenster, kein sanfter Übergang.
Unterschiede zur Altinstallation #
| Aspekt | Alt (apps/nextcloud) |
Neu (apps/nextcloud-new) |
|---|---|---|
| Nextcloud-Image | ghcr.io/linuxserver/nextcloud (s6, nginx+php-fpm+cron in einem Container, root) |
library/nextcloud:*-fpm-alpine (ein php-fpm-Prozess, uid 33) |
| Chart | bjw-s app-template | offizielles nextcloud/nextcloud |
| Topologie | 1 Pod, 5 Container | 8 Workloads, je 1-2 Container |
| Webserver | im Image gebündelt, Configs handgepflegt im PVC | nginx-Sidecar, Config aus dem Chart generiert |
| Cron | Daemon im Container | CronJob-Ressource, alle 5 Minuten |
| DB / Cache | Sidecar-Container | eigene StatefulSets |
| ClamAV | TCP 3310 auf Loopback, ein Pod | eigener Pod, TCP 3310 über Service |
| Konfiguration | config.php im PVC, Caching-Keys als ConfigMap |
Env + Chart-Werte in values.yaml |
| Credentials | Klartext in values*.yaml |
Secret-Referenzen |
| Probes | keine | Liveness/Readiness/Startup pro Workload |
| Ressourcen | Requests und Limits pro Container | Requests und Limits pro Container |
| php-fpm | www2.conf als ConfigMap |
nextcloud.phpConfigs |
| Startreihenfolge | implizit (ein Pod) | initContainer wartet auf DB und Cache |
.well-known |
— | von der generierten nginx-Config abgedeckt |
Funktionsabgleich #
Jede Funktion der Altinstallation und wo sie im neuen Setup landet:
| Funktion (alt) | Neu | Status |
|---|---|---|
Deployment nextcloud, Container nextcloud |
Deployment nextcloud (fpm + nginx) |
ersetzt |
Container db (mariadb:lts) |
StatefulSet nextcloud-mariadb (mariadb:11.8) |
ersetzt |
Container redis (redis:8.4) |
StatefulSet nextcloud-redis (redis:8.4-alpine) |
ersetzt |
Container clamav |
Deployment nextcloud-clamav |
ersetzt |
Container ssh (PUID 1000) |
Deployment nextcloud-ssh (PUID 33) |
ersetzt |
Service nextcloud-main :443 |
Service nextcloud :8080 (HTTP statt HTTPS zum Backend) |
ersetzt |
Service nextcloud-main :3306 |
Service nextcloud-mariadb:3306 |
ersetzt |
Service nextcloud-ssh-service, LoadBalancer auf Port 4022 (IPv4 und IPv6) |
gleicher Name, gleiche IP, gleicher Port | unverändert |
Ingress nextcloud → gleicher Host |
gleicher Name, gleicher Host | unverändert |
Certificate → nextcloud-server-tls |
unverändert | unverändert |
Middleware nextcloud-stripprefix |
unverändert | unverändert |
ConfigMap clamav-config |
gleicher Name, auf das Nötige eingekürzt | ersetzt |
| Cron (im LSIO-Container) | CronJob nextcloud-cron |
ersetzt |
phpMyAdmin (values-phpmyadmin.yaml, auskommentiert) |
Deployment nextcloud-phpmyadmin unter /php |
jetzt aktiv |
icloudpd privat (values-private.yaml, auskommentiert) |
Deployment nextcloud-icloudpd-private |
vorhanden, replicas: 0 |
icloudpd shared (values-shared.yaml, auskommentiert) |
Deployment nextcloud-icloudpd-shared |
vorhanden, replicas: 0 |
Collabora (in values.yaml auskommentiert) |
nicht übernommen — im Chart über collabora.enabled nachrüstbar |
entfällt |
PVC nextcloud-clamav-socket |
entfällt, ClamAV läuft über TCP | entfällt |
PVC nextcloud-ssh-config |
ersetzt durch nextcloud-sshd-config |
Hostkeys werden kopiert |
Die beiden icloudpd-Workloads stehen auf replicas: 0, weil sie auch in der
Altinstallation nicht aktiv sind (in kustomization.yaml auskommentiert).
Aktivierung ist eine Ein-Zeilen-Änderung, siehe Schritt 11.
Komponenten #
| Workload | Typ | Image | Service |
|---|---|---|---|
nextcloud |
Deployment | library/nextcloud:32.0.9-fpm-alpine + library/nginx:1.29-alpine |
nextcloud:8080 |
nextcloud-cron |
CronJob | dito | — |
nextcloud-mariadb |
StatefulSet | library/mariadb:11.8 |
nextcloud-mariadb:3306 |
nextcloud-redis |
StatefulSet | library/redis:8.4-alpine |
nextcloud-redis:6379 |
nextcloud-clamav |
Deployment | clamav/clamav:1.5.3_base |
nextcloud-clamav:3310 |
nextcloud-phpmyadmin |
Deployment | library/phpmyadmin:5.2-apache |
nextcloud-phpmyadmin:80 |
nextcloud-ssh |
Deployment | lscr.io/linuxserver/openssh-server |
nextcloud-ssh-service LB :4022 |
nextcloud-icloudpd-private |
Deployment | icloudpd/icloudpd:1.32.2 |
— (replicas 0) |
nextcloud-icloudpd-shared |
Deployment | icloudpd/icloudpd:1.32.2 |
— (replicas 0) |
Versionspinning #
Chart 8.9.1 bringt App-Version 32.0.6 mit, die Altinstallation läuft auf
32.0.9. Ein Downgrade verweigert Nextcloud beim Start, deshalb überschreibt
values.yaml den Image-Tag explizit auf 32.0.9-fpm-alpine. Das Label
app.kubernetes.io/version zeigt dadurch 32.0.6 an — kosmetisch, aber gut zu
wissen, bevor man sich über die Diskrepanz wundert.
Nextcloud überspringt keine Major-Versionen. Der Upgrade-Pfad nach der Migration ist einzeln: 32 → 33 (Chart 9.1.4) → 34 (Chart 9.2.5).
php-fpm-Tuning #
Verifiziert in docker.io/library/nextcloud:34.0.3-fpm-alpine:
1pm.max_children = 5 (www.conf, Zeile 127)
2request_terminate_timeout nicht gesetzt
3slowlog nicht gesetzt
4apc.shm_size = 32MDas ist exakt die Konstellation, die am 20.08.2026 die Altinstallation lahmgelegt hat: fünf hängende Requests belegen alle Worker, und weil kein Terminate-Timeout greift, erholt sich die Instanz bis zum manuellen Neustart nicht mehr. Jeder weitere Request läuft in den nginx-Timeout. Ohne Gegenmaßnahme hätte der Cutover den Ausfall mitgenommen.
nextcloud.phpConfigs legt deshalb zz-zyria.conf nach
/usr/local/etc/php-fpm.d/. Die Reihenfolge im Image ist docker.conf,
www.conf, zz-docker.conf — unsere Datei kommt alphabetisch zuletzt und
gewinnt.
Drei Kopplungen, die man nicht einzeln anfassen darf:
pm.max_children = 24setzt das CPU-Limit von 4 voraus. Ohne Limit können 24 Amok-Worker einen ganzen Node belegen.- 24 Worker brauchen etwa 3 GiB. Das Memory-Limit musste deshalb von 2Gi
auf 8Gi, sonst greift der OOM-Killer, bevor PHP sein eigenes
memory_limitzieht. request_terminate_timeout = 900kappt effektiv denfastcgi_read_timeout 3600sdes nginx-Sidecars. Das ist Absicht: ein Worker, der eine Stunde hängt, ist genau das Szenario, das vermieden werden soll. Wer sehr lange Einzelrequests braucht, muss beide Werte gemeinsam anheben.
apc.shm_size geht nicht über phpConfigs: das Chart mountet diese
Dateien bei nginx.enabled: true nach /usr/local/etc/php-fpm.d/, wo nur
Pool-Direktiven gelten. Auch php_admin_value[] hilft nicht, weil APCu sein
Shared-Memory-Segment beim Modul-Init im Master anlegt. Deshalb der Umweg
über die ConfigMap nextcloud-php-ini nach
/usr/local/etc/php/conf.d/zz-zyria.ini.
Der Slowlog liegt unter /tmp und ist damit beim Pod-Neustart weg. Im
offiziellen Image gibt es kein persistentes Log-Verzeichnis, und der Webroot
unter /var/www/html wird von der Integritätsprüfung erfasst. Beim Cutover
prüfen, ob slowlog = /proc/self/fd/2 funktioniert — dann landet er im
Container-Log und damit in fluent-bit.
Trusted Proxies #
TRUSTED_PROXIES stand auf 10.42.0.0/16, dem k3s-Default. Weicht der
Cluster davon ab oder laeuft er Dual-Stack, muss der Wert beide Familien
abdecken. Die tatsaechlichen Bereiche liefert:
1kubectl get nodes -o custom-columns=NAME:.metadata.name,CIDRS:.spec.podCIDRs
2kubectl get pod -n kube-system -l app.kubernetes.io/name=traefik \
3 -o custom-columns=NAME:.metadata.name,IPS:.status.podIPsFehlt das v6-Präfix, wird jeder über IPv6 eingehende Request nicht als
Proxy-Request erkannt: Nextcloud protokolliert dann die Traefik-Pod-IP als
remoteAddr, Brute-Force-Schutz und Rate-Limiting treffen den Ingress statt
den Angreifer — und ein einzelner auffälliger v6-Client bremst alle anderen
mit aus. Im Log der Altinstallation standen 15 solcher Einträge, in denen
eine ULA-Adresse aus dem Pod-Netz als vermeintliche Client-Adresse auftauchte —
das ist das Erkennungsmerkmal für einen fehlenden v6-Eintrag.
Der Wert ist space-separiert (reverse-proxy.config.php im Image macht
explode(' ', …)), nicht komma-separiert.
Vor dem Cutover prüfen: Die Altinstallation vertraut zusätzlich
172.16.0.0/12sowie zwei öffentlichen v6-Präfixen des Hosters. Ob dort noch etwas davorhängt, das diese Adressen braucht, ist ungeklärt — falls ja, gehören sie in die Liste. Die konkreten Werte stehen in dervalues.yamlder Altinstallation.
Storage #
storage.yaml übernimmt die PV/PVC-Definitionen aus
apps/nextcloud/storage.yaml wortgleich. Das ist keine Redundanz, sondern
Voraussetzung: PVC-Specs sind weitgehend immutable, jede Abweichung führt beim
Wechsel der ArgoCD-Application zu einem Sync-Fehler statt zu einer Übernahme.
| PVC | Größe | Inhalt | Herkunft |
|---|---|---|---|
nextcloud-data |
350 Gi | Nutzdaten | übernommen |
nextcloud-clamav-db |
2 Gi | Virensignaturen | übernommen |
icloudpd-cookie |
10 Mi | Apple-Session-Cookies | übernommen |
nextcloud-html |
10 Gi | Webroot: App-Code, config/, custom_apps/ |
neu |
nextcloud-sshd-config |
100 Mi | SSH-Hostkeys | neu |
data-nextcloud-mariadb-0 |
10 Gi | MariaDB (volumeClaimTemplate) | neu |
data-nextcloud-redis-0 |
1 Gi | Redis-AOF (volumeClaimTemplate) | neu |
nextcloud-config |
5 Gi | altes LSIO-/config |
Rückfallebene |
nextcloud-db |
10 Gi | alter MariaDB-Bestand | Rückfallebene |
nextcloud-redis |
1 Gi | alter Redis-Bestand | Rückfallebene |
ReadWriteOnce + podAffinity: nextcloud-data ist RWO. Alle Pods, die es
mounten — die Nextcloud-App, die Cron-CronJob, SSH und icloudpd — sind per
podAffinity an den Node der App gebunden.
Datenverzeichnis bleibt /data. Das Chart würde per Default nach
/var/www/html/data mounten. Die Datenbank speichert Storage-IDs aber als
local::/data/; bei geändertem Pfad legt Nextcloud einen zweiten Storage an
und der komplette Dateibestand müsste per occ files:scan neu eingelesen
werden. Bei 350 Gi ist das keine Option, deshalb nextcloud.datadir: /data.
Volume-Layout. Das Chart mountet nextcloud-data fest mit subPath: data
(hardcodiert, nicht abschaltbar). Im Volume liegen die Nutzdaten aktuell in der
Wurzel und müssen einmalig nach data/ verschoben werden — ein Rename im
selben Dateisystem, kein Kopieren. Die Mounts für SSH und icloudpd in
values-services.yaml führen denselben Offset mit.
Secrets #
Es gibt in diesem Repo kein sealed-secrets/external-secrets. Die folgenden
Secrets werden einmalig von Hand im Namespace nextcloud angelegt und sind
nicht in Git.
Vorher: Die Credentials in
apps/nextcloud/values.yaml,values-private.yamlundvalues-shared.yamlliegen im Klartext in der Git-Historie — MariaDB-Root, das Apple-Passwort und das SMTP-Passwort. Sie gelten als kompromittiert. Beim Anlegen der neuen Secrets neue Passwörter vergeben, nicht die alten übernehmen. Das Apple-Passwort und das SMTP-Passwort zusätzlich beim jeweiligen Anbieter rotieren. Das Entfernen der Dateien beseitigt die Historie nicht.
1# Datenbank. db-hostname-or-ip zeigt auf den Service, nicht auf localhost.
2kubectl create secret generic nextcloud-db -n nextcloud \
3 --from-literal=db-username=nextcloud \
4 --from-literal=db-password="$(openssl rand -base64 24)" \
5 --from-literal=db-name=nextcloud \
6 --from-literal=db-hostname-or-ip=nextcloud-mariadb \
7 --from-literal=mariadb-root-password="$(openssl rand -base64 32)"
8
9# Admin-Account für die Erstinstallation in Schritt 6.
10kubectl create secret generic nextcloud-admin -n nextcloud \
11 --from-literal=nextcloud-username=admin \
12 --from-literal=nextcloud-password="$(openssl rand -base64 24)"
13
14kubectl create secret generic nextcloud-redis -n nextcloud \
15 --from-literal=redis-password="$(openssl rand -base64 24)"
16
17# Nur nötig, wenn icloudpd aktiviert wird.
18kubectl create secret generic nextcloud-icloudpd -n nextcloud \
19 --from-literal=apple-username='<benutzer>@<domain>' \
20 --from-literal=apple-password='<neues Apple-App-Passwort>' \
21 --from-literal=smtp-username='<benutzer>@<domain>' \
22 --from-literal=smtp-password='<neues SMTP-Passwort>'Die erzeugten Passwörter danach auslesen und im Passwortmanager ablegen:
1kubectl -n nextcloud get secret nextcloud-db -o jsonpath='{.data}' \
2 | python3 -c 'import json,sys,base64;
3 [print(k, base64.b64decode(v).decode()) for k,v in json.load(sys.stdin).items()]'Migration #
Ausgangslage: apps/nextcloud läuft. Ziel: dieselbe Instanz, dieselben Daten,
neue Struktur. Die Schritte 1-4 laufen ohne Downtime, ab Schritt 5 ist
Die Nextcloud-Oberfläche ist nicht erreichbar.
Schritt 1 — Ist-Zustand gegen storage.yaml abgleichen #
storage.yaml muss die vorhandenen PVCs exakt beschreiben, sonst scheitert der
Sync an immutablen Feldern:
1kubectl -n nextcloud get pvc \
2 -o custom-columns=NAME:.metadata.name,SIZE:.spec.resources.requests.storage,SC:.spec.storageClassName,VOL:.spec.volumeNameAbweichungen in storage.yaml nachziehen, bevor es weitergeht.
Schritt 2 — Snapshots #
1# Über die Longhorn-UI oder per CRD: Snapshot von nextcloud-data und
2# nextcloud-db anlegen. Das ist die einzige echte Rückfallebene für die
3# Nutzdaten, sobald Schritt 8 gelaufen ist.
4kubectl -n longhorn-system get volumes.longhorn.io nextcloud-data nextcloud-dbSchritt 3 — Secrets anlegen #
Siehe Abschnitt oben. Ohne diese Secrets startet in Schritt 6 nichts.
Schritt 4 — Identität der Altinstallation sichern #
Kritisch.
secret,passwordsaltundinstanceidaus der altenconfig.phpmüssen übernommen werden. Ohnesecretsind alle verschlüsselten Werte in der Datenbank (App-Passwörter, Zugangsdaten für externen Speicher) verloren; ohneinstanceidfindet Nextcloud dasappdata_<instanceid>-Verzeichnis in den Nutzdaten nicht.
1OLD=$(kubectl -n nextcloud get pod -l app.kubernetes.io/name=nextcloud \
2 -o jsonpath='{.items[0].metadata.name}')
3
4kubectl -n nextcloud exec "$OLD" -c nextcloud -- \
5 cat /config/www/nextcloud/config/config.php > /tmp/config.php.alt
6
7grep -E "instanceid|passwordsalt|'secret'" /tmp/config.php.altEbenso die SSH-Hostkeys, damit sich der Fingerprint für Ansible nicht ändert:
1kubectl -n nextcloud exec "$OLD" -c ssh -- \
2 tar cf - -C /config ssh_host_keys > /tmp/ssh_host_keys.tarUnd die Liste der Drittanbieter-Apps, die das offizielle Image nicht mitbringt:
1kubectl -n nextcloud exec "$OLD" -c nextcloud -- occ app:list > /tmp/apps.altSchritt 5 — Downtime beginnt: Wartungsmodus und finaler Dump #
1kubectl -n nextcloud exec "$OLD" -c nextcloud -- occ maintenance:mode --on
2
3kubectl -n nextcloud exec "$OLD" -c db -- \
4 sh -c 'mariadb-dump --single-transaction --default-character-set=utf8mb4 \
5 -u root -p"$MARIADB_ROOT_PASSWORD" nextcloud' > /tmp/nextcloud.sql
6
7ls -lh /tmp/nextcloud.sql # Plausibilitätsprüfung: nicht leer, nicht winzigSchritt 6 — Umschalten #
In manifests.yaml zeigt der bestehende Eintrag auf das neue Verzeichnis —
gleicher Application-Name, gleicher Namespace, nur ein anderer Pfad:
1 - name: nextcloud
2 dir: "apps/nextcloud-new" # vorher: apps/nextcloud
3 namespace: nextcloudDanach die alte Deployment löschen. Das ist kein optionaler Schritt: der
Label-Selector wechselt von app.kubernetes.io/controller: main auf
app.kubernetes.io/component: app, und spec.selector ist immutable. Ohne
Löschen bricht der Sync mit field is immutable ab.
1kubectl -n nextcloud delete deployment nextcloudArgoCD synct jetzt den neuen Stand. Das Webroot-PVC ist leer und im
Datenvolume ist data/ noch nicht vorhanden — der Entrypoint sieht also eine
jungfräuliche Installation, legt ein frisches config.php an und
initialisiert das leere Schema in der neuen MariaDB. Genau das ist gewollt:
die Altdaten liegen weiterhin unberührt in der Wurzel des Volumes.
1kubectl -n nextcloud rollout status deploy/nextcloud --timeout=20m
2kubectl -n nextcloud get podsSchritt 7 — Identität übertragen #
1NC="kubectl -n nextcloud exec deploy/nextcloud -c nextcloud -- php /var/www/html/occ"
2
3$NC config:system:set instanceid --value='<Wert aus Schritt 4>'
4$NC config:system:set passwordsalt --value='<Wert aus Schritt 4>'
5$NC config:system:set secret --value='<Wert aus Schritt 4>'Schritt 8 — Datenbank und Nutzdaten übernehmen #
1kubectl -n nextcloud scale deploy/nextcloud --replicas=0
2
3kubectl -n nextcloud exec -i sts/nextcloud-mariadb -- \
4 sh -c 'mariadb -u root -p"$MARIADB_ROOT_PASSWORD" \
5 -e "DROP DATABASE nextcloud; CREATE DATABASE nextcloud
6 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"'
7
8kubectl -n nextcloud exec -i sts/nextcloud-mariadb -- \
9 sh -c 'mariadb -u root -p"$MARIADB_ROOT_PASSWORD" nextcloud' < /tmp/nextcloud.sql
10
11# Der Dump bringt keine Grants mit.
12kubectl -n nextcloud exec sts/nextcloud-mariadb -- \
13 sh -c 'mariadb -u root -p"$MARIADB_ROOT_PASSWORD" \
14 -e "GRANT ALL ON nextcloud.* TO '"'"'nextcloud'"'"'@'"'"'%'"'"'; FLUSH PRIVILEGES;"'Jetzt die Nutzdaten unter data/ bringen und auf www-data (33) umschreiben.
Der Helper-Pod braucht podAffinity nicht, weil die Nextcloud-Deployment auf 0
steht und das RWO-Volume damit frei ist:
1kubectl -n nextcloud run migrate --rm -it --restart=Never \
2 --image=alpine:3.22 --overrides='
3{
4 "spec": {
5 "securityContext": {"runAsUser": 0},
6 "containers": [{
7 "name": "migrate", "image": "alpine:3.22",
8 "command": ["sh"], "stdin": true, "tty": true,
9 "volumeMounts": [{"name": "d", "mountPath": "/mnt"}]
10 }],
11 "volumes": [{"name": "d",
12 "persistentVolumeClaim": {"claimName": "nextcloud-data"}}]
13 }
14}' -- shIm Pod:
1ls /mnt # erwartet: die Altdaten + ein frisches data/
2rm -rf /mnt/data # Reste der Erstinstallation aus Schritt 6
3mkdir -p /mnt/data
4find /mnt -mindepth 1 -maxdepth 1 ! -name data -exec mv -t /mnt/data {} +
5ls /mnt/data # erwartet: appdata_<alte-id>, <benutzerverzeichnis>, .ocdata
6chown -R 33:33 /mnt
7exitchown -R über 350 Gi läuft je nach Dateizahl lange und darf nicht
unterbrochen werden.
Die SSH-Hostkeys aus Schritt 4 auf demselben Weg in das PVC
nextcloud-sshd-config entpacken (tar xf - -C /mnt, Ziel ssh_host_keys/).
Schritt 9 — Hochfahren und reparieren #
1kubectl -n nextcloud scale deploy/nextcloud --replicas=1
2kubectl -n nextcloud rollout status deploy/nextcloud --timeout=30m
3
4$NC maintenance:mode --on
5$NC upgrade
6$NC maintenance:repair --include-expensive
7$NC db:add-missing-indices
8$NC db:add-missing-columns
9$NC db:add-missing-primary-keys
10$NC maintenance:mode --offEin vollständiges occ files:scan --all ist nicht nötig, weil
datadirectory unverändert /data ist und die Storage-IDs damit passen.
Wenn einzelne Ordner fehlen, gezielt nachscannen:
$NC files:scan --path="/fabrice/files/…".
Die Drittanbieter-Apps aus /tmp/apps.alt gegen $NC app:list abgleichen und
fehlende über die Weboberfläche neu installieren.
Schritt 10 — ClamAV umstellen #
Der Virenscanner spricht nicht mehr über einen Socket, sondern über TCP:
1$NC config:app:set files_antivirus av_mode --value=daemon
2$NC config:app:set files_antivirus av_host --value=nextcloud-clamav
3$NC config:app:set files_antivirus av_port --value=3310
4$NC config:app:set files_antivirus av_stream_max_length --value=536870912Der ClamAV-Pod braucht beim Erststart mehrere Minuten, bis freshclam die
Signaturen geladen hat. Bis dahin steht er auf Ready: false — das ist die
startupProbe, kein Fehler.
Schritt 11 — Abnahme #
1kubectl -n nextcloud get pods,svc,pvc,cronjob
2$NC status
3$NC check
4$NC config:system:get trusted_domains
5$NC config:system:get datadirectory # muss /data sein
6$NC config:system:get instanceid # muss dem alten Wert entsprechenÜber die Weboberfläche: Anmeldung mit einem bestehenden Konto, Dateiliste,
Up- und Download, Freigabe-Link, CalDAV/CardDAV, /php hinter Authentik,
ein Upload gegen den Virenscanner, und einen Cron-Lauf abwarten
(kubectl -n nextcloud get jobs).
SSH gegen den unveränderten Endpunkt:
1ssh -p 4022 <benutzer>@<loadbalancer-ip>Wenn alles steht, icloudpd aktivieren: in values-services.yaml bei beiden
Controllern replicas: 0 auf 1 setzen.
Schritt 12 — Aufräumen #
Erst nach ein paar Tagen stabilen Betriebs:
networkpolicies.yamlinkustomization.yamlaufnehmen.- Den Altbestand-Block aus
storage.yamlentfernen (nextcloud-config,nextcloud-db,nextcloud-redis). Die PVs stehen aufRetain, die Longhorn-Volumes bleiben also erhalten und müssen dort separat gelöscht werden. git rm -r apps/nextcloudundgit mv apps/nextcloud-new apps/nextcloud, dann den Pfad inmanifests.yamlzurückstellen. Damit heißt das Verzeichnis wieder wie der Namespace, wie es die Repo-Konvention vorsieht.
Rollback #
| Zeitpunkt | Rückweg |
|---|---|
| vor Schritt 6 | nichts zu tun, die Altinstallation läuft |
| nach Schritt 6, vor Schritt 8 | manifests.yaml zurückstellen, kubectl -n nextcloud delete deployment nextcloud, Sync abwarten. Die Altdaten liegen unverändert in der Volume-Wurzel. |
| nach Schritt 8 | nur über den Longhorn-Snapshot aus Schritt 2 — die Nutzdaten sind dann nach data/ verschoben und auf uid 33 umgeschrieben |
Das Verschieben in Schritt 8 ist prinzipiell umkehrbar (mv /mnt/data/* /mnt/),
das chown auf PUID 1000 ebenfalls. Verlassen sollte man sich darauf nicht —
deshalb der Snapshot.
Lokale Validierung #
1kubectl kustomize --enable-helm apps/nextcloud-newDas legt apps/nextcloud-new/charts/ an — von .gitignore abgedeckt, aber
nach dem Testen aufräumen.
Abhängigkeiten #
- k3s-Cluster mit Longhorn (StorageClass
longhorn) - Traefik mit Entrypoint
websecureund den Middlewareslocalnetundauthentikim Namespacekube-system - cert-manager mit ClusterIssuer
letsencrypt-production - MetalLB für den SSH-LoadBalancer (feste, mit anderen Diensten geteilte IP)
Dokumentation #
- Nextcloud Admin Manual
- Nextcloud Helm Chart
- Nextcloud Docker Image
- bjw-s app-template
- ClamAV Documentation