feat(k8s/lubelogger): migrate to Helm + PostgreSQL with OIDC
This commit is contained in:
127
kubernetes/app/lubelogger/MIGRATION.md
Normal file
127
kubernetes/app/lubelogger/MIGRATION.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# LubeLogger Migration: Docker → Kubernetes
|
||||
|
||||
## Overview
|
||||
|
||||
LubeLogger is migrated from a single Docker container using LiteDB (SQLite-like embedded DB) to
|
||||
Kubernetes with PostgreSQL as the data store. The migration involves:
|
||||
|
||||
1. Copying app data (images, documents, config) from the Docker host to NFS
|
||||
2. Running the built-in database migration UI to import records from LiteDB → PostgreSQL
|
||||
|
||||
## Source Layout (Docker)
|
||||
|
||||
| Container Path | Docker Source |
|
||||
|---|---|
|
||||
| `/App/data` | `/home/server/docker/lubelogger/data` on Docker host |
|
||||
| `/root/.aspnet/DataProtection-Keys` | `/home/server/docker/lubelogger/keys` on Docker host |
|
||||
|
||||
The `/App/data` directory contains:
|
||||
- `cartracker.db` — LiteDB database with all vehicle/maintenance records
|
||||
- `images/` — uploaded vehicle images
|
||||
- `documents/` — uploaded maintenance documents
|
||||
|
||||
## Target Layout (Kubernetes)
|
||||
|
||||
| Container Path | Kubernetes PVC |
|
||||
|---|---|
|
||||
| `/App/data` | `lubelogger-data` PVC → NFS `/volume3/k8s-storage/lubelogger-data` |
|
||||
| `/root/.aspnet/DataProtection-Keys` | ephemeral (pod filesystem) — losing keys only invalidates sessions |
|
||||
|
||||
PostgreSQL data is managed by the `lubelogger-db` StatefulSet with its own `nfs-synology-ssd` PVC.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- NFS directory created on Synology: `/volume3/k8s-storage/lubelogger-data`
|
||||
- Secrets filled in and encrypted (see TODO.md)
|
||||
- PostgreSQL restic repos initialized on Synology and B2
|
||||
|
||||
## Step-by-Step Migration
|
||||
|
||||
### 1. Deploy with replicas: 0
|
||||
|
||||
Ensure `statefulset-db.yaml` has `replicas: 1` (PostgreSQL must be running) but set the
|
||||
LubeLogger Helm release to `replicaCount: 0` before the first commit. After Flux applies,
|
||||
all PVCs will be created and bound.
|
||||
|
||||
Actually: PostgreSQL starts at replicas: 1. The app (HelmRelease) starts at replicas: 1 by default
|
||||
from the chart. Since we want to run the migration UI, we need the app running. Scale to 1 normally.
|
||||
|
||||
### 2. Wait for PVCs to bind
|
||||
|
||||
```bash
|
||||
kubectl get pvc -n lubelogger
|
||||
```
|
||||
|
||||
All should be `Bound`. The `lubelogger-data` PVC binds to the static NFS PV automatically.
|
||||
|
||||
The PostgreSQL PVC name is `data-lubelogger-db-0` (StatefulSet volumeClaimTemplate naming).
|
||||
|
||||
### 3. Stop Docker service
|
||||
|
||||
```bash
|
||||
# On the Docker host
|
||||
cd /path/to/lubelogger-compose
|
||||
docker compose stop app
|
||||
# Keep DB stopped too since we're going to PostgreSQL
|
||||
```
|
||||
|
||||
### 4. Copy app data to NFS
|
||||
|
||||
```bash
|
||||
# Create the NFS directory on Synology if not done already
|
||||
mkdir -p /volume3/k8s-storage/lubelogger-data
|
||||
|
||||
# Copy from Docker host to Synology NFS path
|
||||
# Run from the Docker host (or any machine with SSH access to both):
|
||||
rsync -av /home/server/docker/lubelogger/data/ synology:/volume3/k8s-storage/lubelogger-data/
|
||||
```
|
||||
|
||||
The `cartracker.db` file is copied too — it's needed for the migration step.
|
||||
|
||||
### 5. Run the LiteDB → PostgreSQL migration
|
||||
|
||||
Once the Kubernetes app is running and PostgreSQL is ready:
|
||||
|
||||
```bash
|
||||
# Verify LubeLogger pod is running
|
||||
kubectl get pods -n lubelogger
|
||||
|
||||
# Verify PostgreSQL is up
|
||||
kubectl exec -n lubelogger lubelogger-db-0 -- psql -U lubelogger -c '\l'
|
||||
```
|
||||
|
||||
Navigate to `https://lubelogger.berezovskyi.dev/migration` in your browser.
|
||||
|
||||
1. Click **"Import to Postgres"**
|
||||
2. Upload the `cartracker.db` file from your local copy of `/home/server/docker/lubelogger/data/`
|
||||
3. LubeLogger will import all records automatically
|
||||
|
||||
### 6. Verify migration
|
||||
|
||||
- Check all vehicles appear
|
||||
- Check maintenance records
|
||||
- Check images and documents load
|
||||
- Log in via Authelia OIDC
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] All pods running: `kubectl get pods -n lubelogger`
|
||||
- [ ] LubeLogger web UI loads at `https://lubelogger.berezovskyi.dev`
|
||||
- [ ] Authelia OIDC login works
|
||||
- [ ] All vehicles visible with correct data
|
||||
- [ ] Maintenance history records intact
|
||||
- [ ] Images load (stored in NFS `/App/data/images/`)
|
||||
- [ ] Documents accessible
|
||||
- [ ] Test backup: `kubectl create job -n lubelogger --from=cronjob/lubelogger-db-backup test-db-backup`
|
||||
|
||||
## Rollback
|
||||
|
||||
1. Scale HelmRelease to 0: edit `release.yaml` → `replicaCount: 0`, commit, push
|
||||
2. Restart Docker service: `docker compose start app`
|
||||
3. The Docker install still has its LiteDB database intact
|
||||
|
||||
## Notes
|
||||
|
||||
- The Authelia OIDC client was already configured at `lubelogger.berezovskyi.dev` — no changes needed
|
||||
- DataProtection keys are intentionally ephemeral: users will need to log in again after pod restarts
|
||||
- After confirming the migration is complete, the `cartracker.db` in the NFS data directory can be deleted (it is no longer used once PostgreSQL is the backend)
|
||||
156
kubernetes/app/lubelogger/cronjob-backup.yaml
Normal file
156
kubernetes/app/lubelogger/cronjob-backup.yaml
Normal file
@@ -0,0 +1,156 @@
|
||||
---
|
||||
# PostgreSQL database backup
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: lubelogger-db-backup
|
||||
namespace: lubelogger
|
||||
labels:
|
||||
app: lubelogger-backup
|
||||
spec:
|
||||
schedule: "0 2 * * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger-backup
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
initContainers:
|
||||
- name: pg-dump
|
||||
image: postgres:18
|
||||
env:
|
||||
- name: PGHOST
|
||||
value: lubelogger-db
|
||||
- name: PGUSER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_USERNAME
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: PGDATABASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_DATABASE_NAME
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- pg_dump --clean --if-exists > /backup/dump.sql
|
||||
volumeMounts:
|
||||
- name: backup-tmp
|
||||
mountPath: /backup
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
containers:
|
||||
- name: resticprofile
|
||||
image: creativeprojects/resticprofile:0.32.0
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
resticprofile -c /secrets/profiles.yaml -n lubelogger-db backup
|
||||
resticprofile -c /secrets/profiles.yaml -n lubelogger-db copy
|
||||
env:
|
||||
- name: B2_ACCOUNT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-backup-config
|
||||
key: B2_ACCOUNT_ID
|
||||
- name: B2_ACCOUNT_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-backup-config
|
||||
key: B2_ACCOUNT_KEY
|
||||
volumeMounts:
|
||||
- name: secrets
|
||||
mountPath: /secrets
|
||||
readOnly: true
|
||||
- name: backup-tmp
|
||||
mountPath: /backup
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
volumes:
|
||||
- name: secrets
|
||||
secret:
|
||||
secretName: lubelogger-backup-config
|
||||
- name: backup-tmp
|
||||
emptyDir: {}
|
||||
---
|
||||
# App data backup (images, documents)
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: lubelogger-data-backup
|
||||
namespace: lubelogger
|
||||
labels:
|
||||
app: lubelogger-backup
|
||||
spec:
|
||||
schedule: "0 3 * * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger-backup
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: resticprofile
|
||||
image: creativeprojects/resticprofile:0.32.0
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
resticprofile -c /secrets/profiles.yaml -n lubelogger-data backup
|
||||
resticprofile -c /secrets/profiles.yaml -n lubelogger-data copy
|
||||
env:
|
||||
- name: B2_ACCOUNT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-backup-config
|
||||
key: B2_ACCOUNT_ID
|
||||
- name: B2_ACCOUNT_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-backup-config
|
||||
key: B2_ACCOUNT_KEY
|
||||
volumeMounts:
|
||||
- name: secrets
|
||||
mountPath: /secrets
|
||||
readOnly: true
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
volumes:
|
||||
- name: secrets
|
||||
secret:
|
||||
secretName: lubelogger-backup-config
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: lubelogger-data
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger
|
||||
name: lubelogger
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: lubelogger
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/hargata/lubelogger:latest
|
||||
name: lubelogger
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /App/data
|
||||
- name: keys
|
||||
mountPath: /root/.aspnet/DataProtection-Keys
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: lubelogger-data
|
||||
- name: keys
|
||||
persistentVolumeClaim:
|
||||
claimName: lubelogger-keys
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: lubelogger
|
||||
namespace: lubelogger
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- ${LUBELOGGER_HOST}
|
||||
secretName: lubelogger-tls
|
||||
rules:
|
||||
- host: ${LUBELOGGER_HOST}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: lubelogger
|
||||
port:
|
||||
number: 8080
|
||||
@@ -1,4 +1,3 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
|
||||
100
kubernetes/app/lubelogger/networkpolicy.yaml
Normal file
100
kubernetes/app/lubelogger/networkpolicy.yaml
Normal file
@@ -0,0 +1,100 @@
|
||||
# Default deny all ingress
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-ingress
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
---
|
||||
# Allow Traefik to reach the app
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-controller
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lubelogger
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: traefik
|
||||
---
|
||||
# Allow app to reach DB
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-app-to-db
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: lubelogger-db
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lubelogger
|
||||
ports:
|
||||
- port: 5432
|
||||
---
|
||||
# Allow backup pods to reach DB
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-backup-to-db
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: lubelogger-db
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: lubelogger-backup
|
||||
ports:
|
||||
- port: 5432
|
||||
---
|
||||
# Allow backup pods egress (Synology, B2, DNS, DB)
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-backup-egress
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: lubelogger-backup
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- ports:
|
||||
- port: 53
|
||||
protocol: UDP
|
||||
- port: 53
|
||||
protocol: TCP
|
||||
- ports:
|
||||
- port: 8888
|
||||
protocol: TCP
|
||||
- ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
- ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: lubelogger-db
|
||||
@@ -1,35 +1,32 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: lubelogger-data
|
||||
name: lubelogger-data-nfs
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
storage: 5Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: ""
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- hard
|
||||
- nointr
|
||||
- timeo=30
|
||||
- retrans=3
|
||||
nfs:
|
||||
server: synology.storage.lviv
|
||||
path: /volume3/k8s-storage/lubelogger-data
|
||||
path: ${LUBELOGGER_DATA_NFS_PATH}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: lubelogger-keys
|
||||
name: lubelogger-data
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: ""
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- hard
|
||||
- nointr
|
||||
nfs:
|
||||
server: synology.storage.lviv
|
||||
path: /volume3/k8s-storage/lubelogger-keys
|
||||
volumeName: lubelogger-data-nfs
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: lubelogger-data
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: ""
|
||||
volumeName: lubelogger-data
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: lubelogger-keys
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: ""
|
||||
volumeName: lubelogger-keys
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
84
kubernetes/app/lubelogger/release.yaml
Normal file
84
kubernetes/app/lubelogger/release.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: lubelogger
|
||||
namespace: flux-system
|
||||
spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: lubelogger
|
||||
version: 1.4.2
|
||||
reconcileStrategy: ChartVersion
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: anza-labs
|
||||
namespace: flux-system
|
||||
targetNamespace: lubelogger
|
||||
interval: 1m0s
|
||||
values:
|
||||
image:
|
||||
tag: "v1.6.1"
|
||||
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 100%
|
||||
|
||||
config:
|
||||
LANG: en_US.UTF-8
|
||||
LC_ALL: en_US.UTF-8
|
||||
LOGLEVEL: Information
|
||||
translations: []
|
||||
userConfig:
|
||||
AllowedHosts: "*"
|
||||
EnableAuth: true
|
||||
UseDarkMode: false
|
||||
EnableCsvImports: true
|
||||
UseMPG: false
|
||||
UseDescending: true
|
||||
UseThreeDecimalGasCost: true
|
||||
|
||||
postgres:
|
||||
create: false
|
||||
connect: true
|
||||
name: lubelogger-credentials
|
||||
keyRef: POSTGRES_CONNECTION
|
||||
|
||||
oidc:
|
||||
enabled: true
|
||||
create: false
|
||||
name: lubelogger-credentials
|
||||
|
||||
secret:
|
||||
create: false
|
||||
|
||||
persistence:
|
||||
data:
|
||||
enabled: true
|
||||
existingClaim: lubelogger-data
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: ""
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
hosts:
|
||||
- host: ${LUBELOGGER_HOST}
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: lubelogger-tls
|
||||
hosts:
|
||||
- ${LUBELOGGER_HOST}
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
||||
podSecurityContext:
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
8
kubernetes/app/lubelogger/repository.yaml
Normal file
8
kubernetes/app/lubelogger/repository.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: anza-labs
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m0s
|
||||
url: https://anza-labs.github.io/charts
|
||||
26
kubernetes/app/lubelogger/secret-backup.sops.yaml
Normal file
26
kubernetes/app/lubelogger/secret-backup.sops.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: lubelogger-backup-config
|
||||
namespace: lubelogger
|
||||
stringData:
|
||||
profiles.yaml: ENC[AES256_GCM,data:ry4ry1yf+KgUP6D2WzIUaGCPCvsJ8CKjAjJtlMDhHh55KrMEpwmWiHYIaHzRJtYkGpou/mxKyGdPAIDfo2h2teNmBd9sbHd3/FaR5USHqzd+LNhn5LN1aeQ5H7vzFzZj0JVjUwQ6SxppxmW7/kDKFHfTB/QXYchz2QdFtRrBiaXRd0SMYDA7DDLFbGG6x3oxbywpmA5jdojHw/2a18S4eSoLzYZnZZvNR5pMXmmzBUWJ0xBd7t3uzx1MuP+a/tAlalFXcoUg3hH+yFvgF9gb4gxqlDNyvsCBq3klVN43mGYdzC7gzuYGGi5BV8NZ/THSapOsapbux6LbUVebxbt2l2XLv0IoPxZCYKZ0RbA+Of6Fp2tlCekKNey5H2mviPHrjkipt+o7FcNXISSE8k6siky8ouiXFB6Hr/SEZs91i1jgxG1Xwpt7nNSNt2XB2IPjnCSvpAvYW/KlOf880lh7/xmpk5O0Xa4BRF1Hfn/EmsR8HL5q8dSV9OcYUKcIZVMvXFOI+yu10GpkIbueuMuOeFyUUBh3TGJKIJElHzxwDXC5YrqtT3GOphFGnQ+cN1ZHDsywe0Q5wDMxPPGEh6SL/7OpSN5loUZ5MoC65lkVzEQZewG0RBjgiZSIJsCUlIKdmt5AfokXjXxUmb8/qPEVyvL/ltFdzFIiGJcAnlRsM1ltFcrxGr+N6bnr1jyoS6xk5b4QWCJKWhJt4ITeoHZzN9liWOEpKxhYWpN2wlkmpmTgXIVhzi1bR15s7ZX+XbQi9X6iVwGZiJ6T3HLb4BeWo6YvtqebU3fIJabWHr9I956OU8+F8uCLFJjUXUYoT0ww50wsNix0C2PNovNv7SGQO+GH1F7sU6EYJAqKBXZRMF49NCuyAiK9uB5N2xKqh0eEtmGvO/U38ihs1OPZtCzwNg/xo5OHAoJWx09BE8+YR7KRmIh/AJHR6Jfb9JPCb8Qz8iNBMhtxJk2l6clZKMnBNckHk97mGYELFyTPlsVDnHIxWIokMshHxhCtuT/OaxsZawzAUYQ8Tz4TLei1/iTS97wn2AyeF4L6yPSQfYbZWu4mwsuQ2zr3VCmnbzsMomihJgiELSpcoXqh7GEc4FPbhXWBUfdJH1DA9jH/E4LpNnwX1g5bs1cphK6nkcaU6pbsEYiEktvpCV1Vyd9rxcHEIkCVQnLkUZPRIXaW/+7+TQPtKVjvOc33SjTrQJNLuZ2zd0mxrJAforagMZHENBJpefHe4dzy1farKTTccTCCbzVjXkz4+QyjDdI9Qjq+HfPJ5ajrO4mgudNazAJuBWc=,iv:BUdGosePz+FW9bqLuJhSaIMbU0N/2UVjmSJVEAwbk8c=,tag:So7no71/2ypFkyVadF9myg==,type:str]
|
||||
restic-password-nas: ENC[AES256_GCM,data:qhOYuyEjbX4lqOzQM+T+pQEWxm8LqTy/yskxw9tl6bMz0OnwbkdJ87TVqUV99TRbRteoNfEnbUec3P/w2H4LVw==,iv:Ge5RiXnavsohOfh90Nn2cmdvY4qapK5QYoC8O13j52E=,tag:NjRsyb/F7sMd/UBZr3PIAg==,type:str]
|
||||
restic-password-b2: ENC[AES256_GCM,data:emCXooHFBUTBN0fuVN+bG2LfYcoxDr6vYEWNV/4A9Eru/cXXwfvzQQOasmRKVxtd13AmtQlZMY7MgTg1cvackw==,iv:rzYf2hA3/MDz8eVn9NrgjTEA0+qhKcrtGGvEIITfJws=,tag:n/PP2R81FH6WfvOQsZyejw==,type:str]
|
||||
B2_ACCOUNT_ID: ENC[AES256_GCM,data:5emkgkrSMlo9SAcMgjLtu4TiRMxi4GGxng==,iv:bhaBY5vZey6+bz1/xje3CGznWh4XoFBEPAaYYdhipbs=,tag:DzPTv9gyCiuuRuiot7eshg==,type:str]
|
||||
B2_ACCOUNT_KEY: ENC[AES256_GCM,data:M5r+drnI7MyvYs5XpAbvyZbEDuY4hQCgQEgwpQO8JQ==,iv:fKEDq2fqpOdn3WqSN8YcBK2/7cNgLkAfDewzuuInVYE=,tag:NuWBKr7J/asYgqa8e5xrHg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJK09RUldOZVdNSENrQ0J0
|
||||
cHU3dWlVYnllV3RmWUFTdUM0U0ZLeHpwN1hBCmZ4TTMyVy9FMEtGcWRRUzUzWHpN
|
||||
bnhiNHZZbWVzelNqNXVTUlBDYzlpUEUKLS0tIEFGOXhNN0pIeXpiZ29LdTB4Vm9T
|
||||
REdCTDVUSjVGbFh6aGlhUFVFR3VhazAKLpa4UUq4ev4IvexmhVcZm9UJl15bi4TZ
|
||||
/AM7PcY1khK48OJA2QczOXpL6VkKin5YY3zUBmU388boVgWNPU7ygw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-03-12T17:28:48Z"
|
||||
mac: ENC[AES256_GCM,data:33oz/vhF702e0a4JdGoQ6iM0huUufXlQS69o2dCemASpDpfl4+fl1N0e4KWM16WiVkN2PV1Tbc/nPa+0nZ6rIg3XZwnVY9Zemr3WNfMHEtodJRxN4WZPQ3sJ2rRAfGTus2SnYFs2mHYXPHzyY6aFBUKfEExbUL7UU2wQ1UmK1H4=,iv:0QisSz8NnEL09q8z8I5BtkdcDjO5yOF9XZhMyagxNxc=,tag:3JGHRQl5P9uKS5xQ+jBdIg==,type:str]
|
||||
encrypted_regex: ^(data|stringData|email)$
|
||||
version: 3.12.1
|
||||
26
kubernetes/app/lubelogger/secret-mail.sops.yaml
Normal file
26
kubernetes/app/lubelogger/secret-mail.sops.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: lubelogger-lubelogger-mail
|
||||
namespace: lubelogger
|
||||
stringData:
|
||||
MailConfig__EmailServer: ""
|
||||
MailConfig__EmailFrom: ""
|
||||
MailConfig__Port: ENC[AES256_GCM,data:BAtd,iv:i5Q/4OONVm0c7wZe8JvKnF/bMSH9bh8XY4+2xwGh36E=,tag:i+q0spj4URbiShtEvnbghQ==,type:str]
|
||||
MailConfig__Username: ""
|
||||
MailConfig__Password: ""
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5M2loaXBwVmMrcHBUaTJV
|
||||
Smp0bURnUWh6ZjFUcUhFc3p4ZGxGVHlMbUc4Cm4vdnBvOS9zeVBDVE84dkEzek9N
|
||||
Y3ROelkxY3A3cXN5ODZ4RHZEd2c1YWcKLS0tIDZPZEQ4cVQwcldscDdaeVJzMTBI
|
||||
emlNNUFSOERJeEdNSkdpdEs0QVUralkKN9aSdQnGXGzLrZfCOFO1VgSAOC5PWkE8
|
||||
HRB6woNiTVPTgwObG+7u8/IxLN/WdwAGjx3ETBMys4BYk2QhjLkADg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-03-12T17:41:00Z"
|
||||
mac: ENC[AES256_GCM,data:bLdSIuaRXGcGRjnIuboJnRkabuNUno8OjeQQYaYUkLzmIv1ukAAVismMfCUKLcN3ZaqsNPwjfnRrpLA4YWiS4aN9Nk5fCL8QMBe49CwITytrtZkaxtUIn/TC0U8G+KGT4YSmv6XPoai37B48zdqVnard0OqwWItcgv+le9l0ozI=,iv:YU1JgWt/jfRSoZPzvc4+ffsR4sPbcjgbdsh1P+g8lTo=,tag:85SfU3FQUpqW5ALV24rEMw==,type:str]
|
||||
encrypted_regex: ^(data|stringData|email)$
|
||||
version: 3.12.1
|
||||
44
kubernetes/app/lubelogger/secret.sops.yaml
Normal file
44
kubernetes/app/lubelogger/secret.sops.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: lubelogger-credentials
|
||||
namespace: lubelogger
|
||||
stringData:
|
||||
#ENC[AES256_GCM,data:q8YkSYhUjXayq4c/v9q014si6MiQwH//1AD04/j0hxwUyH/Kr2Z+Q1vw9g/qWo/19cxBWPkt1NkY,iv:2kdJLLw4epkN0ZymXumUBpo1U5RSpgDfVftslovvAMk=,tag:upMo0Mk+STLa0XxgQ6dYeQ==,type:comment]
|
||||
DB_USERNAME: ENC[AES256_GCM,data:eogW0ytMfVFp9g==,iv:5SCxLHVSiuWekj2Z9DzoVFNphK8lap4DbGJEtuKlE/g=,tag:DXy9H0dhAaOVIGP0IzmOyQ==,type:str]
|
||||
DB_PASSWORD: ENC[AES256_GCM,data:eokX9Zf/HCBDXPvggJvAdnYMZtpfeGA3KOUP99CGZrbpsuibWSYNBCZRSVppSMU++el71rgxsuNe7GiOLjJkSg==,iv:+/vsYNdqW5OLZe2cQAeG16x39wAdnUD7O3iv3JfY6PA=,tag:M3z9yUcr8njY7n4eJvQKVg==,type:str]
|
||||
DB_DATABASE_NAME: ENC[AES256_GCM,data:rBl/9lzfihT5Cw==,iv:bIAa2b1+AJH8pAmFUEPe8bbDw0aV+wRmgnjTZ4KhbHc=,tag:Zf/KruFw0IGj39A5v0g2sQ==,type:str]
|
||||
#ENC[AES256_GCM,data:chnWZQLNaZdeX0+nNG8OJnVuDktWKFjxs01U1ErzIrpYLILlROOnVxPq6xnkLGz2LSaBbw6HSfU=,iv:xrHMQ78h04edxwRvhgHYUfMWp76UgM0+mQkS4OQszRg=,tag:99pUo39fOHjYFEVYqQkWEQ==,type:comment]
|
||||
POSTGRES_CONNECTION: ENC[AES256_GCM,data:qiXHM0OI/bb24TM4OtcYmRt7UiyZ0phkQ5WJ4io/1sPKD6nPj/g6IbF03V8fAejApzNPkBpGtPTQbF1QhiHLZvRa530lWlcfXvj5nu0ZLhqJ/cGQ1nv1mNoSAE8QpbqxtJ/K3M1fl0M4nvkeH/xEj7VOcOJ0acAFjjmhWNR3qQgkjhwgtfKuMSrj,iv:/cK1H8YOVPOW8hA2NlyD2ihsmsqI7xMejCont0SwNFM=,tag:rjQ89vFDzRuDFB83txRYfw==,type:str]
|
||||
#ENC[AES256_GCM,data:I8lMrioI4WHL3E3kuGIvuaZWk0bF8C4F4Hql1seJrz2EOOfZ8os9RX5GDPVnzUanH+OxXQy2FQ5GaGSS8hz+VF8=,iv:yV5mo7iDFV44ioj7AvNo+Vt0/DdeCOqZJeuykA/RONU=,tag:82+jBpVf/Iz6UD5bNDdPLA==,type:comment]
|
||||
OpenIDConfig__Name: ENC[AES256_GCM,data:EgLPMKKWvtQ=,iv:9oQiLXbv/Z3s+nXfCzIX/wgrptz66vwJiQnvX85sF2g=,tag:9crlLAiGwrWGxuZAAr6fxQ==,type:str]
|
||||
OpenIDConfig__ClientId: ENC[AES256_GCM,data:RX4Upr/Y9VcE8g==,iv:WkjziuLRuAsiNqfqgw00KHflRb7u57LVIQuYlEwvAGc=,tag:rWhjbdSx63d8iiMCgSt2hA==,type:str]
|
||||
OpenIDConfig__ClientSecret: ENC[AES256_GCM,data:J5LSBhRUVQ8ySEpHZgy0FWTyQz14dJUSwT2IXQFnsGjHqQfsxXKRN5bIh4qTCOrMTa+L7vcPUk00wiUqJAsRyHIdUhWqutb5,iv:vLkjOyvvVmqlOi1cbs0QSpAMLWTDaXGXl+Bc7zIkNYU=,tag:Je2cH9kDNzzkSxKNHqOb0Q==,type:str]
|
||||
OpenIDConfig__AuthURL: ENC[AES256_GCM,data:ECZF4cUaiBb9WgDS6bq5azkpWhuRBy4Lbzs5FwpCdpUOzYddlkp3vZN4I8PkDYt4JMZ5XKEs,iv:2P24/H1FhHzimZDYCAHoyxTLyaS4ETuiAICwFwoDqyo=,tag:R63yiGpo5TF+kWxWXMIlPQ==,type:str]
|
||||
OpenIDConfig__TokenURL: ENC[AES256_GCM,data:G03Uow5kKfjDwqG472sm86d7GgpsmZ4jFKTjrfC5SC2EwIMMAm0TxEb26lV3wg==,iv:77R5/h/Z+mipmp88M6P0qd3fdLaRqmNv1K8SzuGoGg0=,tag:fDA/b+/Rb4dZ/oSKlDlAzQ==,type:str]
|
||||
OpenIDConfig__RedirectURL: ENC[AES256_GCM,data:pbOS6LCe65QAP45rnnuJAXiuDwAR/8pzanNJKk5ia4BO2Mk3s/4/6csvPA==,iv:0MCYj9rE1TUxJQ2zN0g2UAbAGK/7O89pkbPEwm9qAI4=,tag:byM6tFlmS8SAZDyLiayJFA==,type:str]
|
||||
OpenIDConfig__Scope: ENC[AES256_GCM,data:JnXTW0PS0a0ShLVg+93MFF4OqPw=,iv:CXKuW9WOx9oPs7yIP07RVgk+fyrkJ6uQmVuxh9chXMg=,tag:MmgWGOFYCR6vF4DGftObUw==,type:str]
|
||||
OpenIDConfig__ValidateState: ENC[AES256_GCM,data:xfeRVQ==,iv:YXeNyG4zqy7/MWBZVBOgu2tPOIaS+sDFsHHCtt0bUcg=,tag:ySDP5mSoQpy7N1lh6klT6Q==,type:str]
|
||||
OpenIDConfig__UsePKCE: ENC[AES256_GCM,data:S3ReXQ==,iv:0ZG4KolJ8lQ7CFelr65ZMGwpFVV8UrewC+om5A6n1M0=,tag:p6ASno+y7XptZEElFD8b9w==,type:str]
|
||||
OpenIDConfig__DisableRegularLogin: ENC[AES256_GCM,data:/fRFow==,iv:Gpy/YT2ucTZYhs5fm8eb2zakZ5LLsRoY027nRuB7X4A=,tag:klios0Pqo13UV21eDsM2LQ==,type:str]
|
||||
OpenIDConfig__UserInfoURL: ENC[AES256_GCM,data:adn2dAYWwQWCBy+hb8MmkHsG8IV1UTJK5pKC7G9gTJao/X16bifniMKgfVX1mTpWhQ==,iv:o9lm6RwiLaZDKJHTUY+lTAyKXg0FPsoizMeuAhFlHSE=,tag:fVGYK8yDAgT8ztEVlq+glg==,type:str]
|
||||
OpenIDConfig__LogOutURL: ENC[AES256_GCM,data:ugvDXxINUuTkLicLcfZ50XyzXBIrCp2HXU+CYMxX0hu+bDA3vyo=,iv:ZWqQ+lPnEV8vjPjZDYy2ws5J4ZumeGAJ5wW1Y+0rk1g=,tag:AiwMUGQppa/M2zCMUcBGCw==,type:str]
|
||||
EnableAuth: ENC[AES256_GCM,data:oocLtw==,iv:peSI/7zKYld+iySbqV4OX2Q4YJbHePv9K7eEmXV78GI=,tag:qdTcHLjVINMxMZHN/C2RbQ==,type:str]
|
||||
EnableRootUserOIDC: ENC[AES256_GCM,data:H/YHUw==,iv:88BYn3MeePmUy+2Z+DctMx4Gx/0AXKPKQDThliSrmcw=,tag:2moLxirbot9HArcLliRb4A==,type:str]
|
||||
DefaultReminderEmail: ENC[AES256_GCM,data:wl2nfvSdSN0v1rM2ZiC4jYR5ba16hAgazQ==,iv:o638Gcgax5Z87xUUxQ+hvLrio8qpg6Ikq7V0pC9iB74=,tag:6ghl4RcMEAevGlRLmngMvQ==,type:str]
|
||||
LUBELOGGER_OPEN_REGISTRATION: ENC[AES256_GCM,data:qpQuKzY=,iv:rTwdoAyu6QXf4qKL2ATuCTO847X0VjKb3Rl1q+O49qc=,tag:XLyMRYW6iEZG3QoFeSgH9w==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFOWI2ZW9OSG9pS0xFdlFt
|
||||
cWVVaVNNeUNrcFR0Qm5jSGFjK2lzNHRabm5rCjgrN2xDZXdmeHdSUTk3cHk5QUlk
|
||||
TDFmUGNydWNwS1B1TjdIeFgzbnZmczAKLS0tIG0wM3hqY2F3UXRiODRUTGdVRGYz
|
||||
ZVpEL0I5WlM1UjRya3F0akdzdzBxVXMKCyXCgwv4SVwKASE/rUrHg17iuNdykk/d
|
||||
rixoJvG3XPXWLcAGLn14hrE0uAs4Oha27eW3psjae7/0UEgcUOvAag==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-03-12T18:01:33Z"
|
||||
mac: ENC[AES256_GCM,data:KpkIviq319M4o9igUXKkBpzCfetySjxsL75HMh7r66C8I9vnxVdKQcMYXGiGtBWdSmYincxY49O0qnxr3oDzSIEgcIq6dE4AGXgWSMaJ837QbbIUG8MhEo6HRAUU2UB+ixiDPGBafu8Fna7b3HMVXSQN6BFr7kSIKWlhv/njyyA=,iv:ERQnyXxkUUm93le2CxBmqXN7MooWV7I26uXSOL2QstU=,tag:xvtBJxwLLpOIBKqhrOlNPw==,type:str]
|
||||
encrypted_regex: ^(data|stringData|email)$
|
||||
version: 3.12.1
|
||||
12
kubernetes/app/lubelogger/service-db.yaml
Normal file
12
kubernetes/app/lubelogger/service-db.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: lubelogger-db
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: lubelogger-db
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger
|
||||
name: lubelogger
|
||||
namespace: lubelogger
|
||||
spec:
|
||||
ports:
|
||||
- name: 8080-8080
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: lubelogger
|
||||
type: ClusterIP
|
||||
|
||||
65
kubernetes/app/lubelogger/statefulset-db.yaml
Normal file
65
kubernetes/app/lubelogger/statefulset-db.yaml
Normal file
@@ -0,0 +1,65 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: lubelogger-db
|
||||
namespace: lubelogger
|
||||
labels:
|
||||
app: lubelogger-db
|
||||
spec:
|
||||
serviceName: lubelogger-db
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: lubelogger-db
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lubelogger-db
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 999
|
||||
runAsGroup: 999
|
||||
fsGroup: 999
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:18
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_USERNAME
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: lubelogger-credentials
|
||||
key: DB_DATABASE_NAME
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
storageClassName: nfs-synology-ssd
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
Reference in New Issue
Block a user