Files
homelab-manifests/adventurelog-system/adventurelog.yaml
T
2025-12-28 20:42:27 +01:00

483 lines
13 KiB
YAML

---
# AdventureLog System - Travel/Adventure logging application
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: adventurelog-system
---
# PostgreSQL with PostGIS Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: adventurelog-postgres
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
template:
metadata:
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
spec:
securityContext:
fsGroup: 999
containers:
- name: postgres
image: postgis/postgis:16-3.5
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: adventurelog-db
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: adventurelog-db
key: password
- name: POSTGRES_DB
value: adventurelog
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- name: postgres
containerPort: 5432
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
subPath: data
volumes:
- name: data
persistentVolumeClaim:
claimName: adventurelog-postgres
---
# Backend Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: adventurelog-backend
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: backend
app.kubernetes.io/version: latest
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: backend
template:
metadata:
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: backend
app.kubernetes.io/version: latest
spec:
containers:
- name: backend
image: ghcr.io/seanmorley15/adventurelog-backend:latest
imagePullPolicy: Always
env:
# Django settings
- name: DJANGO_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: adventurelog-admin
key: username
- name: DJANGO_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: adventurelog-admin
key: password
- name: DJANGO_ADMIN_EMAIL
valueFrom:
secretKeyRef:
name: adventurelog-admin
key: email
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: adventurelog-admin
key: secret-key
# Public URL - update to your domain
- name: PUBLIC_URL
value: https://adventures.dooplex.hu
- name: CSRF_TRUSTED_ORIGINS
value: https://adventures.dooplex.hu,https://adventures.home
# Disable user registration (set to False to allow)
- name: DISABLE_REGISTRATION
value: "True"
- name: SOCIALACCOUNT_ALLOW_SIGNUPS
value: "True"
# Database
- name: PGHOST
value: adventurelog-postgres
- name: PGPORT
value: "5432"
- name: PGDATABASE
value: adventurelog
- name: PGUSER
valueFrom:
secretKeyRef:
name: adventurelog-db
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: adventurelog-db
key: password
# SMTP Configuration
- name: EMAIL_BACKEND
value: email
- name: EMAIL_HOST
valueFrom:
secretKeyRef:
name: smtp-credentials
key: host
- name: EMAIL_PORT
valueFrom:
secretKeyRef:
name: smtp-credentials
key: port
- name: EMAIL_USE_TLS
value: "True"
- name: EMAIL_USE_SSL
value: "False"
- name: EMAIL_HOST_USER
valueFrom:
secretKeyRef:
name: smtp-credentials
key: username
- name: EMAIL_HOST_PASSWORD
valueFrom:
secretKeyRef:
name: smtp-credentials
key: password
- name: DEFAULT_FROM_EMAIL
valueFrom:
secretKeyRef:
name: smtp-credentials
key: from-address
# Frontend URL (for CORS)
- name: FRONTEND_URL
value: https://adventures.dooplex.hu
# Optional: Google Maps API (commented out - uses OpenStreetMap by default)
# Requires billing enabled on Google Cloud, but has free tier for personal use
# - name: GOOGLE_MAPS_API_KEY
# valueFrom:
# secretKeyRef:
# name: adventurelog-google
# key: api-key
ports:
- name: http
containerPort: 80
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
livenessProbe:
httpGet:
path: /api/
port: http
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
readinessProbe:
httpGet:
path: /api/
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- name: media
mountPath: /code/media
volumes:
- name: media
hostPath:
path: /mnt/4_hdd/data/adventurelog
type: DirectoryOrCreate
---
# Frontend Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: adventurelog-frontend
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: frontend
app.kubernetes.io/version: latest
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: frontend
template:
metadata:
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: frontend
app.kubernetes.io/version: latest
spec:
containers:
- name: frontend
image: ghcr.io/seanmorley15/adventurelog-frontend:latest
imagePullPolicy: Always
env:
# Public-facing URL
- name: PUBLIC_SERVER_URL
value: http://adventurelog-backend
- name: ORIGIN
value: https://adventures.dooplex.hu
- name: BODY_SIZE_LIMIT
value: "Infinity"
ports:
- name: http
containerPort: 3000
protocol: TCP
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
---
# PostgreSQL Service
apiVersion: v1
kind: Service
metadata:
name: adventurelog-postgres
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
spec:
type: ClusterIP
ports:
- name: postgres
port: 5432
targetPort: postgres
protocol: TCP
selector:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
---
# Backend Service
apiVersion: v1
kind: Service
metadata:
name: adventurelog-backend
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: backend
app.kubernetes.io/version: latest
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
selector:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: backend
---
# Frontend Service
apiVersion: v1
kind: Service
metadata:
name: adventurelog-frontend
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: frontend
app.kubernetes.io/version: latest
spec:
type: ClusterIP
ports:
- name: http
port: 3000
targetPort: http
protocol: TCP
selector:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: frontend
---
# Main Ingress (Frontend + Backend)
# NOTE: /api routes through frontend (SvelteKit handles proxying to backend)
# This avoids Django APPEND_SLASH issues with direct ingress routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adventurelog
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: adventurelog
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: adventures.dooplex.hu,adventures.home
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- adventures.dooplex.hu
secretName: adventurelog-tls
rules:
- host: adventures.dooplex.hu
http:
paths:
# Django admin panel (direct to backend)
- path: /admin
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
- path: /accounts
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
# Media files (user uploads)
- path: /media
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
# Static files (Django static assets)
- path: /static
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
# Frontend handles everything else including /api proxying
- path: /
pathType: Prefix
backend:
service:
name: adventurelog-frontend
port:
number: 3000
- host: adventures.home
http:
paths:
- path: /admin
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
- path: /accounts
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
- path: /media
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
- path: /static
pathType: Prefix
backend:
service:
name: adventurelog-backend
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: adventurelog-frontend
port:
number: 3000
---
# PostgreSQL PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: adventurelog-postgres
namespace: adventurelog-system
labels:
app.kubernetes.io/instance: adventurelog
app.kubernetes.io/name: postgres
recurring-job-group.longhorn.io/needbackup: enabled
recurring-job.longhorn.io/source: enabled
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 5Gi
---