From 8818d822cff326ff443be1f24440c381d5f4858c Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 30 Dec 2025 03:39:19 +0000 Subject: [PATCH] loomio (not yet working), and new config for postgres and redis --- loomio/db-init-job.yaml | 64 ++++++++++++++++++ loomio/deployment-worker.yaml | 101 +++++++++++++++++++++++++++ loomio/deployment.yaml | 124 ++++++++++++++++++++++++++++++++++ loomio/ingress.yaml | 24 +++++++ loomio/kustomization.yaml | 20 ++++++ loomio/manifest.yaml | 55 +++++++++++++++ loomio/namespace.yaml | 4 ++ loomio/pvc-storage.yaml | 11 +++ loomio/pvc-uploads.yaml | 11 +++ loomio/service.yaml | 13 ++++ postgres/deployment.yaml | 10 +-- postgres/manifest.yaml | 7 +- postgres/namespace.yaml | 2 +- postgres/pvc.yaml | 2 +- postgres/service.yaml | 2 +- redis/deployment.yaml | 8 +-- redis/manifest.yaml | 7 +- redis/namespace.yaml | 2 +- redis/service.yaml | 4 +- 19 files changed, 452 insertions(+), 19 deletions(-) create mode 100644 loomio/db-init-job.yaml create mode 100644 loomio/deployment-worker.yaml create mode 100644 loomio/deployment.yaml create mode 100644 loomio/ingress.yaml create mode 100644 loomio/kustomization.yaml create mode 100644 loomio/manifest.yaml create mode 100644 loomio/namespace.yaml create mode 100644 loomio/pvc-storage.yaml create mode 100644 loomio/pvc-uploads.yaml create mode 100644 loomio/service.yaml diff --git a/loomio/db-init-job.yaml b/loomio/db-init-job.yaml new file mode 100644 index 0000000..020d9f6 --- /dev/null +++ b/loomio/db-init-job.yaml @@ -0,0 +1,64 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: loomio-db-init +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: db-init + image: postgres:15-alpine + env: + - name: PGHOST + value: "{{ .db.host }}" + - name: PGPORT + value: "{{ .db.port }}" + - name: PGUSER + value: postgres + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: postgres-secrets + key: postgres.password + - name: LOOMIO_DB_NAME + value: "{{ .db.name }}" + - name: LOOMIO_DB_USER + value: "{{ .db.user }}" + - name: LOOMIO_DB_PASSWORD + valueFrom: + secretKeyRef: + name: loomio-secrets + key: dbPassword + command: + - sh + - -c + - | + echo "Creating database and user for Loomio..." + + # Check if database exists, create if not + psql -tc "SELECT 1 FROM pg_database WHERE datname = '$LOOMIO_DB_NAME'" | grep -q 1 || \ + psql -c "CREATE DATABASE \"$LOOMIO_DB_NAME\"" + + # Check if user exists, create or update password + psql -tc "SELECT 1 FROM pg_user WHERE usename = '$LOOMIO_DB_USER'" | grep -q 1 && \ + psql -c "ALTER USER \"$LOOMIO_DB_USER\" WITH PASSWORD '$LOOMIO_DB_PASSWORD'" || \ + psql -c "CREATE USER \"$LOOMIO_DB_USER\" WITH PASSWORD '$LOOMIO_DB_PASSWORD'" + + # Grant all privileges + psql -c "GRANT ALL PRIVILEGES ON DATABASE \"$LOOMIO_DB_NAME\" TO \"$LOOMIO_DB_USER\"" + + # Connect to the database and grant schema permissions + psql -d "$LOOMIO_DB_NAME" -c "GRANT ALL ON SCHEMA public TO \"$LOOMIO_DB_USER\"" + + echo "Database initialization complete!" + securityContext: + runAsNonRoot: true + runAsUser: 999 # postgres user + runAsGroup: 999 + allowPrivilegeEscalation: false + capabilities: + drop: [ALL] + readOnlyRootFilesystem: true + seccompProfile: + type: RuntimeDefault \ No newline at end of file diff --git a/loomio/deployment-worker.yaml b/loomio/deployment-worker.yaml new file mode 100644 index 0000000..cdd67b7 --- /dev/null +++ b/loomio/deployment-worker.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: loomio-worker +spec: + replicas: 1 + selector: + matchLabels: + component: worker + template: + metadata: + labels: + component: worker + spec: + containers: + - name: worker + image: {{ .workerImage }} + env: + - name: TASK + value: worker + - name: RAILS_ENV + value: production + - name: SITE_NAME + value: {{ .appName }} + - name: CANONICAL_HOST + value: {{ .domain }} + - name: PUBLIC_APP_URL + value: https://{{ .domain }} + - name: SUPPORT_EMAIL + value: {{ .supportEmail }} + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: loomio-secrets + key: dbUrl + - name: REDIS_URL + value: {{ .redisUrl }} + - name: DEVISE_SECRET + valueFrom: + secretKeyRef: + name: loomio-secrets + key: deviseSecret + - name: SECRET_COOKIE_TOKEN + valueFrom: + secretKeyRef: + name: loomio-secrets + key: secretCookieToken + - name: ACTIVE_STORAGE_SERVICE + value: {{ .activeStorageService }} + - name: SMTP_AUTH + value: {{ .smtp.auth }} + - name: SMTP_DOMAIN + value: {{ .smtp.domain }} + - name: SMTP_SERVER + value: {{ .smtp.host }} + - name: SMTP_PORT + value: "{{ .smtp.port }}" + - name: SMTP_USERNAME + value: {{ .smtp.user }} + - name: SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: loomio-secrets + key: smtpPassword + - name: SMTP_USE_SSL + value: "{{ .smtp.tls }}" + - name: REPLY_HOSTNAME + value: {{ .smtp.from }} + volumeMounts: + - name: uploads + mountPath: /loomio/public/system + - name: storage + mountPath: /loomio/storage + - name: tmp + mountPath: /loomio/tmp + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 1Gi + cpu: 500m + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + allowPrivilegeEscalation: false + capabilities: + drop: [ALL] + readOnlyRootFilesystem: false + seccompProfile: + type: RuntimeDefault + volumes: + - name: uploads + persistentVolumeClaim: + claimName: loomio-uploads + - name: storage + persistentVolumeClaim: + claimName: loomio-storage + - name: tmp + emptyDir: {} \ No newline at end of file diff --git a/loomio/deployment.yaml b/loomio/deployment.yaml new file mode 100644 index 0000000..8c54136 --- /dev/null +++ b/loomio/deployment.yaml @@ -0,0 +1,124 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: loomio +spec: + replicas: 1 + selector: + matchLabels: + component: web + template: + metadata: + labels: + component: web + spec: + containers: + - name: loomio + image: {{ .image }} + ports: + - containerPort: 3000 + name: http + env: + - name: RAILS_ENV + value: production + - name: SITE_NAME + value: {{ .appName }} + - name: CANONICAL_HOST + value: {{ .domain }} + - name: PUBLIC_APP_URL + value: https://{{ .domain }} + - name: SUPPORT_EMAIL + value: {{ .supportEmail }} + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: loomio-secrets + key: dbUrl + - name: REDIS_URL + value: {{ .redisUrl }} + - name: DEVISE_SECRET + valueFrom: + secretKeyRef: + name: loomio-secrets + key: deviseSecret + - name: SECRET_COOKIE_TOKEN + valueFrom: + secretKeyRef: + name: loomio-secrets + key: secretCookieToken + - name: FORCE_SSL + value: "{{ .forceSSL }}" + - name: USE_RACK_ATTACK + value: "{{ .useRackAttack }}" + - name: PUMA_WORKERS + value: "{{ .pumaWorkers }}" + - name: MIN_THREADS + value: "{{ .minThreads }}" + - name: MAX_THREADS + value: "{{ .maxThreads }}" + - name: ACTIVE_STORAGE_SERVICE + value: {{ .activeStorageService }} + - name: SMTP_AUTH + value: {{ .smtp.auth }} + - name: SMTP_DOMAIN + value: {{ .smtp.domain }} + - name: SMTP_SERVER + value: {{ .smtp.host }} + - name: SMTP_PORT + value: "{{ .smtp.port }}" + - name: SMTP_USERNAME + value: {{ .smtp.user }} + - name: SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: loomio-secrets + key: smtpPassword + - name: SMTP_USE_SSL + value: "{{ .smtp.tls }}" + - name: REPLY_HOSTNAME + value: {{ .smtp.from }} + volumeMounts: + - name: uploads + mountPath: /loomio/public/system + - name: storage + mountPath: /loomio/storage + - name: tmp + mountPath: /loomio/tmp + resources: + requests: + memory: 512Mi + cpu: 200m + limits: + memory: 2Gi + cpu: 1000m + livenessProbe: + httpGet: + path: /health + port: 3000 + initialDelaySeconds: 60 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /health + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 10 + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + allowPrivilegeEscalation: false + capabilities: + drop: [ALL] + readOnlyRootFilesystem: false + seccompProfile: + type: RuntimeDefault + volumes: + - name: uploads + persistentVolumeClaim: + claimName: loomio-uploads + - name: storage + persistentVolumeClaim: + claimName: loomio-storage + - name: tmp + emptyDir: {} \ No newline at end of file diff --git a/loomio/ingress.yaml b/loomio/ingress.yaml new file mode 100644 index 0000000..c181efd --- /dev/null +++ b/loomio/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: loomio + annotations: + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" +spec: + ingressClassName: traefik + tls: + - hosts: + - {{ .domain }} + secretName: {{ .tlsSecretName }} + rules: + - host: {{ .domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: loomio + port: + number: 80 \ No newline at end of file diff --git a/loomio/kustomization.yaml b/loomio/kustomization.yaml new file mode 100644 index 0000000..89cd7d3 --- /dev/null +++ b/loomio/kustomization.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: loomio + +resources: + - namespace.yaml + - pvc-uploads.yaml + - pvc-storage.yaml + - deployment.yaml + - deployment-worker.yaml + - service.yaml + - ingress.yaml + - db-init-job.yaml + +labels: + - includeSelectors: true + pairs: + app: loomio + managedBy: kustomize + partOf: wild-cloud \ No newline at end of file diff --git a/loomio/manifest.yaml b/loomio/manifest.yaml new file mode 100644 index 0000000..8dbbbd0 --- /dev/null +++ b/loomio/manifest.yaml @@ -0,0 +1,55 @@ +name: loomio +description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together +version: 3.0.11 +icon: https://www.loomio.com/favicon.ico +requires: + - name: postgres + installed_as: postgres + - name: redis +defaultConfig: + namespace: loomio + externalDnsDomain: {{ .cloud.domain }} + image: loomio/loomio:v3.0.11 + workerImage: loomio/loomio:v3.0.11 + appName: Loomio + domain: loomio.{{ .cloud.domain }} + tlsSecretName: wildcard-wild-cloud-tls + port: 3000 + storage: + uploads: 5Gi + files: 5Gi + plugins: 1Gi + redisUrl: {{ .apps.redis.uri }} + adminEmail: "admin@{{ .cloud.domain }}" + supportEmail: "support@{{ .cloud.domain }}" + forceSSL: "1" + useRackAttack: "1" + pumaWorkers: "2" + minThreads: "5" + maxThreads: "5" + activeStorageService: local + db: + name: loomio + user: loomio + host: {{ .apps.postgres.host }} + port: {{ .apps.postgres.port }} + smtp: + auth: plain + domain: "{{ .cloud.domain }}" + host: "{{ .cloud.smtp.host }}" + port: "{{ .cloud.smtp.port }}" + user: "{{ .cloud.smtp.user }}" + tls: "{{ .cloud.smtp.tls }}" + from: "{{ .cloud.smtp.from }}" +defaultSecrets: + - key: dbPassword + default: "{{ random.AlphaNum 32 }}" + - key: dbUrl + default: "postgresql://{{ .app.db.user }}:{{ .secrets.dbPassword }}@{{ .app.db.host }}:{{ .app.db.port }}/{{ .app.db.name }}?pool=30" + - key: deviseSecret + default: "{{ random.AlphaNum 32 }}" + - key: secretCookieToken + default: "{{ random.AlphaNum 32 }}" + - key: smtpPassword +requiredSecrets: + - postgres.password diff --git a/loomio/namespace.yaml b/loomio/namespace.yaml new file mode 100644 index 0000000..054927e --- /dev/null +++ b/loomio/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .namespace }} diff --git a/loomio/pvc-storage.yaml b/loomio/pvc-storage.yaml new file mode 100644 index 0000000..d34c554 --- /dev/null +++ b/loomio/pvc-storage.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: loomio-storage +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage.files }} + storageClassName: longhorn \ No newline at end of file diff --git a/loomio/pvc-uploads.yaml b/loomio/pvc-uploads.yaml new file mode 100644 index 0000000..33e3e6d --- /dev/null +++ b/loomio/pvc-uploads.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: loomio-uploads +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage.uploads }} + storageClassName: longhorn \ No newline at end of file diff --git a/loomio/service.yaml b/loomio/service.yaml new file mode 100644 index 0000000..f618df9 --- /dev/null +++ b/loomio/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: loomio +spec: + type: ClusterIP + selector: + component: web + ports: + - name: http + port: 80 + targetPort: 3000 + protocol: TCP \ No newline at end of file diff --git a/postgres/deployment.yaml b/postgres/deployment.yaml index d14151f..9b677d0 100644 --- a/postgres/deployment.yaml +++ b/postgres/deployment.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: postgres - image: "{{ .apps.postgres.image }}" + image: "{{ .image }}" args: [ "-c", @@ -35,16 +35,16 @@ spec: - name: PGDATA value: /var/lib/postgresql/data/pgdata - name: TZ - value: "{{ .apps.postgres.timezone }}" + value: "{{ .timezone }}" - name: POSTGRES_DB - value: "{{ .apps.postgres.database }}" + value: "{{ .database }}" - name: POSTGRES_USER - value: "{{ .apps.postgres.user }}" + value: "{{ .user }}" - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: postgres-secrets - key: apps.postgres.password + key: password volumeMounts: - name: postgres-data mountPath: /var/lib/postgresql/data diff --git a/postgres/manifest.yaml b/postgres/manifest.yaml index 53d7113..2095c69 100644 --- a/postgres/manifest.yaml +++ b/postgres/manifest.yaml @@ -4,10 +4,13 @@ description: PostgreSQL is a powerful, open source object-relational database sy version: 1.0.0 icon: https://www.postgresql.org/media/img/about/press/elephant.png defaultConfig: + namespace: postgres + host: postgres.postgres.svc.cluster.local + port: 5432 database: postgres user: postgres storage: 10Gi image: pgvector/pgvector:pg15 timezone: UTC -requiredSecrets: - - apps.postgres.password +defaultSecrets: + - key: password diff --git a/postgres/namespace.yaml b/postgres/namespace.yaml index 427794c..054927e 100644 --- a/postgres/namespace.yaml +++ b/postgres/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: postgres + name: {{ .namespace }} diff --git a/postgres/pvc.yaml b/postgres/pvc.yaml index 822353a..08624ec 100644 --- a/postgres/pvc.yaml +++ b/postgres/pvc.yaml @@ -9,4 +9,4 @@ spec: storageClassName: longhorn resources: requests: - storage: {{ .apps.postgres.storage | default "10Gi" }} + storage: {{ .storage }} diff --git a/postgres/service.yaml b/postgres/service.yaml index 4628dde..61d5219 100644 --- a/postgres/service.yaml +++ b/postgres/service.yaml @@ -5,6 +5,6 @@ metadata: name: postgres spec: ports: - - port: 5432 + - port: {{ .port }} selector: app: postgres diff --git a/redis/deployment.yaml b/redis/deployment.yaml index c0dba06..e8e6ebe 100644 --- a/redis/deployment.yaml +++ b/redis/deployment.yaml @@ -14,18 +14,18 @@ spec: app: redis spec: containers: - - image: "{{ .apps.redis.image }}" + - image: "{{ .image }}" name: redis ports: - - containerPort: {{ .apps.redis.port }} + - containerPort: {{ .port }} env: - name: TZ - value: "{{ .apps.redis.timezone }}" + value: "{{ .timezone }}" - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: redis-secrets - key: apps.redis.password + key: password command: - redis-server - --requirepass diff --git a/redis/manifest.yaml b/redis/manifest.yaml index d3e7c06..b0bf720 100644 --- a/redis/manifest.yaml +++ b/redis/manifest.yaml @@ -4,8 +4,11 @@ description: Redis is an open source, in-memory data structure store, used as a version: 1.0.0 icon: defaultConfig: + namespace: redis image: redis:alpine timezone: UTC + host: redis.redis.svc.cluster.local port: 6379 -requiredSecrets: - - apps.redis.password + uri: redis://{{ .app.host }}:{{ .app.port }}/0 +defaultSecrets: + - key: password diff --git a/redis/namespace.yaml b/redis/namespace.yaml index 188bfc8..6990999 100644 --- a/redis/namespace.yaml +++ b/redis/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: redis \ No newline at end of file + name: {{ .namespace }} \ No newline at end of file diff --git a/redis/service.yaml b/redis/service.yaml index 9c75149..9740f0e 100644 --- a/redis/service.yaml +++ b/redis/service.yaml @@ -7,7 +7,7 @@ metadata: app: redis spec: ports: - - port: {{ .apps.redis.port }} - targetPort: {{ .apps.redis.port }} + - port: {{ .port }} + targetPort: {{ .port }} selector: app: redis