From 7770e9859c71123a14ada1884a3b2c3d38a1df5b Mon Sep 17 00:00:00 2001 From: Adrien Date: Tue, 31 Mar 2026 15:30:40 +0000 Subject: [PATCH] initial git commit saving configs --- README.md | 124 +++ backup.md | 66 ++ bitwarden/Chart.lock | 6 + bitwarden/Chart.yaml | 11 + bitwarden/charts/postgresql-15.5.29.tgz | Bin 0 -> 75764 bytes bitwarden/notes.md | 30 + bitwarden/pv-bitwarden.yaml | 22 + bitwarden/pvc-bitwarden.yaml | 12 + bitwarden/templates/_helpers.tpl | 30 + bitwarden/templates/deployment.yaml | 53 ++ bitwarden/templates/ingress.yaml | 55 ++ bitwarden/templates/service.yaml | 12 + bitwarden/values.yaml | 81 ++ cluster/storage-class.yaml | 9 + gitea/NOTES.MD | 34 + gitea/pv-gitea.yaml | 22 + gitea/pvc-gitea.yaml | 12 + gitea/values.yaml | 92 ++ immich/immich-postgres/Chart.yaml | 6 + .../templates/postgres-cluster.yaml | 43 + .../templates/postgres-secret.yaml | 9 + immich/immich-postgres/values.yaml | 16 + immich/notes.md | 47 + immich/pv-master-node.yaml | 22 + immich/pv-postgres.yaml | 22 + immich/pvc-immich.yaml | 12 + immich/values-immich.yaml | 131 +++ letsencrypt/values.yaml | 15 + mumble/value.yaml | 18 + nextcloud/NOTES.md | 57 ++ nextcloud/notify-push-ingress.yaml | 24 + nextcloud/notify-push-svc.yaml | 12 + nextcloud/notify-push.yaml | 92 ++ nextcloud/pv-nextcloud-data.yaml | 22 + nextcloud/pv-nextcloud-postgres.yaml | 22 + nextcloud/pvc-nextcloud-data.yaml | 12 + nextcloud/pvc-nextcloud-postgres.yaml | 12 + nextcloud/values.yaml | 868 ++++++++++++++++++ observability/alloy/values.yaml | 124 +++ observability/grafana/pv-loki.yaml | 22 + observability/grafana/pvc-loki.yaml | 12 + observability/grafana/values.yaml | 38 + observability/loki/storage-loki.yaml | 22 + observability/loki/values.yaml | 59 ++ observability/notes.md | 26 + observability/prometheus/pv-prometheus.yaml | 22 + .../storageclass-prometheus-data.yaml | 7 + observability/prometheus/values.yaml | 27 + shared-db/postgres-nodeport.yaml | 15 + shared-db/postgres.yaml | 28 + shared-db/pv-shared-postgres.yaml | 22 + shared-db/pvc-shared-postgres.yaml | 12 + traefik/values.yaml | 14 + vaultwarden/Chart.lock | 6 + vaultwarden/Chart.yaml | 11 + vaultwarden/charts/postgresql-15.5.29.tgz | Bin 0 -> 75764 bytes vaultwarden/notes.md | 32 + vaultwarden/pv-vaultwarden.yaml | 22 + vaultwarden/pvc-vaultwarden.yaml | 12 + vaultwarden/templates/_helpers.tpl | 30 + vaultwarden/templates/deployment.yaml | 38 + vaultwarden/templates/ingress.yaml | 55 ++ vaultwarden/templates/service.yaml | 12 + vaultwarden/values.yaml | 65 ++ 64 files changed, 2866 insertions(+) create mode 100644 README.md create mode 100644 backup.md create mode 100644 bitwarden/Chart.lock create mode 100644 bitwarden/Chart.yaml create mode 100644 bitwarden/charts/postgresql-15.5.29.tgz create mode 100644 bitwarden/notes.md create mode 100644 bitwarden/pv-bitwarden.yaml create mode 100644 bitwarden/pvc-bitwarden.yaml create mode 100644 bitwarden/templates/_helpers.tpl create mode 100644 bitwarden/templates/deployment.yaml create mode 100644 bitwarden/templates/ingress.yaml create mode 100644 bitwarden/templates/service.yaml create mode 100644 bitwarden/values.yaml create mode 100644 cluster/storage-class.yaml create mode 100644 gitea/NOTES.MD create mode 100644 gitea/pv-gitea.yaml create mode 100644 gitea/pvc-gitea.yaml create mode 100644 gitea/values.yaml create mode 100644 immich/immich-postgres/Chart.yaml create mode 100644 immich/immich-postgres/templates/postgres-cluster.yaml create mode 100644 immich/immich-postgres/templates/postgres-secret.yaml create mode 100644 immich/immich-postgres/values.yaml create mode 100644 immich/notes.md create mode 100644 immich/pv-master-node.yaml create mode 100644 immich/pv-postgres.yaml create mode 100644 immich/pvc-immich.yaml create mode 100644 immich/values-immich.yaml create mode 100644 letsencrypt/values.yaml create mode 100644 mumble/value.yaml create mode 100644 nextcloud/NOTES.md create mode 100644 nextcloud/notify-push-ingress.yaml create mode 100644 nextcloud/notify-push-svc.yaml create mode 100644 nextcloud/notify-push.yaml create mode 100644 nextcloud/pv-nextcloud-data.yaml create mode 100644 nextcloud/pv-nextcloud-postgres.yaml create mode 100644 nextcloud/pvc-nextcloud-data.yaml create mode 100644 nextcloud/pvc-nextcloud-postgres.yaml create mode 100644 nextcloud/values.yaml create mode 100644 observability/alloy/values.yaml create mode 100644 observability/grafana/pv-loki.yaml create mode 100644 observability/grafana/pvc-loki.yaml create mode 100644 observability/grafana/values.yaml create mode 100644 observability/loki/storage-loki.yaml create mode 100644 observability/loki/values.yaml create mode 100644 observability/notes.md create mode 100644 observability/prometheus/pv-prometheus.yaml create mode 100644 observability/prometheus/storageclass-prometheus-data.yaml create mode 100644 observability/prometheus/values.yaml create mode 100644 shared-db/postgres-nodeport.yaml create mode 100644 shared-db/postgres.yaml create mode 100644 shared-db/pv-shared-postgres.yaml create mode 100644 shared-db/pvc-shared-postgres.yaml create mode 100644 traefik/values.yaml create mode 100644 vaultwarden/Chart.lock create mode 100644 vaultwarden/Chart.yaml create mode 100644 vaultwarden/charts/postgresql-15.5.29.tgz create mode 100644 vaultwarden/notes.md create mode 100644 vaultwarden/pv-vaultwarden.yaml create mode 100644 vaultwarden/pvc-vaultwarden.yaml create mode 100644 vaultwarden/templates/_helpers.tpl create mode 100644 vaultwarden/templates/deployment.yaml create mode 100644 vaultwarden/templates/ingress.yaml create mode 100644 vaultwarden/templates/service.yaml create mode 100644 vaultwarden/values.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..b9cf175 --- /dev/null +++ b/README.md @@ -0,0 +1,124 @@ +# Kubernetes Cluster Configuration + +A comprehensive Helm-based Kubernetes cluster setup with multiple applications and services organized by function. + +## 📁 Project Structure + +### Core Infrastructure + +#### **Cluster** +- Storage class configuration for persistent volumes + +#### **Traefik** (`traefik/`) +- Ingress controller and reverse proxy +- Routes external traffic to internal services +- Helm values configuration included + +#### **Shared Database** (`shared-db/`) +- Centralized PostgreSQL database instance +- Shared across multiple applications +- Persistent volume and claim configuration +- NodePort service for external access + +### Applications + +#### **Bitwarden** (`bitwarden/`) +- Password manager and secrets vault +- Full Helm chart with templates and customizable values +- Persistent storage configuration + +#### **Vaultwarden** (`vaultwarden/`) +- Open-source Bitwarden alternative +- Complete Helm chart with deployment templates +- Ingress, service, and persistence configuration + +#### **Gitea** (`gitea/`) +- Git hosting service +- Persistent volume and PostgreSQL backed +- Values configuration for customization + +#### **Nextcloud** (`nextcloud/`) +- File sync, sharing, and collaboration platform +- Separate persistent volumes for data and PostgreSQL +- Notification push service included +- Custom ingress configuration + +#### **Immich** (`immich/`) +- Photo and video backup service +- Sub-chart for PostgreSQL database management +- Master node persistent volume +- PostgreSQL and application storage + +#### **Linkwarden Stack** (`linkwarden-stack/`) +- Link management and bookmarking service +- Complete Helm chart with ConfigMap, deployment, and ingress +- Persistent storage configuration + +#### **Mumble** (`mumble/`) +- Voice communication and VoIP service +- Helm values for configuration + +#### **Letsencrypt** (`letsencrypt/`) +- Automated SSL certificate provisioning +- Integrations with ingress controllers + +### Observability & Monitoring + +#### **Observability Stack** (`observability/`) + +##### **Prometheus** (`observability/prometheus/`) +- Metrics collection and time-series database +- Custom storage class for performance +- Persistent volume configuration + +##### **Loki** (`observability/loki/`) +- Log aggregation system +- Companion to Prometheus +- Dedicated storage configuration + +##### **Grafana** (`observability/grafana/`) +- Metrics and logs visualization +- Loki backend for log exploration +- Dashboard and alerting capabilities + +##### **Alloy** (`observability/alloy/`) +- Telemetry collection agent +- Data collection for Prometheus and Loki + +## 🚀 Deployment + +Each service is configured as a Helm chart with: +- `values.yaml` - Configuration and customization +- `Chart.yaml` - Chart metadata (where applicable) +- `templates/` - Kubernetes resource templates +- Persistent volume (PV) and persistent volume claim (PVC) for stateful services + +### Quick Start + +```bash +# Add Helm repositories as needed +helm repo add +helm repo update + +# Deploy a service +helm install -f /values.yaml -n +``` + +## 📝 Storage Configuration + +All persistent services include: +- **pv-\*.yaml** - PersistentVolume definitions +- **pvc-\*.yaml** - PersistentVolumeClaim definitions +- Reference storage class configurations + +## 🔗 Ingress Routes + +Traefik handles ingress routing with: +- `ingress.yaml` templates in major services +- SSL termination via Letsencrypt +- Pretty hostname routing (e.g., `bitwarden.example.com`) + +## 📚 Additional Resources + +- [backup.md](backup.md) - Backup and recovery procedures +- Individual service notes in each subdirectory (notes.md, NOTES.md) diff --git a/backup.md b/backup.md new file mode 100644 index 0000000..9428d6e --- /dev/null +++ b/backup.md @@ -0,0 +1,66 @@ + +## 3️⃣ Create the backup script on the master node + +Create /usr/local/bin/backup-storage.sh: + +sudo nano /usr/local/bin/backup-storage.sh + +``` +#!/bin/bash +set -e + +SRC="/storage/" +DEST="debian@192.168.1.30:/backup/master-storage/" +SSH_KEY="/home/adrien/.ssh/id_backup" +LOG="/var/log/storage-backup.log" + +echo "=== Backup started at $(date) ===" >> $LOG + +rsync -aHAX --numeric-ids --delete \ + --link-dest=/backup/master-storage/latest \ + -e "ssh -i $SSH_KEY" \ + "$SRC" "$DEST/$(date +%F)/" >> $LOG 2>&1 + +ssh -i $SSH_KEY debian@192.168.1.30 \ + "ln -sfn /backup/master-storage/$(date +%F) /backup/master-storage/latest" + +echo "=== Backup finished at $(date) ===" >> $LOG +``` + +### What this gives you + +Daily folders (2025-01-14/) + +A latest symlink + +Efficient incremental backups + +Clean deletions mirrored (--delete) + +``` +sudo crontab -e + +0 2 * * * /usr/local/bin/backup-storage.sh + +``` + + +### 5️⃣ Verify backups on vm-nfs +ls -lah /backup/master-storage + +You should see: + +2025-01-14/ +latest -> 2025-01-14 + + +## 6️⃣ Restore (very important) + +To restore everything: + +rsync -aHAX /backup/master-storage/latest/ /storage/ + + +To restore a single folder: + +rsync -aHAX /backup/master-storage/2025-01-10/prometheus/ /storage/prometheus/ \ No newline at end of file diff --git a/bitwarden/Chart.lock b/bitwarden/Chart.lock new file mode 100644 index 0000000..6d708fe --- /dev/null +++ b/bitwarden/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 15.5.29 +digest: sha256:e02780f5fb6cf25d49477b43986ea907d96df3167f5a398a34eedad988c841e7 +generated: "2025-12-21T17:14:41.412181861Z" diff --git a/bitwarden/Chart.yaml b/bitwarden/Chart.yaml new file mode 100644 index 0000000..46b60a1 --- /dev/null +++ b/bitwarden/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: bitwarden-lite +description: Bitwarden Lite with Bitnami PostgreSQL subchart +type: application +version: 0.1.0 +appVersion: "1.32.0" + +dependencies: + - name: postgresql + version: 15.5.29 + repository: https://charts.bitnami.com/bitnami diff --git a/bitwarden/charts/postgresql-15.5.29.tgz b/bitwarden/charts/postgresql-15.5.29.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ef2dac4c2d25190bd5563d97d09c8625ff65477d GIT binary patch literal 75764 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

N5O}<4Lx~c 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%0AxRW7k(iPn*IS(o5e!lm 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 JTKfQ|2mqLcd_VvI literal 0 HcmV?d00001 diff --git a/bitwarden/notes.md b/bitwarden/notes.md new file mode 100644 index 0000000..3ce1119 --- /dev/null +++ b/bitwarden/notes.md @@ -0,0 +1,30 @@ +# Bitwarden lite + +https://bitwarden.com/help/install-and-deploy-lite + + +``` +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update +helm dependency build +helm upgrade --install bitwarden . -f values.yaml -n bitwarden + +helm delete bitwarden -n bitwarden +kubectl -n bitwarden rollout restart deploy/bitwarden-lite + +kubectl -n bitwarden create secret generic bitwarden-postgresql-auth \ + --from-literal=postgres-password='pwdBitwardenSqlStorage' \ + --from-literal=password='pwdBitwardenStorage' + + + +kubectl -n bitwarden create secret generic bitwarden-smtp \ + --from-literal=globalSettings__mail__smtp__host='smtp.gmail.com' \ + --from-literal=globalSettings__mail__smtp__ssl='starttls' \ + --from-literal=globalSettings__mail__smtp__username='adrcpp@gmail.com' \ + --from-literal=globalSettings__mail__smtp__password='agkp arhk yapp rafi' \ + --from-literal=globalSettings__mail__replyToEmail='adrcpp@gmail.com' + + +kubectl -n bitwarden get pods +``` \ No newline at end of file diff --git a/bitwarden/pv-bitwarden.yaml b/bitwarden/pv-bitwarden.yaml new file mode 100644 index 0000000..46cfb07 --- /dev/null +++ b/bitwarden/pv-bitwarden.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-bitwarden-data +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: bitwarden-data + local: + path: /storage/bitwarden + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/bitwarden/pvc-bitwarden.yaml b/bitwarden/pvc-bitwarden.yaml new file mode 100644 index 0000000..80dbc2d --- /dev/null +++ b/bitwarden/pvc-bitwarden.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-bitwarden-data + namespace: bitwarden +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: bitwarden-data \ No newline at end of file diff --git a/bitwarden/templates/_helpers.tpl b/bitwarden/templates/_helpers.tpl new file mode 100644 index 0000000..9fd4426 --- /dev/null +++ b/bitwarden/templates/_helpers.tpl @@ -0,0 +1,30 @@ +{{- define "bitwarden-lite.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "bitwarden-lite.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" (include "bitwarden-lite.name" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "bitwarden-lite.labels" -}} +app.kubernetes.io/name: {{ include "bitwarden-lite.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | quote }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "bitwarden-lite.selectorLabels" -}} +app.kubernetes.io/name: {{ include "bitwarden-lite.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} \ No newline at end of file diff --git a/bitwarden/templates/deployment.yaml b/bitwarden/templates/deployment.yaml new file mode 100644 index 0000000..6a9cc36 --- /dev/null +++ b/bitwarden/templates/deployment.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "bitwarden-lite.fullname" . }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ include "bitwarden-lite.fullname" . }} + template: + metadata: + labels: + app: {{ include "bitwarden-lite.fullname" . }} + spec: + containers: + - name: bitwarden + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + env: + - name: BW_DB_SERVER + value: {{ .Values.database.host | quote }} + - name: BW_DB_USERNAME + value: {{ .Values.database.user | quote }} + - name: BW_DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.postgresql.auth.existingSecret }} + key: {{ .Values.postgresql.auth.secretKeys.userPasswordKey | quote }} + - name: BW_DB_DATABASE + value: {{ .Values.database.name | quote }} + - name: BW_DB_PROVIDER + value: "postgresql" + - name: BW_DOMAIN + value: {{ .Values.bitwarden.domain | quote }} + - name: globalSettings__hibpApiKey + value: {{ .Values.hibp.apiKey | quote }} + - name: BW_INSTALLATION_ID + value: {{ .Values.bitwarden.installation.id | quote }} + - name: BW_INSTALLATION_KEY + value: {{ .Values.bitwarden.installation.key | quote }} + envFrom: + - secretRef: + name: bitwarden-smtp + volumeMounts: + - name: data + mountPath: /data + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ default (printf "%s-data" (include "bitwarden-lite.fullname" .)) .Values.persistence.existingClaim }} diff --git a/bitwarden/templates/ingress.yaml b/bitwarden/templates/ingress.yaml new file mode 100644 index 0000000..4a6c935 --- /dev/null +++ b/bitwarden/templates/ingress.yaml @@ -0,0 +1,55 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "bitwarden-lite.fullname" . }} + labels: + {{- include "bitwarden-lite.labels" . | nindent 4 }} + {{- if .Values.ingress.annotations }} + annotations: + {{- toYaml .Values.ingress.annotations | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + - host: {{ .Values.bitwarden.domain | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + service: + name: {{ include "bitwarden-lite.fullname" . }} + port: + number: {{ .Values.service.port }} + {{- range .Values.ingress.extraHosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ include "bitwarden-lite.fullname" . }} + port: + number: {{ .Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/bitwarden/templates/service.yaml b/bitwarden/templates/service.yaml new file mode 100644 index 0000000..2bbbbb3 --- /dev/null +++ b/bitwarden/templates/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "bitwarden-lite.fullname" . }} +spec: + type: {{ .Values.service.type }} + selector: + app: {{ include "bitwarden-lite.fullname" . }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: 8080 \ No newline at end of file diff --git a/bitwarden/values.yaml b/bitwarden/values.yaml new file mode 100644 index 0000000..a8b1572 --- /dev/null +++ b/bitwarden/values.yaml @@ -0,0 +1,81 @@ +image: + repository: ghcr.io/bitwarden/lite + tag: "2025.12.0" + pullPolicy: IfNotPresent + +replicaCount: 1 + +service: + type: ClusterIP + port: 8080 + +ingress: + enabled: true + ingressClassName: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + hosts: + - host: bitwarden.immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - secretName: bitwarden-tls + hosts: + - bitwarden.immich-ad.ovh + +# Persist bitwarden data (attachments, icon cache, etc.) +persistence: + enabled: true + existingClaim: pvc-bitwarden-data + +bitwarden: + # REQUIRED for secure cookies, web vault, etc. + domain: "bitwarden.immich-ad.ovh" + disableUserRegistration: false + + installation: + id: "bca307eb-c177-4eb7-b6a6-b3ba0129ff3d" + key: "x4FBfkK4f1wDCuXWQdX9" + + # SMTP optional + smtp: + enabled: false + host: "" + port: 587 + username: "" + password: + existingSecret: "" + key: "SMTP_PASSWORD" + from: "" +hibp: + apiKey: "" + +# Database config +database: + name: bitwarden + user: bitwarden + +# Bitnami PostgreSQL subchart values +postgresql: + enabled: true + image: + registry: docker.io + repository: bitnami/postgresql + tag: latest + + auth: + username: bitwarden + database: bitwarden + + # Upgrade-safe: point to an existing secret you create once + existingSecret: bitwarden-postgresql-auth + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + + primary: + persistence: + enabled: true + existingClaim: pvc-bitwarden-data # bind to precreated PVC if you want \ No newline at end of file diff --git a/cluster/storage-class.yaml b/cluster/storage-class.yaml new file mode 100644 index 0000000..e2c1044 --- /dev/null +++ b/cluster/storage-class.yaml @@ -0,0 +1,9 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: local-storage + # Optional: make it the default StorageClass for the cluster + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer \ No newline at end of file diff --git a/gitea/NOTES.MD b/gitea/NOTES.MD new file mode 100644 index 0000000..7c8ccec --- /dev/null +++ b/gitea/NOTES.MD @@ -0,0 +1,34 @@ +``` + +kubectl create namespace gitea + +helm repo add gitea-charts https://dl.gitea.com/charts/ +helm repo update + +helm upgrade --install gitea gitea-charts/gitea \ + --namespace gitea \ + -f values.yaml + +``` + +## PV / PVC + +``` +kubectl create -f ./pv-gitea.yaml +kubectl create -f ./pvc-gitea.yaml +``` + +## Check + +``` +kubectl -n gitea get pods,pvc,ingress +kubectl -n gitea rollout status deploy/gitea +kubectl -n gitea get secret +``` + +## Show chart values - usefuel for override in value.yaml +``` +helm show values gitea-charts/gitea | grep -A20 -B5 -i claim +helm show values gitea-charts/gitea | grep -A20 -B5 -i persistence +helm show values gitea-charts/gitea | grep -A20 -B5 -i storage +``` \ No newline at end of file diff --git a/gitea/pv-gitea.yaml b/gitea/pv-gitea.yaml new file mode 100644 index 0000000..639b9d5 --- /dev/null +++ b/gitea/pv-gitea.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-gitea-data +spec: + capacity: + storage: 20Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: gitea-data + local: + path: /storage/gitea + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/gitea/pvc-gitea.yaml b/gitea/pvc-gitea.yaml new file mode 100644 index 0000000..9bf6f76 --- /dev/null +++ b/gitea/pvc-gitea.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-gitea-data + namespace: gitea +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi + storageClassName: gitea-data \ No newline at end of file diff --git a/gitea/values.yaml b/gitea/values.yaml new file mode 100644 index 0000000..e286236 --- /dev/null +++ b/gitea/values.yaml @@ -0,0 +1,92 @@ +# gitea-values.yaml +image: + rootless: true + +strategy: + type: Recreate + +postgresql: + enabled: false + +postgresql-ha: + enabled: false + +valkey-cluster: + enabled: false + +redis-cluster: + enabled: false + +persistence: + enabled: true + create: false + claimName: pvc-gitea-data + size: 20Gi + accessModes: + - ReadWriteOnce + +gitea: + admin: + username: giteaadmin + password: "51aad51@#zé" + email: "admin@immich-ad.ovh" + + config: + server: + DOMAIN: git.immich-ad.ovh + ROOT_URL: https://git.immich-ad.ovh/ + SSH_DOMAIN: git.immich-ad.ovh + PROTOCOL: http + START_SSH_SERVER: false + + database: + DB_TYPE: sqlite3 + + service: + DISABLE_REGISTRATION: true + REQUIRE_SIGNIN_VIEW: false + REGISTER_MANUAL_CONFIRM: false + + session: + PROVIDER: memory + + cache: + ADAPTER: memory + + queue: + TYPE: level + +service: + http: + type: ClusterIP + port: 3000 + + ssh: + enabled: false + +ingress: + enabled: true + className: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + hosts: + - host: git.immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - secretName: gitea-tls + hosts: + - git.immich-ad.ovh + +resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1000m + memory: 1Gi + +test: + enabled: false \ No newline at end of file diff --git a/immich/immich-postgres/Chart.yaml b/immich/immich-postgres/Chart.yaml new file mode 100644 index 0000000..ab37014 --- /dev/null +++ b/immich/immich-postgres/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: immich-postgres +description: CloudNativePG Cluster for Immich with VectorChord +type: application +version: 0.1.0 +appVersion: "16" \ No newline at end of file diff --git a/immich/immich-postgres/templates/postgres-cluster.yaml b/immich/immich-postgres/templates/postgres-cluster.yaml new file mode 100644 index 0000000..b19e06f --- /dev/null +++ b/immich/immich-postgres/templates/postgres-cluster.yaml @@ -0,0 +1,43 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ .Values.cluster.name }} +spec: + instances: {{ .Values.cluster.instances }} + + storage: + pvcTemplate: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: postgres-storage + volumeMode: Filesystem + imageName: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + + postgresql: + shared_preload_libraries: + - "vchord.so" + + # Optional: you can tweak resources, monitoring, etc. here. + # resources: + # requests: + # cpu: 100m + # memory: 512Mi + # limits: + # cpu: 2 + # memory: 2Gi + + + bootstrap: + initdb: + database: {{ .Values.database.name }} + owner: {{ .Values.database.user }} + dataChecksums: true + secret: + name: {{ ternary .Values.database.existingSecret (printf "%s-app" .Values.cluster.name) (ne .Values.database.existingSecret "") }} + postInitApplicationSQL: + - ALTER USER {{ .Values.database.user }} WITH SUPERUSER; + - CREATE EXTENSION vchord CASCADE; + - CREATE EXTENSION earthdistance CASCADE; \ No newline at end of file diff --git a/immich/immich-postgres/templates/postgres-secret.yaml b/immich/immich-postgres/templates/postgres-secret.yaml new file mode 100644 index 0000000..9f36ab5 --- /dev/null +++ b/immich/immich-postgres/templates/postgres-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.cluster.name }}-app +type: kubernetes.io/basic-auth +stringData: + username: {{ .Values.database.user | quote }} + password: {{ .Values.database.password | quote }} + dbname: {{ .Values.database.name | quote }} # handy for Immich env, CNPG ignores this \ No newline at end of file diff --git a/immich/immich-postgres/values.yaml b/immich/immich-postgres/values.yaml new file mode 100644 index 0000000..53075e5 --- /dev/null +++ b/immich/immich-postgres/values.yaml @@ -0,0 +1,16 @@ +cluster: + name: immich-postgres # will also be used for services: immich-postgresql-rw, -ro, ... + instances: 1 + + storage: + size: 10Gi + +image: + repository: ghcr.io/tensorchord/cloudnative-vectorchord + tag: "16.9-0.4.3" + + +database: + name: immich + user: immich + password: "change-me-immich" # for dev; in prod override via --set or external secret \ No newline at end of file diff --git a/immich/notes.md b/immich/notes.md new file mode 100644 index 0000000..9d8a983 --- /dev/null +++ b/immich/notes.md @@ -0,0 +1,47 @@ +##immich-postgres: + +A chart to deploy a cloudnative-pg specificly to be used by immich +Namespace: immich + +### Helm + +``` +helm install immich-postgres ./immich-postgres -n immich +helm delete immich-postgres -n immich + +helm upgrade --install immich immich/immich -n immich -f values-immich.yaml +``` + +## PV: + +``` +kubectl get pvc -n immich +kubectl get pv + +``` + +## Logs: +``` +kubectl -n immich logs --prefix +``` +## Monitoring: +``` +kubectl -n immich get svc +kubectl -n immich get pods +kubectl -n immich describe + +``` + +## Traefik ingress +https://doc.traefik.io/traefik/getting-started/kubernetes/ + +## cert manager in the cluster +https://www.slingacademy.com/article/how-to-set-up-ssl-with-lets-encrypt-in-kubernetes/ + +## Certificate: +``` +kubectl -n immich get certificate +kubectl -n immich describe certificate immich-tls +kubectl -n immich get challenges + +``` \ No newline at end of file diff --git a/immich/pv-master-node.yaml b/immich/pv-master-node.yaml new file mode 100644 index 0000000..0c60d9e --- /dev/null +++ b/immich/pv-master-node.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-master-node +spec: + capacity: + storage: 500Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /storage/immich-data + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/immich/pv-postgres.yaml b/immich/pv-postgres.yaml new file mode 100644 index 0000000..e72647f --- /dev/null +++ b/immich/pv-postgres.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-postgres +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: postgres-storage + local: + path: /storage/immich-data + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/immich/pvc-immich.yaml b/immich/pvc-immich.yaml new file mode 100644 index 0000000..9b322a4 --- /dev/null +++ b/immich/pvc-immich.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-immich + namespace: immich +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 500Gi + storageClassName: local-storage \ No newline at end of file diff --git a/immich/values-immich.yaml b/immich/values-immich.yaml new file mode 100644 index 0000000..4259aad --- /dev/null +++ b/immich/values-immich.yaml @@ -0,0 +1,131 @@ +## This chart relies on the common library chart from bjw-s +## You can find it at https://github.com/bjw-s-labs/helm-charts/tree/common-4.3.0/charts/library/common +## Refer there for more detail about the supported values + +controllers: + main: + containers: + main: + image: + tag: v2.6.3 + env: + REDIS_HOSTNAME: '{{ printf "%s-valkey" .Release.Name }}' + IMMICH_MACHINE_LEARNING_URL: '{{ printf "http://%s-machine-learning:3003" .Release.Name }}' + + DB_HOSTNAME: "immich-postgres-rw" + DB_PORT: "5432" + + # Database name matches what we set in the CNPG cluster + DB_DATABASE_NAME: "immich" + + # Credentials: reuse the CNPG bootstrap secret + DB_USERNAME: + valueFrom: + secretKeyRef: + name: immich-postgres-app + key: username + DB_PASSWORD: + valueFrom: + secretKeyRef: + name: immich-postgres-app + key: password + +immich: + metrics: + # Enabling this will create the service monitors needed to monitor immich with the prometheus operator + enabled: false + persistence: + # Main data store for all photos shared between different components. + library: + # Automatically creating the library volume is not supported by this chart + # You have to specify an existing PVC to use + existingClaim: pvc-immich + # configuration is immich-config.json converted to yaml + # ref: https://immich.app/docs/install/config-file/ + # + configuration: + # trash: + # enabled: false + # days: 30 + storageTemplate: + enabled: true + template: "{{y}}/{{y}}-{{MM}}/{{filename}}" + +# Dependencies +valkey: + enabled: true + controllers: + main: + containers: + main: + image: + repository: docker.io/valkey/valkey + tag: 9.0-alpine@sha256:b4ee67d73e00393e712accc72cfd7003b87d0fcd63f0eba798b23251bfc9c394 + pullPolicy: IfNotPresent + persistence: + data: + enabled: true + size: 1Gi + # Optional: Set this to persistentVolumeClaim to keep job queues persistent + type: emptyDir + accessMode: ReadWriteOnce + storageClass: local-storage + +# Immich components +server: + enabled: true + controllers: + main: + containers: + main: + image: + repository: ghcr.io/immich-app/immich-server + pullPolicy: IfNotPresent + ingress: + main: + enabled: true + ingressClassName: traefik + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/proxy-body-size: "0" + hosts: + - host: immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - immich-ad.ovh + secretName: immich-tls + + service: + main: + type: ClusterIP + ports: + http: + port: 2283 + targetPort: 2283 + + +machine-learning: + enabled: true + controllers: + main: + containers: + main: + image: + repository: ghcr.io/immich-app/immich-machine-learning + pullPolicy: IfNotPresent + env: + TRANSFORMERS_CACHE: /cache + HF_XET_CACHE: /cache/huggingface-xet + MPLCONFIGDIR: /cache/matplotlib-config + persistence: + cache: + enabled: true + size: 10Gi + # Optional: Set this to persistentVolumeClaim to avoid downloading the ML models every start. + type: emptyDir + accessMode: ReadWriteMany + # storageClass: your-class \ No newline at end of file diff --git a/letsencrypt/values.yaml b/letsencrypt/values.yaml new file mode 100644 index 0000000..d0606af --- /dev/null +++ b/letsencrypt/values.yaml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + email: adrcpp@gmail.com + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-prod-key + solvers: + - http01: + ingress: + class: traefik + \ No newline at end of file diff --git a/mumble/value.yaml b/mumble/value.yaml new file mode 100644 index 0000000..f7b43e3 --- /dev/null +++ b/mumble/value.yaml @@ -0,0 +1,18 @@ +# https://artifacthub.io/packages/helm/syntaxerror404/mumble +persistence: + enabled: false + +config: + welcometext: "Welcome to our Mumble server!" + registerName: "Apex Legend forever bronze" + users: "10" + +resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 128Mi + +service: + type: NodePort \ No newline at end of file diff --git a/nextcloud/NOTES.md b/nextcloud/NOTES.md new file mode 100644 index 0000000..9c442b3 --- /dev/null +++ b/nextcloud/NOTES.md @@ -0,0 +1,57 @@ + +## Config +https://github.com/nextcloud/helm/blob/main/charts/nextcloud/README.md + +``` +kubectl top pods --all-namespaces + +helm repo add nextcloud https://nextcloud.github.io/helm/ +helm install nextcloud nextcloud/nextcloud -f values.yaml -n nextcloud +helm upgrade --install nextcloud nextcloud/nextcloud -f values.yaml -n nextcloud + +helm delete nextcloud -n nextcloud + +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- \ + php occ maintenance:mode --on + +kubectl exec -it -n nextcloud deploy/nextcloud -c nextcloud -- bash +``` +nextcloud.immich-ad.ovh/ + + +## PV / PVC + +``` +kubectl create -f ./pv-postgres.yaml +kubectl create -f ./pvc-nextcloud.yaml +``` + +## Service +``` +kubectl -n nextcloud get svc +kubectl -n nextcloud get pods +``` + +## Certificates + +``` +kubectl -n nextcloud get certificate +kubectl -n nextcloud describe certificate nextcloud-tls +kubectl -n nextcloud get challenges +``` + + +## Updates: + +``` +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ status +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ maintenance:mode +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ upgrade + +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ maintenance:repair + +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ db:add-missing-indices +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ db:add-missing-columns +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ db:add-missing-primary-keys +kubectl exec -n nextcloud deploy/nextcloud -c nextcloud -- php occ maintenance:mode --off +``` diff --git a/nextcloud/notify-push-ingress.yaml b/nextcloud/notify-push-ingress.yaml new file mode 100644 index 0000000..d752571 --- /dev/null +++ b/nextcloud/notify-push-ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: notify-push + namespace: nextcloud + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure +spec: + ingressClassName: traefik + tls: + - hosts: + - nextcloud.immich-ad.ovh + secretName: nextcloud-tls + rules: + - host: nextcloud.immich-ad.ovh + http: + paths: + - path: /push + pathType: Prefix + backend: + service: + name: notify-push + port: + number: 7867 \ No newline at end of file diff --git a/nextcloud/notify-push-svc.yaml b/nextcloud/notify-push-svc.yaml new file mode 100644 index 0000000..b66a707 --- /dev/null +++ b/nextcloud/notify-push-svc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: notify-push + namespace: nextcloud +spec: + selector: + app: notify-push + ports: + - name: http + port: 7867 + targetPort: 7867 \ No newline at end of file diff --git a/nextcloud/notify-push.yaml b/nextcloud/notify-push.yaml new file mode 100644 index 0000000..677d446 --- /dev/null +++ b/nextcloud/notify-push.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: notify-push + namespace: nextcloud +spec: + replicas: 1 + selector: + matchLabels: + app: notify-push + template: + metadata: + labels: + app: notify-push + spec: + initContainers: + - name: fetch-notify-push + image: alpine:3.21 + command: ["sh","-lc"] + args: + - | + set -eu + apk add --no-cache curl + VER="1.3.0" + URL="https://github.com/nextcloud/notify_push/releases/download/v${VER}/notify_push-aarch64-unknown-linux-musl" + echo "Downloading $URL" + curl -fsSL "$URL" -o /shared/notify_push + chmod +x /shared/notify_push + /shared/notify_push --help | head -n 5 + volumeMounts: + - name: shared + mountPath: /shared + + containers: + - name: notify-push + image: alpine:3.21 + command: ["/shared/notify_push"] + args: + - "--port" + - "7867" + ports: + - name: http + containerPort: 7867 + env: + # Nextcloud + - name: NEXTCLOUD_URL + value: "https://nextcloud.immich-ad.ovh" + envFrom: + - secretRef: + name: notify-push-db + - secretRef: + name: notify-push-redis + # # Redis + # - name: REDIS_HOST + # value: "nextcloud-redis-master" + # - name: REDIS_PASSWORD + # valueFrom: + # secretKeyRef: + # name: nextcloud-redis + # key: redis-password + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 256Mi + # readinessProbe: + # httpGet: + # path: / + # port: 7867 + # initialDelaySeconds: 10 + # periodSeconds: 10 + # livenessProbe: + # httpGet: + # path: / + # port: 7867 + # initialDelaySeconds: 30 + # periodSeconds: 20 + volumeMounts: + - name: shared + mountPath: /shared + - name: nextcloud-data + mountPath: /nextcloud + readOnly: true + + volumes: + - name: shared + emptyDir: {} + - name: nextcloud-data + persistentVolumeClaim: + claimName: pvc-nextcloud-data \ No newline at end of file diff --git a/nextcloud/pv-nextcloud-data.yaml b/nextcloud/pv-nextcloud-data.yaml new file mode 100644 index 0000000..535e7fe --- /dev/null +++ b/nextcloud/pv-nextcloud-data.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-nextcloud-data +spec: + capacity: + storage: 50Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: nextcloud-data + local: + path: /storage/nextcloud + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/nextcloud/pv-nextcloud-postgres.yaml b/nextcloud/pv-nextcloud-postgres.yaml new file mode 100644 index 0000000..111f29b --- /dev/null +++ b/nextcloud/pv-nextcloud-postgres.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-nextcloud-postgres +spec: + capacity: + storage: 20Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: nextcloud-postgres-storage + local: + path: /storage/nextcloud-postgres + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/nextcloud/pvc-nextcloud-data.yaml b/nextcloud/pvc-nextcloud-data.yaml new file mode 100644 index 0000000..c9beb43 --- /dev/null +++ b/nextcloud/pvc-nextcloud-data.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-nextcloud-data + namespace: nextcloud +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi + storageClassName: nextcloud-data \ No newline at end of file diff --git a/nextcloud/pvc-nextcloud-postgres.yaml b/nextcloud/pvc-nextcloud-postgres.yaml new file mode 100644 index 0000000..9b90f67 --- /dev/null +++ b/nextcloud/pvc-nextcloud-postgres.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-nextcloud-postgres + namespace: nextcloud +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi + storageClassName: nextcloud-postgres-storage \ No newline at end of file diff --git a/nextcloud/values.yaml b/nextcloud/values.yaml new file mode 100644 index 0000000..0eb16d0 --- /dev/null +++ b/nextcloud/values.yaml @@ -0,0 +1,868 @@ +global: + image: + # -- if set it will overwrite all registry entries + registry: + + security: + # required for bitnamilegacy repos + allowInsecureImages: true + +## ref: https://hub.docker.com/r/library/nextcloud/tags/ +## +image: + registry: docker.io + repository: library/nextcloud + flavor: apache + # default is generated by flavor and appVersion + tag: 33.0.1-apache + pullPolicy: IfNotPresent + # pullSecrets: + # - myRegistrKeySecretName + +nameOverride: "" +fullnameOverride: "" +podAnnotations: {} +podLabels: {} +deploymentAnnotations: {} +deploymentLabels: {} + +# Number of replicas to be deployed +replicaCount: 1 + +## Allowing use of ingress controllers +## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ +## +ingress: + enabled: true + className: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/proxy-body-size: "0" + # HSTS + traefik.ingress.kubernetes.io/headers.customResponseHeaders.Strict-Transport-Security: "max-age=15552000; includeSubDomains; preload" + + hosts: + - host: nextcloud.immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - nextcloud.immich-ad.ovh + secretName: nextcloud-tls + labels: {} + path: / + pathType: Prefix + +# Allow configuration of lifecycle hooks +# ref: https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/ +lifecycle: {} +# lifecycle: +# postStartCommand: [] +# preStopCommand: [] + +phpClientHttpsFix: + enabled: false + protocol: https + +nextcloud: + host: nextcloud.immich-ad.ovh + username: admin + password: changeme + ## Use an existing secret + existingSecret: + enabled: false + # secretName: nameofsecret + usernameKey: nextcloud-username + passwordKey: nextcloud-password + tokenKey: "" + smtpUsernameKey: smtp-username + smtpPasswordKey: smtp-password + smtpHostKey: smtp-host + update: 0 + # If web server is not binding default port, you can define it + containerPort: 80 + datadir: /var/www/html/data + persistence: + subPath: + # if set, we'll template this list to the NEXTCLOUD_TRUSTED_DOMAINS env var + trustedDomains: ["nextcloud.nextcloud.svc.cluster.local","nextcloud.immich-ad.ovh", "nextcloud", "localhost"] + ## SMTP configuration + mail: + enabled: true + # the user we send email as + fromAddress: admin + # the domain we send email from + domain: immich-ad.ovh + smtp: + host: ssl0.ovh.net + secure: starttls + port: 587 + authtype: LOGIN + name: 'admin@immich-ad.ovh' + password: ',3FV\]Knv_AqC' + ## PHP Configuration files + # Will be injected in /usr/local/etc/php/conf.d for apache image and in /usr/local/etc/php-fpm.d when nginx.enabled: true + phpConfigs: + zzz-memory.ini: | + memory_limit = 1024M + max_execution_time = 360 + upload_max_filesize = 2G + post_max_size = 2G + opcache.ini: | + opcache.enable=1 + opcache.memory_consumption=256 + opcache.interned_strings_buffer=32 + opcache.max_accelerated_files=20000 + opcache.revalidate_freq=60 + opcache.save_comments=1 + opcache.fast_shutdown=1 + ## Default config files that utilize environment variables: + # see: https://github.com/nextcloud/docker/tree/master#auto-configuration-via-environment-variables + # IMPORTANT: Will be used only if you put extra configs, otherwise default will come from nextcloud itself + # Default confgurations can be found here: https://github.com/nextcloud/docker/tree/master/.config + defaultConfigs: + # To protect /var/www/html/config + .htaccess: true + # Apache configuration for rewrite urls + apache-pretty-urls.config.php: true + # Define APCu as local cache + apcu.config.php: true + # Apps directory configs + apps.config.php: true + # Used for auto configure database + autoconfig.php: true + # Redis default configuration + redis.config.php: |- + '\OC\Memcache\Redis', + 'memcache.local' => '\OC\Memcache\APCu', + 'redis' => [ + 'host' => 'nextcloud-redis-master', + 'port' => 6379, + 'password' => 'StrongRedisPass', + 'timeout' => 1.5, + ], + ]; + # Reverse proxy default configuration + reverse-proxy.config.php: true + # S3 Object Storage as primary storage + s3.config.php: true + # SMTP default configuration via environment variables + smtp.config.php: true + # Swift Object Storage as primary storage + swift.config.php: true + # disables the web based updater as the default nextcloud docker image does not support it + upgrade-disable-web.config.php: true + # -- imaginary support config + imaginary.config.php: false + + # Extra config files created in /var/www/html/config/ + # ref: https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#multiple-config-php-file + configs: + audit.config.php: |- + 'syslog', + 'syslog_tag_audit' => 'Nextcloud', + 'logfile_audit' => '', + ); + # For example, to enable image and text file previews: + # previews.config.php: |- + # true, + # 'enabledPreviewProviders' => array ( + # 'OC\Preview\Movie', + # 'OC\Preview\PNG', + # 'OC\Preview\JPEG', + # 'OC\Preview\GIF', + # 'OC\Preview\BMP', + # 'OC\Preview\XBitmap', + # 'OC\Preview\MP3', + # 'OC\Preview\MP4', + # 'OC\Preview\TXT', + # 'OC\Preview\MarkDown', + # 'OC\Preview\PDF' + # ), + # ); + + # Hooks for auto configuration + # Here you could write small scripts which are placed in `/docker-entrypoint-hooks.d//helm.sh` + # ref: https://github.com/nextcloud/docker?tab=readme-ov-file#auto-configuration-via-hook-folders + hooks: + pre-installation: + post-installation: + pre-upgrade: + post-upgrade: + before-starting: + + ## Strategy used to replace old pods + ## IMPORTANT: use with care, it is suggested to leave as that for upgrade purposes + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + strategy: + type: Recreate + # type: RollingUpdate + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 0 + + ## + ## Extra environment variables + extraEnv: + - name: OVERWRITEPROTOCOL + value: https + - name: OVERWRITECLIURL + value: https://nextcloud.immich-ad.ovh + - name: TRUSTED_PROXIES + value: "10.244.0.0/16" + + # Extra init containers that runs before pods start. + extraInitContainers: [] + # - name: do-something + # image: busybox + # command: ['do', 'something'] + + # Extra sidecar containers. + extraSidecarContainers: [] + # - name: nextcloud-logger + # image: busybox + # command: [/bin/sh, -c, 'while ! test -f "/run/nextcloud/data/nextcloud.log"; do sleep 1; done; tail -n+1 -f /run/nextcloud/data/nextcloud.log'] + # volumeMounts: + # - name: nextcloud-data + # mountPath: /run/nextcloud/data + + # Extra mounts for the pods. Example shown is for connecting a legacy NFS volume + # to NextCloud pods in Kubernetes. This can then be configured in External Storage + extraVolumes: + # - name: nfs + # nfs: + # server: "10.0.0.1" + # path: "/nextcloud_data" + # readOnly: false + extraVolumeMounts: + # - name: nfs + # mountPath: "/legacy_data" + + # Set securityContext parameters for the nextcloud CONTAINER only (will not affect nginx container). + # For example, you may need to define runAsNonRoot directive + securityContext: {} + # runAsUser: 33 + # runAsGroup: 33 + # runAsNonRoot: true + # readOnlyRootFilesystem: false + + # Set securityContext parameters for the entire pod. For example, you may need to define runAsNonRoot directive + podSecurityContext: {} + # runAsUser: 33 + # runAsGroup: 33 + # runAsNonRoot: true + # readOnlyRootFilesystem: false + + # Settings for the MariaDB init container + mariaDbInitContainer: + resources: {} + # Set mariadb initContainer securityContext parameters. For example, you may need to define runAsNonRoot directive + securityContext: {} + + # Settings for the PostgreSQL init container + postgreSqlInitContainer: + resources: {} + # Set postgresql initContainer securityContext parameters. For example, you may need to define runAsNonRoot directive + securityContext: {} + + # -- priority class for nextcloud. + # Overrides .Values.priorityClassName + priorityClassName: "" + + + +## +## External database configuration +## +externalDatabase: + enabled: true + type: postgresql + host: nextcloud-postgresql # service name of subchart (default) + #user: nextcloud + #database: nextcloud + #password: "MyStrongPass123" + existingSecret: + enabled: true + secretName: nextcloud-db + passwordKey: password + +## +## PostgreSQL chart configuration +## for more options see https://github.com/bitnami/charts/tree/main/bitnami/postgresql +## +postgresql: + enabled: true + image: + registry: docker.io + repository: bitnamilegacy/postgresql + global: + postgresql: + # global.postgresql.auth overrides postgresql.auth + #auth: + # username: nextcloud + # password: "MyStrongPass123" + # database: nextcloud + auth: + #username: nextcloud + #database: nextcloud + existingSecret: nextcloud-postgresql + + primary: + resources: + requests: + memory: 512Mi + limits: + memory: 1Gi + persistence: + enabled: true + # Use an existing Persistent Volume Claim (must be created ahead of time) + existingClaim: pvc-nextcloud-postgres + storageClass: nextcloud-postgres-storage + +## +## Collabora chart configuration +## for more options see https://github.com/CollaboraOnline/online/tree/master/kubernetes/helm/collabora-online +## +collabora: + enabled: true + + # url in admin should be: https://collabora.immich-ad.ovh + collabora: + ## HTTPS nextcloud domain, if needed + aliasgroups: + - host: https://nextcloud.immich-ad.ovh:443 + + securityContext: + privileged: true + + env: + # We terminate TLS at Traefik, so Collabora must not try to do HTTPS itself + - name: DONT_GEN_SSL_CERT + value: "true" + # Tell Collabora which Nextcloud URL is allowed to use it + - name: aliasgroup1 + value: https://nextcloud.immich-ad.ovh:443 + + # set extra parameters for collabora + # you may need to add --o:ssl.termination=true + extra_params: > + --o:ssl.enable=false + --o:ssl.termination=true + + + ## Specify server_name when the hostname is not reachable directly for + # example behind reverse-proxy. example: collabora.domain + server_name: null + + existingSecret: + # set to true to to get collabora admin credentials from an existin secret + # if set, ignores collabora.collabora.username and password + enabled: false + # name of existing Kubernetes Secret with collboara admin credentials + secretName: "" + usernameKey: "username" + passwordKey: "password" + + # setup admin login credentials, these are ignored if + # collabora.collabora.existingSecret.enabled=true + password: examplepass + username: admin + + # setup ingress + ingress: + enabled: true + className: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/proxy-body-size: "0" + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: collabora.immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - hosts: + - collabora.immich-ad.ovh + secretName: collabora-tls + + # see collabora helm README.md for recommended values + resources: {} + readinessProbe: + enabled: true + path: /hosting/discovery + port: 9980 + scheme: HTTP + initialDelaySeconds: 40 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 6 + + livenessProbe: + enabled: true + path: /hosting/discovery + port: 9980 + scheme: HTTP + initialDelaySeconds: 60 +## Cronjob to execute Nextcloud background tasks +## ref: https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/background_jobs_configuration.html#cron +## +cronjob: + enabled: true + + # Either 'sidecar' or 'cronjob' + type: sidecar + + # Runs crond as a sidecar container in the Nextcloud pod + # Note: crond requires root + sidecar: + ## Cronjob sidecar resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + ## + resources: {} + + # Allow configuration of lifecycle hooks + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/ + lifecycle: {} + # lifecycle: + # postStartCommand: [] + # preStopCommand: [] + # Set securityContext parameters. For example, you may need to define runAsNonRoot directive + securityContext: {} + # runAsUser: 33 + # runAsGroup: 33 + # runAsNonRoot: true + # readOnlyRootFilesystem: true + + # The command the cronjob container executes. + command: + - /cron.sh + + # Uses a Kubernetes CronJob to execute the Nextcloud cron tasks + # Note: can run as non-root user. Should run as same user as the Nextcloud pod. + cronjob: + # Use a CronJob instead of crond sidecar container + # crond does not work when not running as root user + # Note: requires `persistence.enabled=true` + schedule: "*/5 * * * *" + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 5 + # -- Additional labels for cronjob + labels: {} + # -- Additional labels for cronjob pod + podLabels: {} + annotations: {} + backoffLimit: 1 + affinity: {} + # Often RWO volumes are used. But the cronjob pod needs access to the same volume as the nextcloud pod. + # Depending on your provider two pods on the same node can still access the same volume. + # Following config ensures that the cronjob pod is scheduled on the same node as the nextcloud pod. + # affinity: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: app.kubernetes.io/name + # operator: In + # values: + # - nextcloud + # - key: app.kubernetes.io/component + # operator: In + # values: + # - app + # topologyKey: kubernetes.io/hostname + + ## Resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + ## + resources: {} + + # -- priority class for the cron job. + # Overrides .Values.priorityClassName + priorityClassName: "" + + # Allow configuration of lifecycle hooks + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/ + # Set securityContext parameters. For example, you may need to define runAsNonRoot directive + securityContext: {} + # runAsUser: 33 + # runAsGroup: 33 + # runAsNonRoot: true + # readOnlyRootFilesystem: true + + # The command to run in the cronjob container + # Example to incerase memory limit: php -d memory_limit=2G ... + command: + - php + - -f + - /var/www/html/cron.php + - -- + - --verbose + +service: + type: ClusterIP + port: 8080 + loadBalancerIP: "" + nodePort: + # -- use additional annotation on service for nextcloud + annotations: {} + # -- Set this to "ClientIP" to make sure that connections from the same client + # are passed to the same Nextcloud pod each time. + sessionAffinity: "" + sessionAffinityConfig: {} + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ +## +persistence: + # Nextcloud Data (/var/www/html) + enabled: true + existingClaim: pvc-nextcloud-data + storageClass: nextcloud-data + + + ## Use an additional pvc for the data directory rather than a subpath of the default PVC + ## Useful to store data on a different storageClass (e.g. on slower disks) + nextcloudData: + enabled: false + subPath: + labels: {} + annotations: {} + # storageClass: "-" + # existingClaim: + accessMode: ReadWriteOnce + size: 8Gi + +redis: + enabled: yes + architecture: standalone + auth: + enabled: true + password: "StrongRedisPass" + master: + persistence: + enabled: false + size: 1Gi + +resources: {} +# We usually recommend not to specify default resources and to leave this as a conscious +# choice for the user. This also increases chances charts run on environments with little +# resources, such as Minikube. If you do want to specify resources, uncomment the following +# lines, adjust them as necessary, and remove the curly braces after 'resources:'. +# resources: +# limits: +# cpu: 100m +# memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi + +# -- Priority class for pods. This is the _default_ +# priority class for pods created by this deployment - it may be +# overridden by more specific instances of priorityClassName - +# e.g. cronjob.cronjob.priorityClassName +priorityClassName: "" + +## Liveness and readiness probe values +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 +readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 +startupProbe: + enabled: false + initialDelaySeconds: 50 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 30 + successThreshold: 1 + +## Enable pod autoscaling using HorizontalPodAutoscaler +## ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ +## +hpa: + enabled: false + cputhreshold: 60 + minPods: 1 + maxPods: 10 + +nodeSelector: {} + +tolerations: [] + +# -- Nextcloud pod topologySpreadConstraints +topologySpreadConstraints: [] + +affinity: {} + +dnsConfig: {} +# Custom dns config for Nextcloud containers. +# You can for example configure ndots. This may be needed in some clusters with alpine images. +# options: +# - name: ndots +# value: "1" + +imaginary: + # -- Start Imgaginary + enabled: false + # -- Number of imaginary pod replicas to deploy + replicaCount: 1 + + image: + # -- Imaginary image registry + registry: docker.io + # -- Imaginary image name + repository: h2non/imaginary + # -- Imaginary image tag + tag: 1.2.4 + # -- Imaginary image pull policy + pullPolicy: IfNotPresent + # -- Imaginary image pull secrets + pullSecrets: [] + + # -- Additional annotations for imaginary + podAnnotations: {} + # -- Additional labels for imaginary + podLabels: {} + # -- Imaginary pod nodeSelector + nodeSelector: {} + # -- Imaginary pod tolerations + tolerations: [] + # -- Imaginary pod topologySpreadConstraints + topologySpreadConstraints: [] + + # -- imaginary resources + resources: {} + + # -- priority class for imaginary. + # Overrides .Values.priorityClassName + priorityClassName: "" + + # -- Optional security context for the Imaginary container + securityContext: + runAsUser: 1000 + runAsNonRoot: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + + # -- Optional security context for the Imaginary pod (applies to all containers in the pod) + podSecurityContext: {} + # runAsNonRoot: true + # seccompProfile: + # type: RuntimeDefault + + readinessProbe: + enabled: true + failureThreshold: 3 + successThreshold: 1 + periodSeconds: 10 + timeoutSeconds: 1 + livenessProbe: + enabled: true + failureThreshold: 3 + successThreshold: 1 + periodSeconds: 10 + timeoutSeconds: 1 + + service: + # -- Imaginary: Kubernetes Service type + type: ClusterIP + # -- Imaginary: LoadBalancerIp for service type LoadBalancer + loadBalancerIP: + # -- Imaginary: NodePort for service type NodePort + nodePort: + # -- Additional annotations for service imaginary + annotations: {} + # -- Additional labels for service imaginary + labels: {} + +## Prometheus Exporter / Metrics +## +metrics: + enabled: false + + replicaCount: 1 + # Optional: becomes NEXTCLOUD_SERVER env var in the nextcloud-exporter container. + # Without it, we will use the full name of the nextcloud service + server: "" + # The metrics exporter needs to know how you serve Nextcloud either http or https + https: false + # Use API token if set, otherwise fall back to password authentication + # https://github.com/xperimental/nextcloud-exporter#token-authentication + # Currently you still need to set the token manually in your nextcloud install + token: "" + timeout: 5s + # if set to true, exporter skips certificate verification of Nextcloud server. + tlsSkipVerify: false + info: + # Optional: becomes NEXTCLOUD_INFO_APPS env var in the nextcloud-exporter container. + # Enables gathering of apps-related metrics. Defaults to false + apps: false + update: false + + image: + registry: docker.io + repository: xperimental/nextcloud-exporter + tag: 0.8.0 + pullPolicy: IfNotPresent + # pullSecrets: + # - myRegistrKeySecretName + + ## Metrics exporter resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + ## + resources: {} + + # -- Metrics exporter pod Annotation + podAnnotations: {} + + # -- Metrics exporter pod Labels + podLabels: {} + + # -- Metrics exporter pod nodeSelector + nodeSelector: {} + + # -- Metrics exporter pod tolerations + tolerations: [] + + # -- Metrics exporter pod affinity + affinity: {} + + service: + type: ClusterIP + # Use serviceLoadBalancerIP to request a specific static IP, + # otherwise leave blank + loadBalancerIP: + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9205" + labels: {} + + # -- security context for the metrics CONTAINER in the pod + securityContext: + runAsUser: 1000 + runAsNonRoot: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + + # -- security context for the metrics POD + podSecurityContext: {} + # runAsNonRoot: true + # seccompProfile: + # type: RuntimeDefault + + ## Prometheus Operator ServiceMonitor configuration + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor Resource for scraping metrics using PrometheusOperator + ## + enabled: false + + ## @param metrics.serviceMonitor.namespace Namespace in which Prometheus is running + ## + namespace: "" + + ## @param metrics.serviceMonitor.namespaceSelector The selector of the namespace where the target service is located (defaults to the release namespace) + namespaceSelector: + + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus. + ## + jobLabel: "" + + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + # ref: https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.Endpoint + ## + interval: 30s + + ## @param metrics.serviceMonitor.scrapeTimeout Specify the timeout after which the scrape is ended + # ref: https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.Endpoint + ## + scrapeTimeout: "" + + ## @param metrics.serviceMonitor.labels Extra labels for the ServiceMonitor + ## + labels: {} + + rules: + # -- Deploy Prometheus Rules (Alerts) for the exporter + # @section -- Metrics + enabled: false + # -- Label on Prometheus Rules CRD Manifest + # @section -- Metrics + labels: {} + defaults: + # -- Add Default Rules + # @section -- Metrics + enabled: true + # -- Label on the rules (the severity is already set) + # @section -- Metrics + labels: {} + # -- Filter on metrics on alerts (default just for this helm-chart) + # @section -- Metrics + filter: "" + # -- Add own Rules to Prometheus Rules + # @section -- Metrics + additionalRules: [] + + +# -- Allows users to inject additional Kubernetes manifests (YAML) to be rendered with the release. +# Could either be a list or a map +# If a map, each key is the name of the manifest. +# If an array, each item is a manifest, which can be a string (YAML block) or a YAML object. +# Each item should be a string containing valid YAML. Example: +# extraManifests: +# - | +# apiVersion: traefik.containo.us/v1alpha1 +# kind: Middleware +# metadata: +# name: my-middleware +# spec: +# ... +# - | +# apiVersion: traefik.containo.us/v1alpha1 +# kind: IngressRoute +# metadata: +# name: my-ingressroute +# spec: +# ... +# Or as a map: +# extraManifests: +# my-middleware: +# apiVersion: traefik.containo.us/v1alpha1 +# kind: Middleware +# metadata: +# name: my-middleware +# spec: +# ... +# my-ingressroute: +# apiVersion: traefik.containo.us/v1alpha1 +# kind: IngressRoute +# metadata: +# name: my-ingressroute +# spec: +# ... +extraManifests: [] \ No newline at end of file diff --git a/observability/alloy/values.yaml b/observability/alloy/values.yaml new file mode 100644 index 0000000..8243845 --- /dev/null +++ b/observability/alloy/values.yaml @@ -0,0 +1,124 @@ +controller: + type: daemonset + +alloy: + configMap: + create: true + content: | + logging { + level = "info" + } + loki.write "default" { + endpoint { + url = "http://loki.observability.svc.cluster.local:3100/loki/api/v1/push" + } + } + + // discovery.kubernetes allows you to find scrape targets from Kubernetes resources. + // It watches cluster state and ensures targets are continually synced with what is currently running in your cluster. + discovery.kubernetes "pod" { + role = "pod" + // Restrict to pods on the node to reduce cpu & memory usage + selectors { + role = "pod" + field = "spec.nodeName=" + coalesce(sys.env("HOSTNAME"), constants.hostname) + } + } + + // discovery.relabel rewrites the label set of the input targets by applying one or more relabeling rules. + // If no rules are defined, then the input targets are exported as-is. + discovery.relabel "pod_logs" { + targets = discovery.kubernetes.pod.targets + + // Label creation - "namespace" field from "__meta_kubernetes_namespace" + rule { + source_labels = ["__meta_kubernetes_namespace"] + action = "replace" + target_label = "namespace" + } + + // Label creation - "pod" field from "__meta_kubernetes_pod_name" + rule { + source_labels = ["__meta_kubernetes_pod_name"] + action = "replace" + target_label = "pod" + } + + // Label creation - "container" field from "__meta_kubernetes_pod_container_name" + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + action = "replace" + target_label = "container" + } + + // Label creation - "app" field from "__meta_kubernetes_pod_label_app_kubernetes_io_name" + rule { + source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"] + action = "replace" + target_label = "app" + } + + // Label creation - "job" field from "__meta_kubernetes_namespace" and "__meta_kubernetes_pod_container_name" + // Concatenate values __meta_kubernetes_namespace/__meta_kubernetes_pod_container_name + rule { + source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] + action = "replace" + target_label = "job" + separator = "/" + replacement = "$1" + } + + // Label creation - "__path__" field from "__meta_kubernetes_pod_uid" and "__meta_kubernetes_pod_container_name" + // Concatenate values __meta_kubernetes_pod_uid/__meta_kubernetes_pod_container_name.log + rule { + source_labels = ["__meta_kubernetes_pod_uid", "__meta_kubernetes_pod_container_name"] + action = "replace" + target_label = "__path__" + separator = "/" + replacement = "/var/log/pods/*$1/*.log" + } + + // Label creation - "container_runtime" field from "__meta_kubernetes_pod_container_id" + rule { + source_labels = ["__meta_kubernetes_pod_container_id"] + action = "replace" + target_label = "container_runtime" + regex = "^(\\S+):\\/\\/.+$" + replacement = "$1" + } + } + + // loki.source.kubernetes tails logs from Kubernetes containers using the Kubernetes API. + loki.source.kubernetes "pod_logs" { + targets = discovery.relabel.pod_logs.output + forward_to = [loki.process.pod_logs.receiver] + } + + // loki.process receives log entries from other Loki components, applies one or more processing stages, + // and forwards the results to the list of receivers in the component's arguments. + loki.process "pod_logs" { + stage.static_labels { + values = { + cluster = "master", + } + } + + forward_to = [loki.write.default.receiver] + } + + extraVolumes: + - name: varlog + hostPath: + path: /var/log + extraVolumeMounts: + - name: varlog + mountPath: /var/log + readOnly: true + + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 300m + memory: 256Mi \ No newline at end of file diff --git a/observability/grafana/pv-loki.yaml b/observability/grafana/pv-loki.yaml new file mode 100644 index 0000000..a329936 --- /dev/null +++ b/observability/grafana/pv-loki.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-loki-data +spec: + capacity: + storage: 20Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: loki-data + local: + path: /storage/loki + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/observability/grafana/pvc-loki.yaml b/observability/grafana/pvc-loki.yaml new file mode 100644 index 0000000..ff43988 --- /dev/null +++ b/observability/grafana/pvc-loki.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-loki-data + namespace: observability +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi + storageClassName: loki-data \ No newline at end of file diff --git a/observability/grafana/values.yaml b/observability/grafana/values.yaml new file mode 100644 index 0000000..0f91e36 --- /dev/null +++ b/observability/grafana/values.yaml @@ -0,0 +1,38 @@ +adminUser: admin +adminPassword: "admin" # or use an existingSecret + +resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 300m + memory: 512Mi + +persistence: + enabled: true + storageClassName: loki-data + existingClaim: pvc-loki-data + +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Loki + type: loki + access: proxy + url: http://loki.observability.svc.cluster.local:3100 + isDefault: true + +ingress: + enabled: true + ingressClassName: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + hosts: + - grafana.immich-ad.ovh + tls: + - secretName: grafana-tls + hosts: + - grafana.immich-ad.ovh diff --git a/observability/loki/storage-loki.yaml b/observability/loki/storage-loki.yaml new file mode 100644 index 0000000..a5f491e --- /dev/null +++ b/observability/loki/storage-loki.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: storage-loki-0 +spec: + capacity: + storage: 20Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + local: + path: /storage/loki-data + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/observability/loki/values.yaml b/observability/loki/values.yaml new file mode 100644 index 0000000..b56d100 --- /dev/null +++ b/observability/loki/values.yaml @@ -0,0 +1,59 @@ +# simplest storage for homelab: filesystem + PVC (works well for small volume) +loki: + auth_enabled: false + commonConfig: + replication_factor: 1 + storage: + type: filesystem + schemaConfig: + configs: + - from: "2024-01-01" + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: loki_index_ + period: 24h + limits_config: + retention_period: 14d + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 768Mi + persistence: + enabled: true + size: 10Gi + +deploymentMode: SingleBinary + +backend: + replicas: 0 +read: + replicas: 0 +write: + replicas: 0 + + +singleBinary: + replicas: 1 + +promtail: + enabled: false +prometheus: + enabled: false +canary: + enabled: false +gateway: + enabled: false +results_cache: + enabled: false +chunks_cache: + enabled: false +memcached: + enabled: false +memberlist: + service: + enabled: false \ No newline at end of file diff --git a/observability/notes.md b/observability/notes.md new file mode 100644 index 0000000..506ba3b --- /dev/null +++ b/observability/notes.md @@ -0,0 +1,26 @@ + + +``` +helm upgrade --install grafana grafana/grafana -n observability -f values.yaml +helm delete grafana -n observability + +helm upgrade --install loki grafana/loki -n observability -f values.yaml +helm delete loki -n observability + +helm upgrade --install alloy grafana/alloy -n observability -f values.yaml +helm delete alloy -n observability + + +helm upgrade --install kps prometheus-community/kube-prometheus-stack \ + -n observability -f values.yaml +helm delete kps -n observability + + + +kubectl get pods -n observability + + +kubectl -n observability describe pod loki-0 + +kubectl logs -n observability loki-0 --tail=200 +``` \ No newline at end of file diff --git a/observability/prometheus/pv-prometheus.yaml b/observability/prometheus/pv-prometheus.yaml new file mode 100644 index 0000000..684a4bf --- /dev/null +++ b/observability/prometheus/pv-prometheus.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-prometheus-data +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: prometheus-data + local: + path: /storage/prometheus + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/observability/prometheus/storageclass-prometheus-data.yaml b/observability/prometheus/storageclass-prometheus-data.yaml new file mode 100644 index 0000000..ebc0d90 --- /dev/null +++ b/observability/prometheus/storageclass-prometheus-data.yaml @@ -0,0 +1,7 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: prometheus-data +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer +reclaimPolicy: Retain \ No newline at end of file diff --git a/observability/prometheus/values.yaml b/observability/prometheus/values.yaml new file mode 100644 index 0000000..8f394fd --- /dev/null +++ b/observability/prometheus/values.yaml @@ -0,0 +1,27 @@ +grafana: + enabled: false # you already run Grafana + +alertmanager: + enabled: false # keep it light (enable later if you want) + +prometheus: + prometheusSpec: + replicas: 1 + retention: 7d + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + storageSpec: + volumeClaimTemplate: + spec: + storageClassName: prometheus-data + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi \ No newline at end of file diff --git a/shared-db/postgres-nodeport.yaml b/shared-db/postgres-nodeport.yaml new file mode 100644 index 0000000..6f2a296 --- /dev/null +++ b/shared-db/postgres-nodeport.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: shared-postgres-nodeport + namespace: db +spec: + type: NodePort + selector: + cnpg.io/cluster: shared-postgres + role: primary + ports: + - name: postgres + port: 5432 + targetPort: 5432 + nodePort: 30432 \ No newline at end of file diff --git a/shared-db/postgres.yaml b/shared-db/postgres.yaml new file mode 100644 index 0000000..70f6401 --- /dev/null +++ b/shared-db/postgres.yaml @@ -0,0 +1,28 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: shared-postgres + namespace: db +spec: + instances: 1 + + storage: + pvcTemplate: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: pvc-shared-postgres + volumeMode: Filesystem + imageName: ghcr.io/cloudnative-pg/postgresql:16 + + bootstrap: + initdb: + database: dbtest + owner: admin + secret: + name: shared-postgres-app + postInitApplicationSQL: + - ALTER USER admin WITH SUPERUSER; + - CREATE EXTENSION vector; \ No newline at end of file diff --git a/shared-db/pv-shared-postgres.yaml b/shared-db/pv-shared-postgres.yaml new file mode 100644 index 0000000..2e84cff --- /dev/null +++ b/shared-db/pv-shared-postgres.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-shared-postgres +spec: + capacity: + storage: 100Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: shared-postgres + local: + path: /storage/shared-postgres + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/shared-db/pvc-shared-postgres.yaml b/shared-db/pvc-shared-postgres.yaml new file mode 100644 index 0000000..439ad8a --- /dev/null +++ b/shared-db/pvc-shared-postgres.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-shared-postgres + namespace: db +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: shared-postgres \ No newline at end of file diff --git a/traefik/values.yaml b/traefik/values.yaml new file mode 100644 index 0000000..e5739d6 --- /dev/null +++ b/traefik/values.yaml @@ -0,0 +1,14 @@ +ingressRoute: + dashboard: + enabled: true + matchRule: Host(`dashboard.localhost`) + entryPoints: + - web +providers: + kubernetesGateway: + enabled: true +gateway: + listeners: + web: + namespacePolicy: + from: All \ No newline at end of file diff --git a/vaultwarden/Chart.lock b/vaultwarden/Chart.lock new file mode 100644 index 0000000..6d708fe --- /dev/null +++ b/vaultwarden/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 15.5.29 +digest: sha256:e02780f5fb6cf25d49477b43986ea907d96df3167f5a398a34eedad988c841e7 +generated: "2025-12-21T17:14:41.412181861Z" diff --git a/vaultwarden/Chart.yaml b/vaultwarden/Chart.yaml new file mode 100644 index 0000000..4796299 --- /dev/null +++ b/vaultwarden/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: vaultwarden +description: Vaultwarden with Bitnami PostgreSQL subchart +type: application +version: 0.1.0 +appVersion: "1.32.0" + +dependencies: + - name: postgresql + version: 15.5.29 + repository: https://charts.bitnami.com/bitnami diff --git a/vaultwarden/charts/postgresql-15.5.29.tgz b/vaultwarden/charts/postgresql-15.5.29.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ef2dac4c2d25190bd5563d97d09c8625ff65477d GIT binary patch literal 75764 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

N5O}<4Lx~c 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%0AxRW7k(iPn*IS(o5e!lm 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 JTKfQ|2mqLcd_VvI literal 0 HcmV?d00001 diff --git a/vaultwarden/notes.md b/vaultwarden/notes.md new file mode 100644 index 0000000..d09c2e6 --- /dev/null +++ b/vaultwarden/notes.md @@ -0,0 +1,32 @@ +# vaultwarden lite + +https://vaultwarden.com/help/install-and-deploy + +https://github.com/dani-garcia/vaultwarden/wiki/Using-the-PostgreSQL-Backend +``` +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update +helm dependency build +helm upgrade --install vaultwarden . -f values.yaml -n vaultwarden + +helm delete vaultwarden -n vaultwarden +kubectl -n vaultwarden rollout restart deploy/vaultwarden + +kubectl -n vaultwarden create secret generic vaultwarden-postgresql-auth \ + --from-literal=postgres-password='pwdvaultwardenSqlStorage' \ + --from-literal=password='pwdvaultwardenStorage' + +kubectl -n vaultwarden create secret generic vaultwarden-db-url \ + --from-literal=DATABASE_URL='postgresql://vaultwarden:pwdvaultwardenStorage@vaultwarden-postgresql:5432/vaultwarden' + +kubectl -n vaultwarden create secret generic vaultwarden-smtp \ + --from-literal=SMTP_HOST='ssl0.ovh.net' \ + --from-literal=SMTP_PORT='587' \ + --from-literal=SMTP_SECURITY='starttls' \ + --from-literal=SMTP_USERNAME='admin@immich-ad.ovh' \ + --from-literal=SMTP_PASSWORD=',3FV\]Knv_AqC' \ + --from-literal=SMTP_FROM='admin@immich-ad.ovh' + + +kubectl -n vaultwarden get pods +``` \ No newline at end of file diff --git a/vaultwarden/pv-vaultwarden.yaml b/vaultwarden/pv-vaultwarden.yaml new file mode 100644 index 0000000..9394402 --- /dev/null +++ b/vaultwarden/pv-vaultwarden.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pv-vaultwarden-data +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: vaultwarden-data + local: + path: /storage/vaultwarden + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/vaultwarden/pvc-vaultwarden.yaml b/vaultwarden/pvc-vaultwarden.yaml new file mode 100644 index 0000000..573eb2b --- /dev/null +++ b/vaultwarden/pvc-vaultwarden.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-vaultwarden-data + namespace: vaultwarden +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: vaultwarden-data \ No newline at end of file diff --git a/vaultwarden/templates/_helpers.tpl b/vaultwarden/templates/_helpers.tpl new file mode 100644 index 0000000..de4514a --- /dev/null +++ b/vaultwarden/templates/_helpers.tpl @@ -0,0 +1,30 @@ +{{- define "vaultwarden.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "vaultwarden.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" (include "vaultwarden.name" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "vaultwarden.labels" -}} +app.kubernetes.io/name: {{ include "vaultwarden.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | quote }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "vaultwarden.selectorLabels" -}} +app.kubernetes.io/name: {{ include "vaultwarden.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} \ No newline at end of file diff --git a/vaultwarden/templates/deployment.yaml b/vaultwarden/templates/deployment.yaml new file mode 100644 index 0000000..9dc2eaa --- /dev/null +++ b/vaultwarden/templates/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "vaultwarden.fullname" . }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ include "vaultwarden.fullname" . }} + template: + metadata: + labels: + app: {{ include "vaultwarden.fullname" . }} + spec: + containers: + - name: vaultwarden + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + env: + - name: ADMIN_TOKEN + value: {{ .Values.vaultwarden.adminToken | quote }} + - name: SIGNUPS_ALLOWED + value: {{ .Values.vaultwarden.signupAllowed | quote }} + envFrom: + - secretRef: + name: vaultwarden-smtp # SMTP secret + - secretRef: + name: vaultwarden-db-url # Database URL secret + volumeMounts: + - name: data + mountPath: /data + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ default (printf "%s-data" (include "vaultwarden.fullname" .)) .Values.persistence.existingClaim }} diff --git a/vaultwarden/templates/ingress.yaml b/vaultwarden/templates/ingress.yaml new file mode 100644 index 0000000..2803b4f --- /dev/null +++ b/vaultwarden/templates/ingress.yaml @@ -0,0 +1,55 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "vaultwarden.fullname" . }} + labels: + {{- include "vaultwarden.labels" . | nindent 4 }} + {{- if .Values.ingress.annotations }} + annotations: + {{- toYaml .Values.ingress.annotations | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + - host: {{ .Values.vaultwarden.domain | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + service: + name: {{ include "vaultwarden.fullname" . }} + port: + number: {{ .Values.service.port }} + {{- range .Values.ingress.extraHosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ include "vaultwarden.fullname" . }} + port: + number: {{ .Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/vaultwarden/templates/service.yaml b/vaultwarden/templates/service.yaml new file mode 100644 index 0000000..cb3a41f --- /dev/null +++ b/vaultwarden/templates/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "vaultwarden.fullname" . }} +spec: + type: {{ .Values.service.type }} + selector: + app: {{ include "vaultwarden.fullname" . }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: 80 \ No newline at end of file diff --git a/vaultwarden/values.yaml b/vaultwarden/values.yaml new file mode 100644 index 0000000..d00023c --- /dev/null +++ b/vaultwarden/values.yaml @@ -0,0 +1,65 @@ +image: + repository: docker.io/vaultwarden/server + tag: 1.35.3 + pullPolicy: IfNotPresent + +replicaCount: 1 + +service: + type: ClusterIP + port: 8080 + +ingress: + enabled: true + ingressClassName: traefik + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + hosts: + - host: vaultwarden.immich-ad.ovh + paths: + - path: / + pathType: Prefix + tls: + - secretName: vaultwarden-tls + hosts: + - vaultwarden.immich-ad.ovh + +# Persist vaultwarden data (attachments, icon cache, etc.) +persistence: + enabled: true + existingClaim: pvc-vaultwarden-data + +vaultwarden: + # REQUIRED for secure cookies, web vault, etc. + domain: "vaultwarden.immich-ad.ovh" + signupAllowed: false + adminToken: "x4FBfkK4f1wDCuXWQdX9" + +# Database config +database: + name: vaultwarden + user: vaultwarden + +# Bitnami PostgreSQL subchart values +postgresql: + enabled: true + image: + registry: docker.io + repository: bitnami/postgresql + tag: latest + + auth: + username: vaultwarden + database: vaultwarden + + # Upgrade-safe: point to an existing secret you create once + existingSecret: vaultwarden-postgresql-auth + secretKeys: + adminPasswordKey: postgres-password + userPasswordKey: password + + primary: + persistence: + enabled: true + existingClaim: pvc-vaultwarden-data # bind to precreated PVC if you want \ No newline at end of file