Compare commits

...

2 Commits

Author SHA1 Message Date
f0a02c3740 ADD: added working nextcloud version 2026-03-02 20:49:50 +01:00
f0c47beaad ADD: added nextcloud 2026-02-27 20:54:54 +01:00
23 changed files with 764 additions and 33 deletions

View File

@@ -0,0 +1,2 @@
smb user nextcloud
smb pass qCPJgc7C

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
# Konfiguration (anpassen falls nötig)
NAMESPACE="nextcloud"
RELEASE="nextcloud"
CHART="nextcloud/nextcloud"
VALUES_FILE="values-nextcloud.yaml"
SMB_SCRIPT_FILE="install-smb.sh"
CONFIGMAP_NAME="smb-install-script"
HELM_REPO_NAME="nextcloud"
HELM_REPO_URL="https://nextcloud.github.io/helm/"
WAIT_TIMEOUT="600s" # Timeout für Pod-Readiness (10m)
# Hilfsfunktionen
err() { echo "ERROR: $*" >&2; exit 1; }
info() { echo "INFO: $*"; }
confirm() {
echo
echo "!!! Achtung: Das Skript wird das Helm-Release '$RELEASE' im Namespace '$NAMESPACE' deinstallieren"
echo " und alle zugehörigen PersistentVolumeClaims (PVCs) löschen. Daten gehen verloren!"
echo
read -p "Tippe DELETE um fortzufahren (oder STRG-C zum Abbrechen): " ans
if [ "$ans" != "DELETE" ]; then
echo "Abgebrochen."
exit 0
fi
}
check_tools() {
command -v kubectl >/dev/null 2>&1 || err "kubectl ist nicht installiert oder nicht in PATH"
command -v helm >/dev/null 2>&1 || err "helm ist nicht installiert oder nicht in PATH"
}
create_namespace_if_missing() {
if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then
info "Namespace $NAMESPACE existiert nicht — wird angelegt"
kubectl create namespace "$NAMESPACE"
else
info "Namespace $NAMESPACE existiert"
fi
}
uninstall_release() {
if helm -n "$NAMESPACE" status "$RELEASE" >/dev/null 2>&1; then
info "Helm-Release '$RELEASE' gefunden -> deinstalliere..."
helm -n "$NAMESPACE" uninstall "$RELEASE"
info "Warte bis alle Pods des Releases entfernt sind..."
# Warte bis keine Pods mehr mit dem Release-Label vorhanden sind
for i in $(seq 1 60); do
sleep 2
COUNT=$(kubectl -n "$NAMESPACE" get pods -l app.kubernetes.io/instance="$RELEASE" --no-headers 2>/dev/null | wc -l || true)
if [ "$COUNT" -eq 0 ]; then
break
fi
echo -n "."
done
echo
else
info "Kein bestehendes Helm-Release '$RELEASE' gefunden"
fi
}
delete_pvcs() {
# Liste PVCs, die zum Release gehören (Label app.kubernetes.io/instance)
PVCS=$(kubectl -n "$NAMESPACE" get pvc -l app.kubernetes.io/instance="$RELEASE" -o jsonpath='{.items[*].metadata.name}' || true)
if [ -z "$PVCS" ]; then
info "Keine PVCs mit Label app.kubernetes.io/instance=$RELEASE gefunden"
return
fi
info "Folgende PVCs werden gelöscht: $PVCS"
kubectl -n "$NAMESPACE" delete pvc $PVCS
info "Warte auf Löschung der PVCs..."
for pvc in $PVCS; do
kubectl -n "$NAMESPACE" wait --for=delete pvc/"$pvc" --timeout=120s || true
done
}
recreate_configmap() {
if [ ! -f "$SMB_SCRIPT_FILE" ]; then
err "SMB-Script '$SMB_SCRIPT_FILE' fehlt. Lege die Datei an oder passe \$SMB_SCRIPT_FILE an."
fi
info "Erstelle/aktualisiere ConfigMap $CONFIGMAP_NAME aus $SMB_SCRIPT_FILE"
kubectl -n "$NAMESPACE" create configmap "$CONFIGMAP_NAME" --from-file="$SMB_SCRIPT_FILE" -o yaml --dry-run=client | kubectl apply -f -
}
add_helm_repo() {
# Add repo if not exists
if ! helm repo list | awk '{print $1}' | grep -xq "$HELM_REPO_NAME"; then
info "Füge Helm-Repo $HELM_REPO_NAME hinzu"
helm repo add "$HELM_REPO_NAME" "$HELM_REPO_URL"
fi
helm repo update
}
install_release() {
if [ ! -f "$VALUES_FILE" ]; then
err "Values-File '$VALUES_FILE' nicht gefunden. Abbruch."
fi
info "Installiere Helm-Release '$RELEASE' mit values '$VALUES_FILE'"
helm upgrade --install "$RELEASE" "$CHART" -n "$NAMESPACE" -f "$VALUES_FILE"
}
wait_pods_ready() {
info "Warte bis alle Pods des Releases ready sind (Timeout $WAIT_TIMEOUT)..."
# Warte auf Ready-Bedingung für alle Pods mit dem instance-Label
if ! kubectl -n "$NAMESPACE" wait --for=condition=Ready pod -l app.kubernetes.io/instance="$RELEASE" --all --timeout="$WAIT_TIMEOUT"; then
echo "WARNUNG: Nicht alle Pods sind innerhalb des Timeouts ready. Aktuelle Pods:"
kubectl -n "$NAMESPACE" get pods -o wide
return 1
fi
info "Alle Pods sind ready."
}
post_checks() {
info "Prüfe smbclient im Nextcloud-Container (falls Pod läuft)..."
POD=$(kubectl -n "$NAMESPACE" get pod -l app.kubernetes.io/instance="$RELEASE",app.kubernetes.io/component=app -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
if [ -n "$POD" ]; then
kubectl -n "$NAMESPACE" exec -it "$POD" -- sh -c 'command -v smbclient && smbclient -V || echo "smbclient nicht gefunden"'
else
info "Nextcloud-App-Pod nicht gefunden (noch nicht gestartet)."
fi
info "Führe 'occ files_external:backends' aus (falls Pod läuft)..."
if [ -n "$POD" ]; then
kubectl -n "$NAMESPACE" exec -it "$POD" -- sh -c 'php /var/www/html/occ files_external:backends || true'
fi
}
main() {
check_tools
confirm
create_namespace_if_missing
uninstall_release
delete_pvcs
# recreate_configmap
# add_helm_repo
# install_release
# # Warte auf Pods
# if ! wait_pods_ready; then
# info "Einige Pods sind möglicherweise nicht ready. Schaue in die Logs:"
# kubectl -n "$NAMESPACE" get pods
# kubectl -n "$NAMESPACE" logs -l app.kubernetes.io/instance="$RELEASE" --tail=100 || true
# fi
# post_checks
echo
echo "Fertig. Prüfe die Nextcloud-WebUI und gegebenenfalls die External Storage Einstellungen."
}
main "$@"

View File

@@ -0,0 +1,20 @@
#!/bin/sh
set -eux
# Installiere SMB Tools in einem Init-Container und kopiere sie in ein shared Volume,
# damit der Nextcloud-Container smbclient nutzen kann.
apt-get update
apt-get install -y --no-install-recommends smbclient libsmbclient-dev libwbclient0 ca-certificates
mkdir -p /opt/smb-tools/bin /opt/smb-tools/lib
# Binary
cp -a /usr/bin/smbclient /opt/smb-tools/bin/
# Libraries (best effort; Pfade können je nach Debian-Release leicht variieren)
cp -a /usr/lib/x86_64-linux-gnu/libsmbclient.so* /opt/smb-tools/lib/ || true
cp -a /usr/lib/x86_64-linux-gnu/libwbclient.so* /opt/smb-tools/lib/ || true
# Debug-Ausgabe
/opt/smb-tools/bin/smbclient -V || true
ls -la /opt/smb-tools/bin /opt/smb-tools/lib || true

View File

@@ -0,0 +1,58 @@
# Chart-internes Persistence deaktivieren (nicht ganzes Webroot mounten)
persistence:
enabled: false
# Nextcloud Config
nextcloud:
host: 192.168.178.138
username: admin
password: admin
datadir: /data
trustedDomains:
- 192.168.178.138
- nextcloud.lan
- knode0
# PodSecurityContext wichtig für NFS (www-data ist UID/GID 33)
podSecurityContext:
fsGroup: 33
# Extra Volume nur für /data mounten
extraVolumes:
- name: nextcloud-data
persistentVolumeClaim:
claimName: nextcloud-data-pvc
extraVolumeMounts:
- name: nextcloud-data
mountPath: /data
# MariaDB intern
internalDatabase:
enabled: false
mariadb:
enabled: true
architecture: standalone
auth:
database: nextcloud
username: nextcloud
password: nextcloud
rootPassword: "123456"
primary:
persistence:
enabled: true
storageClass: local-path
size: 10Gi
# Redis
redis:
enabled: true
auth:
enabled: true
password: redis
master:
persistence:
enabled: true
storageClass: local-path
size: 1Gi

View File

@@ -0,0 +1,91 @@
global:
security:
allowInsecureImages: true
image:
registry: docker.io
repository: library/nextcloud
flavor: apache
tag: "33.0.0-apache"
pullPolicy: IfNotPresent
service:
type: NodePort
port: 80
nodePort: 30180
internalDatabase:
enabled: false
nextcloud:
username: "admin"
password: "admin"
host: "192.168.178.138"
trustedDomains:
- "192.168.178.138"
- "nextcloud.lan"
- "knode0"
persistence:
enabled: true
storageClass: local-path
accessMode: ReadWriteOnce
size: 5Gi
# --- SMB "Nachinstallation" via ConfigMap + initContainer ---
extraVolumes:
- name: smb-tools
emptyDir: {}
- name: smb-install-script
configMap:
name: smb-install-script
defaultMode: 0755
extraVolumeMounts:
- name: smb-tools
mountPath: /opt/smb-tools
- name: smb-install-script
mountPath: /scripts
extraInitContainers:
- name: install-smbclient
image: debian:bookworm-slim
imagePullPolicy: IfNotPresent
command: ["sh", "/scripts/install-smb.sh"]
volumeMounts:
- name: smb-tools
mountPath: /opt/smb-tools
- name: smb-install-script
mountPath: /scripts
extraEnv:
- name: PATH
value: "/opt/smb-tools/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
- name: LD_LIBRARY_PATH
value: "/opt/smb-tools/lib"
mariadb:
enabled: true
architecture: standalone
auth:
database: nextcloud
username: nextcloud
password: "nextcloud"
rootPassword: "nextcloud"
primary:
persistence:
enabled: true
storageClass: local-path
size: 10Gi
redis:
enabled: true
auth:
enabled: true
password: "redis"
master:
persistence:
enabled: true
storageClass: local-path
size: 1Gi

View File

@@ -0,0 +1,33 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: collabora
namespace: nextcloud
spec:
replicas: 1
selector:
matchLabels:
app: collabora
template:
metadata:
labels:
app: collabora
spec:
containers:
- name: collabora
image: collabora/code:latest
imagePullPolicy: Always
ports:
- containerPort: 9980
env:
- name: domain
value: "henryathome.home64.de"
- name: extra_params
value: "--o:ssl.enable=false --o:ssl.termination=true"
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2"

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: collabora-nodeport
namespace: nextcloud
spec:
type: NodePort
selector:
app: collabora
ports:
- port: 9980
targetPort: 9980
nodePort: 30980

View File

@@ -0,0 +1,44 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mariadb
namespace: nextcloud
spec:
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:10.8
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
- name: MYSQL_DATABASE
value: nextcloud
- name: MYSQL_USER
value: nextcloud
- name: MYSQL_PASSWORD
value: nextcloud
ports:
- containerPort: 3306
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: mariadb-data
mountPath: /var/lib/mysql
volumes:
- name: mariadb-data
persistentVolumeClaim:
claimName: nextcloud-mariadb-pvc

View File

@@ -0,0 +1,32 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-mariadb-pvc
namespace: nextcloud
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: local-path # <-- explicit default StorageClass
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nextcloud-mariadb-pv
labels:
app: mariadb
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-path
claimRef:
namespace: nextcloud
name: nextcloud-mariadb-pvc
hostPath:
path: /var/lib/nextcloud/mariadb-data
type: DirectoryOrCreate

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: mariadb
namespace: nextcloud
spec:
selector:
app: mariadb
ports:
- port: 3306
targetPort: 3306

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-apps-pvc
namespace: nextcloud
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
volumeName: nextcloud-apps-pv
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nextcloud-apps-pv
labels:
app: nextcloud
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
claimRef:
namespace: nextcloud
name: nextcloud-apps-pvc
hostPath:
path: /var/lib/nextcloud/custom_apps
type: DirectoryOrCreate

View File

@@ -0,0 +1,32 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-config-pvc
namespace: nextcloud
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: local-path # match mariadb local-path style
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nextcloud-config
labels:
app: nextcloud
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-path
claimRef:
namespace: nextcloud
name: nextcloud-config-pvc
hostPath:
path: /var/lib/nextcloud/nextcloud-config
type: DirectoryOrCreate

View File

@@ -0,0 +1,21 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: nextcloud-webcron
namespace: nextcloud
spec:
schedule: "*/5 * * * *" # alle 5 Minuten
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
activeDeadlineSeconds: 300
template:
spec:
restartPolicy: Never
containers:
- name: webcron
image: curlimages/curl:8.5.0
command: ["/bin/sh", "-c"]
args:
- 'until curl -fsS http://nextcloud.nextcloud.svc.cluster.local/status.php; do echo "waiting for nextcloud..."; sleep 5; done; curl -s -o /dev/null -w "%{http_code}\n" http://nextcloud.nextcloud.svc.cluster.local/cron.php'

View File

@@ -0,0 +1,73 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextcloud
namespace: nextcloud
spec:
replicas: 1
selector:
matchLabels:
app: nextcloud
template:
metadata:
labels:
app: nextcloud
spec:
# fsGroup sorgt dafür, dass gemountete Volumes die Gruppe www-data (33) bekommen
securityContext:
fsGroup: 33
containers:
- name: nextcloud
image: nextcloud:33-apache
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
# - name: NEXTCLOUD_ADMIN_USER
# value: admin
# - name: NEXTCLOUD_ADMIN_PASSWORD
# value: admin
- name: MYSQL_HOST
value: mariadb.nextcloud.svc.cluster.local
- name: MYSQL_DATABASE
value: nextcloud
- name: MYSQL_USER
value: nextcloud
- name: MYSQL_PASSWORD
value: "nextcloud"
- name: REDIS_HOST
value: redis.nextcloud.svc.cluster.local
- name: NEXTCLOUD_TRUSTED_DOMAINS
value: "henryathome.home64.de,192.168.178.0/24,192.168.178.138,nextcloud.nextcloud.svc.cluster.local"
- name: TRUSTED_PROXIES
value: "192.168.178.120"
- name: OVERWRITEHOST
value: "henryathome.home64.de"
- name: OVERWRITEPROTOCOL
value: "https"
- name: OVERWRITECLIURL
value: "https://henryathome.home64.de"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "4Gi"
cpu: "3000m"
volumeMounts:
- name: data
mountPath: /var/www/html/data
- name: config
mountPath: /var/www/html/config
- name: apps
mountPath: /var/www/html/custom_apps
volumes:
- name: data
persistentVolumeClaim:
claimName: nextcloud-data-pvc
- name: config
persistentVolumeClaim:
claimName: nextcloud-config-pvc
- name: apps
persistentVolumeClaim:
claimName: nextcloud-apps-pvc

View File

@@ -0,0 +1,33 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nextcloud-data-nfs
spec:
capacity:
storage: 500Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
mountOptions:
- vers=4
- rsize=65536
- wsize=65536
- noatime
nfs:
server: 192.168.178.186 # <-- ERSETZEN: IP oder Hostname deiner NAS
path: /volume1/Nextcloud/data # <-- ERSETZEN: Pfad zum Share auf der NAS (z.B. /volume1/nextcloud)
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-data-pvc
namespace: nextcloud
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs
resources:
requests:
storage: 500Gi
volumeName: pv-nextcloud-data-nfs

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: nextcloud
namespace: nextcloud
spec:
type: NodePort
selector:
app: nextcloud
ports:
- port: 80
targetPort: 80
nodePort: 30180

View File

@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: nextcloud
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
emptyDir: {}

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: nextcloud
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-data-pvc
namespace: nextcloud
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs
resources:
requests:
storage: 500Gi
volumeName: pv-nextcloud-data-nfs

View File

@@ -112,4 +112,4 @@ spec:
claimName: immich-library-pvc claimName: immich-library-pvc
- name: ext-library - name: ext-library
persistentVolumeClaim: persistentVolumeClaim:
claimName: photoprism-storage claimName: photoprism-library-pvc

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: photoprism-library-pvc
namespace: photoprism
spec:
storageClassName: nfs
volumeName: photos-nfs-pv
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi

View File

@@ -1,31 +1,3 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: photoprism-storage
namespace: photoprism
spec:
storageClassName: nfs
volumeName: nfs-pv
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
---
#apiVersion: v1
#kind: PersistentVolumeClaim
#metadata:
# name: photoprism-originals
# namespace: photoprism
#spec:
# storageClassName: nfs
# volumeName: nfs-pv
# accessModes:
# - ReadWriteMany
# resources:
# requests:
# storage: 100Gi
---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
@@ -76,7 +48,23 @@ spec:
value: "true" value: "true"
- name: PHOTOPRISM_SIDECAR_JSON - name: PHOTOPRISM_SIDECAR_JSON
value: "true" value: "true"
# resources: - name: PHOTOPRISM_OIDC_URI
value: "https://authentik.henryathome.home64.de/application/o/photoprism/"
- name: PHOTOPRISM_OIDC_CLIENT
value: "UL29po2otoaH2mioipq9cekGkFSUvX6hTywaRsZ6"
- name: PHOTOPRISM_OIDC_SECRET
value: "Dx1FXPuFMtDFliZaZbpCOnlYvJYsFiBW533IyeRVdsT4y6XIAsHKVtLFYBijLXVQElu0UqoGOF1JJ8E2Gy3v97chQf6kXBQ5T2UMOXeFWSUlzhXVbNTFGwhITqPizycv"
- name: PHOTOPRISM_OIDC_PROVIDER
value: authentik
- name: PHOTOPRISM_OIDC_REDIRECT
value: "true"
- name: PHOTOPRISM_OIDC_REGISTER
value: "true"
- name: PHOTOPRISM_OIDC_ICON
value: "/static/img/oidc.svg"
- name: PHOTOPRISM_OIDC_USERNAME
value: "email"
resources:
# requests: # requests:
# cpu: "100m" # cpu: "100m"
# memory: "128Mi" # memory: "128Mi"
@@ -85,7 +73,7 @@ spec:
# memory: "512Mi" # memory: "512Mi"
volumeMounts: volumeMounts:
- mountPath: /photoprism/ - mountPath: /photoprism/
name: photoprism-storage name: photoprism-library-pvc
# - mountPath: /photoprism/storage # - mountPath: /photoprism/storage
# name: photoprism-storage # name: photoprism-storage
# - mountPath: /photoprism/originals # - mountPath: /photoprism/originals
@@ -95,9 +83,9 @@ spec:
# runAsUser: 1000 # runAsUser: 1000
# runAsGroup: 1000 # runAsGroup: 1000
volumes: volumes:
- name: photoprism-storage - name: photoprism-library-pvc
persistentVolumeClaim: persistentVolumeClaim:
claimName: photoprism-storage claimName: photoprism-library-pvc
# - name: photoprism-originals # - name: photoprism-originals
# persistentVolumeClaim: # persistentVolumeClaim:
# claimName: photoprism-originals # claimName: photoprism-originals

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: photos-nfs-pv
spec:
capacity:
storage: 200Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
server: 192.168.178.186
path: /volume1/Photos
mountOptions:
- hard
- nfsvers=4