feat(k8s/reitti): deploy Reitti with PostGIS, Authelia OIDC, and restic backups
This commit is contained in:
@@ -62,6 +62,7 @@ homelab-v2/
|
|||||||
| **Archmirror** | Local Arch Linux package repository mirror |
|
| **Archmirror** | Local Arch Linux package repository mirror |
|
||||||
| **Blog** | Personal static blog served via git-sync + nginx (gh-pages branch) |
|
| **Blog** | Personal static blog served via git-sync + nginx (gh-pages branch) |
|
||||||
| **Vikunja** | To-do list and task management, SSO via Authelia OIDC |
|
| **Vikunja** | To-do list and task management, SSO via Authelia OIDC |
|
||||||
|
| **Reitti** | Personal location history and timeline (PostGIS), SSO via Authelia OIDC |
|
||||||
|
|
||||||
## Infrastructure Stack
|
## Infrastructure Stack
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ data:
|
|||||||
icon: vikunja.png
|
icon: vikunja.png
|
||||||
href: https://${VIKUNJA_HOST}/
|
href: https://${VIKUNJA_HOST}/
|
||||||
description: Task management
|
description: Task management
|
||||||
|
- Reitti:
|
||||||
|
icon: mdi-map-marker-path
|
||||||
|
href: https://${REITTI_HOST}/
|
||||||
|
description: Location history
|
||||||
|
|
||||||
widgets.yaml: |
|
widgets.yaml: |
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: reitti-db-backup
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti-backup
|
||||||
|
spec:
|
||||||
|
schedule: "30 2 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti-backup
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
initContainers:
|
||||||
|
- name: pg-dump
|
||||||
|
image: postgis/postgis:17-3.5
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: PGHOST
|
||||||
|
value: reitti-db
|
||||||
|
- name: PGUSER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_USERNAME
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_PASSWORD
|
||||||
|
- name: PGDATABASE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_DATABASE_NAME
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- pg_dump --clean --if-exists > /backup/dump.sql
|
||||||
|
volumeMounts:
|
||||||
|
- name: backup-tmp
|
||||||
|
mountPath: /backup
|
||||||
|
containers:
|
||||||
|
- name: resticprofile
|
||||||
|
image: creativeprojects/resticprofile:0.32.0
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
resticprofile -c /secrets/profiles.yaml -n reitti-db backup
|
||||||
|
resticprofile -c /secrets/profiles.yaml -n reitti-db copy
|
||||||
|
env:
|
||||||
|
- name: B2_ACCOUNT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-backup-config
|
||||||
|
key: B2_ACCOUNT_ID
|
||||||
|
- name: B2_ACCOUNT_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-backup-config
|
||||||
|
key: B2_ACCOUNT_KEY
|
||||||
|
volumeMounts:
|
||||||
|
- name: secrets
|
||||||
|
mountPath: /secrets
|
||||||
|
readOnly: true
|
||||||
|
- name: backup-tmp
|
||||||
|
mountPath: /backup
|
||||||
|
volumes:
|
||||||
|
- name: secrets
|
||||||
|
secret:
|
||||||
|
secretName: reitti-backup-config
|
||||||
|
- name: backup-tmp
|
||||||
|
emptyDir: {}
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: reitti-files-backup
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti-backup
|
||||||
|
spec:
|
||||||
|
schedule: "30 3 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti-backup
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: resticprofile
|
||||||
|
image: creativeprojects/resticprofile:0.32.0
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
resticprofile -c /secrets/profiles.yaml -n reitti-files backup
|
||||||
|
resticprofile -c /secrets/profiles.yaml -n reitti-files copy
|
||||||
|
env:
|
||||||
|
- name: B2_ACCOUNT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-backup-config
|
||||||
|
key: B2_ACCOUNT_ID
|
||||||
|
- name: B2_ACCOUNT_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-backup-config
|
||||||
|
key: B2_ACCOUNT_KEY
|
||||||
|
volumeMounts:
|
||||||
|
- name: secrets
|
||||||
|
mountPath: /secrets
|
||||||
|
readOnly: true
|
||||||
|
- name: files
|
||||||
|
mountPath: /files
|
||||||
|
readOnly: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi
|
||||||
|
volumes:
|
||||||
|
- name: secrets
|
||||||
|
secret:
|
||||||
|
secretName: reitti-backup-config
|
||||||
|
- name: files
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: reitti-data
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: reitti-redis
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti-redis
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti-redis
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 999 # redis user in the alpine image
|
||||||
|
runAsGroup: 999
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: redis:7.4.11-alpine
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
# Cache only — no persistence, so no PVC.
|
||||||
|
args: ["--save", "", "--appendonly", "no"]
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
name: redis
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 6379
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 6379
|
||||||
|
periodSeconds: 10
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: reitti-tile-cache
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti-tile-cache
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-tile-cache
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti-tile-cache
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
# nginx image starts as root (renders nginx.conf, binds :80) then drops workers to nginx
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: tile-cache
|
||||||
|
image: dedicatedcode/reitti-tile-cache:5.6.1
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: cache
|
||||||
|
mountPath: /var/cache/nginx
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: 80
|
||||||
|
path: /health
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: 80
|
||||||
|
path: /health
|
||||||
|
periodSeconds: 10
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi # keys_zone shared memory: 512m tiles + 128m panoramax
|
||||||
|
volumes:
|
||||||
|
- name: cache
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: reitti-tile-cache
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: reitti
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
# The image starts as root only to remap UID/GID and chown /data, then drops to
|
||||||
|
# reitti (1000). Running as 1000 directly skips that; the NFS subdir provisioner
|
||||||
|
# creates directories 0777, so /data is writable without a chown.
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- name: reitti
|
||||||
|
image: dedicatedcode/reitti:5.6.1
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: ADVERTISE_URI
|
||||||
|
value: https://${REITTI_HOST}
|
||||||
|
- name: JAVA_OPTS
|
||||||
|
value: -XX:MaxRAMPercentage=75
|
||||||
|
- name: POSTGIS_HOST
|
||||||
|
value: reitti-db
|
||||||
|
- name: POSTGIS_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_USERNAME
|
||||||
|
- name: POSTGIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_PASSWORD
|
||||||
|
- name: POSTGIS_DB
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_DATABASE_NAME
|
||||||
|
- name: REDIS_HOST
|
||||||
|
value: reitti-redis
|
||||||
|
# Tiles are proxied server-side through /api/v1/tiles, so the in-cluster URL works.
|
||||||
|
- name: TILES_CACHE
|
||||||
|
value: http://reitti-tile-cache
|
||||||
|
# Authentication against Authelia over OIDC (redirect URI /login/oauth2/code/oauth).
|
||||||
|
# Sign-up is off: an OIDC login links to the local user whose username matches
|
||||||
|
# preferred_username, so rename the setup admin to match before the first SSO login.
|
||||||
|
# Local login stays on until that link exists — then set DISABLE_LOCAL_LOGIN=true.
|
||||||
|
- name: OIDC_ENABLED
|
||||||
|
value: "true"
|
||||||
|
- name: OIDC_ISSUER_URI
|
||||||
|
value: https://auth.${AUTHELIA_DOMAIN}
|
||||||
|
- name: OIDC_CLIENT_ID
|
||||||
|
value: reitti
|
||||||
|
- name: OIDC_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: OIDC_CLIENT_SECRET
|
||||||
|
- name: OIDC_SCOPE
|
||||||
|
value: openid,profile,email
|
||||||
|
- name: OIDC_AUTHENTICATION_METHOD
|
||||||
|
value: client_secret_basic
|
||||||
|
- name: OIDC_SIGN_UP_ENABLED
|
||||||
|
value: "false"
|
||||||
|
- name: DISABLE_LOCAL_LOGIN
|
||||||
|
value: "false"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
port: 8080
|
||||||
|
path: /actuator/health
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 30 # DB migrations on first start / upgrades
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: 8080
|
||||||
|
path: /actuator/health
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: 8080
|
||||||
|
path: /actuator/health
|
||||||
|
periodSeconds: 10
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
memory: 1536Mi
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: reitti-data
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: reitti
|
||||||
|
namespace: reitti
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt
|
||||||
|
# No Authelia forward-auth middleware — Reitti authenticates against Authelia
|
||||||
|
# natively over OIDC. A middleware here would break the OIDC callback, the
|
||||||
|
# token-authenticated /api ingest endpoints (OwnTracks, GPSLogger, Overland)
|
||||||
|
# and magic share links.
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- ${REITTI_HOST}
|
||||||
|
secretName: reitti-tls
|
||||||
|
rules:
|
||||||
|
- host: ${REITTI_HOST}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: reitti
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: reitti
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: default-deny-ingress
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector: {}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-ingress-controller
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: traefik
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-app-to-db
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-db
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-backup-to-db
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-db
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-backup
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-backup-egress
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-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: reitti-db
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-app-to-redis
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-redis
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-app-to-tile-cache
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-tile-cache
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: reitti-data
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: nfs-synology-ssd
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
---
|
||||||
|
# Map tile cache — recreatable, not backed up. nginx caps it at 2g tiles + 1g Panoramax.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: reitti-tile-cache
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: nfs-synology-ssd
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"kubernetes": {
|
||||||
|
"fileMatch": ["kubernetes/app/reitti/.+\\.yaml$"]
|
||||||
|
},
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchFileNames": ["kubernetes/app/reitti/**"],
|
||||||
|
"semanticCommitScope": "k8s/reitti"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchFileNames": ["kubernetes/app/reitti/**"],
|
||||||
|
"matchPackageNames": ["dedicatedcode/reitti", "dedicatedcode/reitti-tile-cache"],
|
||||||
|
"matchUpdateTypes": ["patch", "minor"],
|
||||||
|
"automerge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchFileNames": ["kubernetes/app/reitti/**"],
|
||||||
|
"matchPackageNames": ["dedicatedcode/reitti", "dedicatedcode/reitti-tile-cache"],
|
||||||
|
"matchUpdateTypes": ["major"],
|
||||||
|
"automerge": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Ignore infrastructure images",
|
||||||
|
"matchFileNames": ["kubernetes/app/reitti/**"],
|
||||||
|
"matchPackageNames": ["postgis/postgis", "redis", "creativeprojects/resticprofile"],
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: reitti-backup-config
|
||||||
|
namespace: reitti
|
||||||
|
stringData:
|
||||||
|
profiles.yaml: ENC[AES256_GCM,data:aVuPPechcaGmXT0g6OTnISgGR2ZdBJvqrf6mpDJyIERXZiQC8aVq1RtkUeyVMs7Hed8OwuRfuo5xlG5206Bg8ynbBFEWsl+sbWRWOa9g+qSnO84Fhej+fbHITzC2BPk1q85CWJUpVcdHq1vgyKYluJpuYpS3HzrinsjTFpiziC7ft/lFjzebdlkFZgvq6cPFzYqP/8f54GOkYaR/cNr6ux6QLsbA3rfPOAfsMiaZFt3JfbTRNfqcM4eZw04N3bf4CVpyPjR69HZvlzHw0Gje+GX3vdez8bByUxo40aB9Aisvr/HeTM8L5njQDefN/zH1VGTSV2LfNk81soSowtxJ3RZ2hZYnx4dz0XUggvGqR5dhlGvT3pDK0v9lkRM1ahZw1x5q2zd3K7IcQLwYSckRdwC0j9vc8TUkHhyg+9x5TRrGy9hA4rCJtsGzTU/Sc4dcobueFXBGrIg9raTDknEo1D4Vq7H74Ce9RnemYlb1KJsjrtyqrpKkzIAChL1b6xhgOzg5YJ2UH6+laEsbC891OZp2PEdQY1lA8n36HXflsZnIQY8SOhToR6FoH3qzOB79a2I5jmJHI9O7S0L6NO2+fFDRgMbUNeIa9yJacN297Qui3paGQTcsGvSGQ7eAEH06VZXU/DX7TU0XiLfejIohm78QSmO7ZcTBxlQ1OTHc1Kiny1e0SomY7kxs1OL4SSBJirmymojuxogOGWblxt2AOz37eCFgp8L3sRPSHWGM982na6Ko7zUw1/bhukGoN445DsiuV59ilXSA0W5ci/PfrqzFOqZWKKDZfE89nCf+2P1thS3DmOpJnlG8tq5rde9QAqT0mgcvxo5Re+Bf/Ehavo0t79Gy35c6EEwPK8lEFXlSib84mfRiMnKBV60cQ4HS3xy78xLKPvjBpM4s8vbnMY4GJxCNAzOivhAfHAU3vTp/ZP8B0LJp7bNk7tre/gR+Q1DuqhwyCjo8sUZi4Cua3ILiKvcvU8ZXvjz+LfIymDocIxeFtRGHA2KceURa25v0hWrEI0Qzaz1m5XeYg76HhjcCU5WqT8CuFZNDlf+35uyKxhOZqr7kT2J/nZ/VYF2+sz9oBmeH/VW3OdgIc203e8wQIPBTd8OYpkabnwxDMlyiaG8MySZORS7kyD88Sy8bFJUN9IO7svav0WxZhJn4atAc2iqH81Y1s4WE1i87UqUDtwd5nOKXUFf8Fr6jXpB8G95hJCzgLFtrmX/6eg==,iv:Kp9nml6af8RmrVIIvAv8m647mMm5oe02T9TqkyIVY+U=,tag:WYbdlHbstN6XhcIP53VpqQ==,type:str]
|
||||||
|
restic-password-nas: ENC[AES256_GCM,data:FSRmDhSQHfHXomxPhefQ3WJNPVzSCNw/ML/mCiloViEkpVj92vcQbA==,iv:ijS0gKwp4dc/Oq346a/KLFnDBkPfhPzr4IUHbziGPxs=,tag:gE2wAuk+zWUJHgPlYQvwjw==,type:str]
|
||||||
|
restic-password-b2: ENC[AES256_GCM,data:4f0xRAKnWLsOFvu0GVu2FK7w8QS/w21AkCjSho7C1q8CV4aJSovvVA==,iv:WOru20OWYoN9jtW2iUdXpfuLd2SWiBXQ6Ncp5FUsRcE=,tag:vYa+obqI7gBHk9wY+tkIwg==,type:str]
|
||||||
|
B2_ACCOUNT_ID: ENC[AES256_GCM,data:52us2nMzoQ7p+I/+9+mJa+DK+MT8CdBDsg==,iv:E/ifDPwDyRJXOZBTPPwpLwCZzQ0n9IN+cdO/3O3u2e4=,tag:dFH0C7bZi4EcevoMJamzuQ==,type:str]
|
||||||
|
B2_ACCOUNT_KEY: ENC[AES256_GCM,data:jYDWYUj42GEtubZ5+RmYc+FT2FbJwg1PrzgtCb8I7Q==,iv:ZVvWw2aBv0iPAFzCn3L3MC3pwR/ru4zTDx0KsTiSQD8=,tag:PXLsKsT9ccSrZwUUONWnpQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCMDliMG1iNTVrNUZ2a0li
|
||||||
|
Tkc2WXFLbGhlbFYwdkovcjNZYXJBa0V1MFc0CnVEaEc1bzBCK0czSHh4dGE5Ky9Y
|
||||||
|
NjFWWGlScGdpODU3KzNmQzUzS3FkeVEKLS0tIDRXbHpST0RySVB1UEVRbWVYYytV
|
||||||
|
SzV4Q01MaGJGNmxqMm50OWh3S1RCbkEKaKPeVOU9Gvg+7RImg0BSLyl8DUNzCJDm
|
||||||
|
9gQd9z8IwciZE4St53kYSbQNCKMjz4yUc4mrbW04IXs5cTbnCLBspA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||||
|
encrypted_regex: ^(data|stringData|email)$
|
||||||
|
lastmodified: "2026-10-03T20:31:00Z"
|
||||||
|
mac: ENC[AES256_GCM,data:Jg964qmIW9hSp4N+4stwmE24qi4sNQfUA0YM5rH1QHWbeZS1gAXszgQQPPrOw+hStgNWZbsgiMJVIvF3v13qgMh6ZVSAFMmf3fWJ+tN6Dhrj79Qx+klaI8qXpXQsLvHX0gJFYBAyPvtBPoDRnHK8X/twAKm03QtCLCMHv3LnQ6Y=,iv:2De8vyYSIMKTWUXB0k5VAojeTFXuCwiuduXeGcCMHmA=,tag:eZzK4MPeCJItfYbbwQXJZQ==,type:str]
|
||||||
|
version: 3.13.3
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: reitti-credentials
|
||||||
|
namespace: reitti
|
||||||
|
stringData:
|
||||||
|
DB_USERNAME: ENC[AES256_GCM,data:s5+3cPVq,iv:xgQHj/ORXzDDsOoZZruGQrGTU+y+BRwkWC7Tk3CSAuI=,tag:6p6OdIL4CR0UDiiKOVsttA==,type:str]
|
||||||
|
DB_PASSWORD: ENC[AES256_GCM,data:GoWO3wMx2R7BAgkfb/GAk6vd7wIrbL8uqaCWf2TMwpgCr8yCY0mifw==,iv:KTkH59Woh/QBkx5lHWv/iV9LqrA1Q1NcpwtDkUKJAaY=,tag:HpHvG8kW2+RTDS0L1DjJQQ==,type:str]
|
||||||
|
DB_DATABASE_NAME: ENC[AES256_GCM,data:/Xrjy1quYwI=,iv:whj1qsDAKMqCeW8Ge+M0cZEjiSpYZizlXfBy3bhIbbg=,tag:8WrJv7bgFbbxIrz3uCZumA==,type:str]
|
||||||
|
OIDC_CLIENT_SECRET: ENC[AES256_GCM,data:WHk4EOUrYj7PnJiahEAy6yL7X155bj3s4wn7nzbeS8YHR5OOCIHa1b/atf1S7bktStkllIOg+EhmzGoHYFUgNg==,iv:zCsaEmx+9kvXGw8Lda+Qi7kIRl1kU7nWk9flFJzeZyA=,tag:eGD1noK0YBjVsIn23vnixQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBseDh0cGhIZkU0WHNJdThj
|
||||||
|
K1dWS29TSUhPWEFxdi9EOG1aZmlKcVJTTWxVCkM3RWtTOWl5Y0psU3BDNmFQSnFT
|
||||||
|
aGlURkFzOVVNd3FWclBYbEpIRXJ1QjQKLS0tIHQrRS9hRVVIYVBIazJFNGxhNWJm
|
||||||
|
dFFocWFxVkJIOVc5aUppQ2p3R2pNU28Kj2q+bIxGc14s8qs3Uc0/Dc9tymLMsT2o
|
||||||
|
x7dDpozVupQY/Pqo4RqWp6/OIOjVSTtqKV8A99KTyp9HBd2m9xjyWA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||||
|
encrypted_regex: ^(data|stringData|email)$
|
||||||
|
lastmodified: "2026-10-03T20:19:54Z"
|
||||||
|
mac: ENC[AES256_GCM,data:lE6AHBDRhNiTXlQMNLIMqBEDpYWfYg8TI6Mpd2as4Q+O7WckTuDkrOrULA063OgjJzohld5x3yExnR2weDMaiz2jXn0kDoXYrYxIYL4J4Ht98t8yndhtDMzSaVyJVyfRN3JRxfpJfVBTcD/mrpvo5fmQRJv0k/l0F4/lZY/UYSk=,iv:WUQv2PyrHt3tdUKsyhzggQ/kYosXebehmeNDqZQ4Lac=,tag:ooVml9rbNwtYaZGYPFv30w==,type:str]
|
||||||
|
version: 3.13.3
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: reitti-db
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app: reitti-db
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
|
targetPort: 5432
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: reitti
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: reitti
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
name: http
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: reitti-redis
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: reitti-redis
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
name: redis
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: reitti-tile-cache
|
||||||
|
namespace: reitti
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: reitti-tile-cache
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
name: http
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: reitti-db
|
||||||
|
namespace: reitti
|
||||||
|
labels:
|
||||||
|
app: reitti-db
|
||||||
|
spec:
|
||||||
|
serviceName: reitti-db
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: reitti-db
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: reitti-db
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsGroup: 999
|
||||||
|
fsGroup: 999
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
# Reitti requires PostGIS; the Debian variant keeps the postgres user at UID 999
|
||||||
|
# (the alpine variant uses 70). The image creates the postgis extension in POSTGRES_DB.
|
||||||
|
image: postgis/postgis:17-3.5
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_USERNAME
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_PASSWORD
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: reitti-credentials
|
||||||
|
key: DB_DATABASE_NAME
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
startupProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 5432
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 30
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 5432
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 5
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 5432
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: nfs-synology-ssd
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
@@ -38,6 +38,7 @@ stringData:
|
|||||||
BLOG_HOST: ENC[AES256_GCM,data:eADRFTla/PPFLVCoP9uKvPZ1YhY=,iv://xbCGLkZ6guGMDU0MnVtGR0adgMqNbe0zrCerj7w8k=,tag:HHXvN6y3YvJ4U4TkENkYVA==,type:str]
|
BLOG_HOST: ENC[AES256_GCM,data:eADRFTla/PPFLVCoP9uKvPZ1YhY=,iv://xbCGLkZ6guGMDU0MnVtGR0adgMqNbe0zrCerj7w8k=,tag:HHXvN6y3YvJ4U4TkENkYVA==,type:str]
|
||||||
VIKUNJA_HOST: ENC[AES256_GCM,data:1VVkvVrdx02jPxHsQoQI9zJKN9v/9mE=,iv:ZagDcljNclEGvmMzS6pJWTv+FMa/a/X6POaWb+kHJuo=,tag:RuaUoX8O4LrEs491Sp4UyQ==,type:str]
|
VIKUNJA_HOST: ENC[AES256_GCM,data:1VVkvVrdx02jPxHsQoQI9zJKN9v/9mE=,iv:ZagDcljNclEGvmMzS6pJWTv+FMa/a/X6POaWb+kHJuo=,tag:RuaUoX8O4LrEs491Sp4UyQ==,type:str]
|
||||||
BACKUP_LOCAL_HOST: ENC[AES256_GCM,data:ABaTI3NKkhF7K2FpPwvvrHA0l/tCxAi4Qek=,iv:34ixxSpKU1c12uoMdk4nz2Vo/+5A/npB7NWMsWFytIM=,tag:qjw2fQBebCKnqCnAPiBHaw==,type:str]
|
BACKUP_LOCAL_HOST: ENC[AES256_GCM,data:ABaTI3NKkhF7K2FpPwvvrHA0l/tCxAi4Qek=,iv:34ixxSpKU1c12uoMdk4nz2Vo/+5A/npB7NWMsWFytIM=,tag:qjw2fQBebCKnqCnAPiBHaw==,type:str]
|
||||||
|
REITTI_HOST: ENC[AES256_GCM,data:Zx0T6aUL/v6ogX1miRxzDmDQ31EImg==,iv:0LBRaaG1FHBXFWrtDX8Z6Cs75BEA7hNYm5FFrBHhyYk=,tag:Tup6HoL6E+L9GJKmv3x17Q==,type:str]
|
||||||
sops:
|
sops:
|
||||||
age:
|
age:
|
||||||
- enc: |
|
- enc: |
|
||||||
@@ -50,6 +51,6 @@ sops:
|
|||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
|
||||||
encrypted_regex: ^(data|stringData|email)$
|
encrypted_regex: ^(data|stringData|email)$
|
||||||
lastmodified: "2026-09-07T11:47:37Z"
|
lastmodified: "2026-10-03T20:20:00Z"
|
||||||
mac: ENC[AES256_GCM,data:4ocnThiPrXCqKTKKgwaincewzI99O7cl9CGnJHrwLRFm8vA2G6MA8yGvywoKjmln8mEfPTTcMMZY8Nd7wFKHz9i4m+CHvzC7kPhTVIDW2HrkFoN7RgywPcgnP+mrco4wOd/huBLdv9+v/j4Iz5lXBMZgbVVkNdWV4xZ4Zx3gtyM=,iv:bfK9KN4E5nZYm6CwaFm3sxG62nDnNiuP5xsIreRHkAc=,tag:wi9r3EcJOHX0azzNVpGw0Q==,type:str]
|
mac: ENC[AES256_GCM,data:xN+k2RvU+IJyYzLRIExm0qM5F/K4s19jm0Sp1fo4L3V2dZHSb1J/JtdtxpbalA3qGxy82qDosagrhrNtdsL2/Ht7JO5f1T3Q1Z5smOBOkvWrjPqnyOWGGwe4j77UY41k50kXNh1VFbhjBYkEei+8191BlMkEmTNSdBvFdvzydIw=,iv:1Q3otFunhnMgrJI8z4XFsp92PHmogEvYi99qAkgJomo=,tag:ikTXnDjTG9fNFrumBGW5Lw==,type:str]
|
||||||
version: 3.13.3
|
version: 3.13.3
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+2
-1
@@ -12,7 +12,8 @@
|
|||||||
"local>oleksandr/homelab//kubernetes/app/paperless/renovate.json",
|
"local>oleksandr/homelab//kubernetes/app/paperless/renovate.json",
|
||||||
"local>oleksandr/homelab//kubernetes/app/lubelogger/renovate.json",
|
"local>oleksandr/homelab//kubernetes/app/lubelogger/renovate.json",
|
||||||
"local>oleksandr/homelab//kubernetes/app/firefly/renovate.json",
|
"local>oleksandr/homelab//kubernetes/app/firefly/renovate.json",
|
||||||
"local>oleksandr/homelab//kubernetes/app/podsync/renovate.json"
|
"local>oleksandr/homelab//kubernetes/app/podsync/renovate.json",
|
||||||
|
"local>oleksandr/homelab//kubernetes/app/reitti/renovate.json"
|
||||||
],
|
],
|
||||||
"enabledManagers": ["kubernetes", "custom.regex"],
|
"enabledManagers": ["kubernetes", "custom.regex"],
|
||||||
"automergeType": "branch",
|
"automergeType": "branch",
|
||||||
|
|||||||
Reference in New Issue
Block a user