--- # 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" # 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/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 # 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: /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 ---