feat(k8s/lubelogger): migrate to Helm + PostgreSQL with OIDC

This commit is contained in:
2026-03-12 19:29:14 +02:00
parent 5d0e50b39b
commit bd155efe9d
17 changed files with 692 additions and 152 deletions

View 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)

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +1,3 @@
---
apiVersion: v1
kind: Namespace
metadata:

View 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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View 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