diff --git a/argocd-apps/homelab.yaml b/argocd-apps/homelab.yaml index ccdbadf..8ba4b7f 100644 --- a/argocd-apps/homelab.yaml +++ b/argocd-apps/homelab.yaml @@ -789,4 +789,26 @@ spec: syncOptions: - CreateNamespace=true - PruneLast=true +--- +# Workout (wger) +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: workout + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: homelab + source: + repoURL: https://gitea.dooplex.hu/admin/homelab-manifests.git + targetRevision: main + path: workout-system + destination: + server: https://kubernetes.default.svc + namespace: workout-system + syncPolicy: + syncOptions: + - CreateNamespace=true + - PruneLast=true --- \ No newline at end of file diff --git a/workout-system/workout.yaml b/workout-system/workout.yaml new file mode 100644 index 0000000..024c0a8 --- /dev/null +++ b/workout-system/workout.yaml @@ -0,0 +1,447 @@ +# wger - Workout Manager +# https://github.com/wger-project/wger +# Version: 2.3 +# Domain: workout.dooplex.hu +# Auth: Authentik Forward Auth (Proxy) with Remote-User header +# +# wger supports authentication via headers (X-Remote-User) +# when WGER_USE_PROXY_AUTH is enabled +# +# Authentik Setup: +# 1. Create Proxy Provider: +# - Name: wger +# - External Host: https://workout.dooplex.hu +# - Mode: Forward auth (single application) +# 2. Configure to send X-Remote-User header +# 3. Create Application linked to this provider +# 4. Create Outpost (or add to existing) with this provider +--- +apiVersion: v1 +kind: Namespace +metadata: + name: workout-system + labels: + app.kubernetes.io/name: wger +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wger-redis + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-redis +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-redis + template: + metadata: + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-redis + spec: + containers: + - name: redis + image: redis:7.2-alpine + ports: + - containerPort: 6379 + name: redis + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wger + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger + app.kubernetes.io/version: "2.3" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger + app.kubernetes.io/version: "2.3" + spec: + containers: + - name: wger + image: wger/server:2.3 + env: + # Django settings + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: secret-key + - name: SIGNING_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: signing-key + - name: DJANGO_DEBUG + value: "False" + - name: WGER_INSTANCE + value: "https://workout.dooplex.hu" + - name: TIME_ZONE + value: "Europe/Budapest" + - name: DJANGO_SETTINGS_MODULE + value: "config.settings.production" + # Database + - name: DJANGO_DB_ENGINE + value: "django.db.backends.postgresql" + - name: DJANGO_DB_HOST + value: "postgresql-rw.database-system.svc.cluster.local" + - name: DJANGO_DB_PORT + value: "5432" + - name: DJANGO_DB_DATABASE + value: "wger" + - name: DJANGO_DB_USER + valueFrom: + secretKeyRef: + name: wger-db + key: username + - name: DJANGO_DB_PASSWORD + valueFrom: + secretKeyRef: + name: wger-db + key: password + # Cache + - name: DJANGO_CACHE_BACKEND + value: "django.core.cache.backends.redis.RedisCache" + - name: DJANGO_CACHE_LOCATION + value: "redis://wger-redis:6379/1" + # Celery + - name: CELERY_BROKER + value: "redis://wger-redis:6379/2" + - name: CELERY_BACKEND + value: "redis://wger-redis:6379/2" + # Proxy Authentication (for Authentik forward auth) + - name: WGER_USE_PROXY_AUTH + value: "True" + - name: WGER_PROXY_AUTH_HEADER + value: "HTTP_X_AUTHENTIK_USERNAME" + # Email (disabled - no email sending) + - name: ENABLE_EMAIL + value: "False" + # Media settings + - name: DJANGO_MEDIA_ROOT + value: "/home/wger/media" + - name: DJANGO_STATIC_ROOT + value: "/home/wger/static" + # Features + - name: ALLOW_REGISTRATION + value: "False" + - name: ALLOW_GUEST_USERS + value: "False" + - name: ALLOW_UPLOAD_VIDEOS + value: "True" + - name: USE_RECAPTCHA + value: "False" + - name: DOWNLOAD_EXERCISE_IMAGES_ON_STARTUP + value: "True" + ports: + - containerPort: 8000 + name: http + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1000m + memory: 1Gi + volumeMounts: + - name: media + mountPath: /home/wger/media + - name: static + mountPath: /home/wger/static + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 120 + periodSeconds: 30 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 60 + periodSeconds: 10 + volumes: + - name: media + persistentVolumeClaim: + claimName: wger-media + - name: static + persistentVolumeClaim: + claimName: wger-static +--- +# Celery worker for background tasks +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wger-celery-worker + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-worker +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-worker + template: + metadata: + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-worker + spec: + containers: + - name: celery-worker + image: wger/server:2.3 + command: ["/start-worker"] + env: + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: secret-key + - name: SIGNING_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: signing-key + - name: DJANGO_DB_ENGINE + value: "django.db.backends.postgresql" + - name: DJANGO_DB_HOST + value: "postgresql-rw.database-system.svc.cluster.local" + - name: DJANGO_DB_PORT + value: "5432" + - name: DJANGO_DB_DATABASE + value: "wger" + - name: DJANGO_DB_USER + valueFrom: + secretKeyRef: + name: wger-db + key: username + - name: DJANGO_DB_PASSWORD + valueFrom: + secretKeyRef: + name: wger-db + key: password + - name: CELERY_BROKER + value: "redis://wger-redis:6379/2" + - name: CELERY_BACKEND + value: "redis://wger-redis:6379/2" + - name: DJANGO_CACHE_BACKEND + value: "django.core.cache.backends.redis.RedisCache" + - name: DJANGO_CACHE_LOCATION + value: "redis://wger-redis:6379/1" + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi +--- +# Celery beat for scheduled tasks +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wger-celery-beat + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-beat +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-beat + template: + metadata: + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-celery-beat + spec: + containers: + - name: celery-beat + image: wger/server:2.3 + command: ["/start-beat"] + env: + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: secret-key + - name: SIGNING_KEY + valueFrom: + secretKeyRef: + name: wger-app + key: signing-key + - name: DJANGO_DB_ENGINE + value: "django.db.backends.postgresql" + - name: DJANGO_DB_HOST + value: "postgresql-rw.database-system.svc.cluster.local" + - name: DJANGO_DB_PORT + value: "5432" + - name: DJANGO_DB_DATABASE + value: "wger" + - name: DJANGO_DB_USER + valueFrom: + secretKeyRef: + name: wger-db + key: username + - name: DJANGO_DB_PASSWORD + valueFrom: + secretKeyRef: + name: wger-db + key: password + - name: CELERY_BROKER + value: "redis://wger-redis:6379/2" + - name: CELERY_BACKEND + value: "redis://wger-redis:6379/2" + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: wger-redis + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-redis +spec: + type: ClusterIP + ports: + - name: redis + port: 6379 + targetPort: redis + selector: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-redis +--- +apiVersion: v1 +kind: Service +metadata: + name: wger + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger +spec: + type: ClusterIP + ports: + - name: http + port: 8000 + targetPort: http + selector: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger +--- +# Ingress with Authentik forward auth +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: wger + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + external-dns.alpha.kubernetes.io/hostname: workout.dooplex.hu,workout.home + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "100m" + # Authentik forward auth + nginx.ingress.kubernetes.io/auth-url: http://ak-outpost-workout-outpost.auth-system.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx + nginx.ingress.kubernetes.io/auth-signin: https://workout.dooplex.hu/outpost.goauthentik.io/start?rd=$escaped_request_uri + nginx.ingress.kubernetes.io/auth-snippet: | + proxy_set_header X-Forwarded-Host $http_host; + nginx.ingress.kubernetes.io/auth-response-headers: X-authentik-username,X-authentik-groups,X-authentik-email +spec: + ingressClassName: nginx-internal + rules: + - host: workout.dooplex.hu + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: wger + port: + number: 8000 + - host: workout.home + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: wger + port: + number: 8000 + tls: + - hosts: + - workout.dooplex.hu + secretName: wger-tls +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: wger-media + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-media + recurring-job-group.longhorn.io/needbackup: enabled + recurring-job.longhorn.io/source: enabled +spec: + accessModes: + - ReadWriteOnce + storageClassName: longhorn + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: wger-static + namespace: workout-system + labels: + app.kubernetes.io/instance: wger + app.kubernetes.io/name: wger-static +spec: + accessModes: + - ReadWriteOnce + storageClassName: longhorn + resources: + requests: + storage: 2Gi \ No newline at end of file