diff --git a/apps/listmonk/db-init-job.yaml b/apps/listmonk/db-init-job.yaml new file mode 100644 index 0000000..5ca2eae --- /dev/null +++ b/apps/listmonk/db-init-job.yaml @@ -0,0 +1,65 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: listmonk-db-init + labels: + component: db-init +spec: + template: + metadata: + labels: + component: db-init + spec: + restartPolicy: OnFailure + securityContext: + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + seccompProfile: + type: RuntimeDefault + containers: + - name: postgres-init + image: postgres:15 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + env: + - name: PGHOST + value: {{ .apps.listmonk.dbHost }} + - name: PGUSER + value: postgres + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: listmonk-secrets + key: apps.postgres.password + - name: DB_NAME + value: {{ .apps.listmonk.dbName }} + - name: DB_USER + value: {{ .apps.listmonk.dbUser }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: listmonk-secrets + key: apps.listmonk.dbPassword + command: + - /bin/bash + - -c + - | + set -e + echo "Waiting for PostgreSQL to be ready..." + until pg_isready; do + echo "PostgreSQL is not ready - sleeping" + sleep 2 + done + echo "PostgreSQL is ready" + + echo "Creating database and user for Listmonk..." + psql -c "CREATE DATABASE ${DB_NAME};" || echo "Database ${DB_NAME} already exists" + psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';" || echo "User ${DB_USER} already exists" + psql -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};" + psql -d ${DB_NAME} -c "GRANT ALL ON SCHEMA public TO ${DB_USER};" + echo "Database initialization complete" \ No newline at end of file diff --git a/apps/listmonk/deployment.yaml b/apps/listmonk/deployment.yaml new file mode 100644 index 0000000..b67c999 --- /dev/null +++ b/apps/listmonk/deployment.yaml @@ -0,0 +1,86 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: listmonk + namespace: listmonk +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: web + template: + metadata: + labels: + component: web + spec: + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: listmonk + image: listmonk/listmonk:v5.0.3 + command: ["/bin/sh"] + args: ["-c", "./listmonk --install --idempotent --yes && ./listmonk --upgrade --yes && ./listmonk"] + ports: + - name: http + containerPort: 9000 + protocol: TCP + env: + - name: LISTMONK_app__address + value: "0.0.0.0:9000" + - name: LISTMONK_db__host + value: {{ .apps.listmonk.dbHost }} + - name: LISTMONK_db__port + value: "{{ .apps.listmonk.dbPort }}" + - name: LISTMONK_db__user + value: {{ .apps.listmonk.dbUser }} + - name: LISTMONK_db__database + value: {{ .apps.listmonk.dbName }} + - name: LISTMONK_db__ssl_mode + value: {{ .apps.listmonk.dbSSLMode }} + - name: LISTMONK_db__password + valueFrom: + secretKeyRef: + name: listmonk-secrets + key: apps.listmonk.dbPassword + resources: + limits: + cpu: 500m + ephemeral-storage: 1Gi + memory: 512Mi + requests: + cpu: 100m + ephemeral-storage: 50Mi + memory: 128Mi + volumeMounts: + - name: listmonk-data + mountPath: /listmonk/data + livenessProbe: + tcpSocket: + port: 9000 + initialDelaySeconds: 30 + timeoutSeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + tcpSocket: + port: 9000 + initialDelaySeconds: 10 + timeoutSeconds: 3 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + volumes: + - name: listmonk-data + persistentVolumeClaim: + claimName: listmonk-data + restartPolicy: Always \ No newline at end of file diff --git a/apps/listmonk/ingress.yaml b/apps/listmonk/ingress.yaml new file mode 100644 index 0000000..e63de9e --- /dev/null +++ b/apps/listmonk/ingress.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: listmonk + namespace: listmonk + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" +spec: + ingressClassName: traefik + tls: + - hosts: + - {{ .apps.listmonk.domain }} + secretName: {{ .apps.listmonk.tlsSecretName }} + rules: + - host: {{ .apps.listmonk.domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: listmonk + port: + number: 80 \ No newline at end of file diff --git a/apps/listmonk/kustomization.yaml b/apps/listmonk/kustomization.yaml new file mode 100644 index 0000000..ffb081a --- /dev/null +++ b/apps/listmonk/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: listmonk +labels: + - includeSelectors: true + pairs: + app: listmonk + managedBy: kustomize + partOf: wild-cloud +resources: + - namespace.yaml + - db-init-job.yaml + - deployment.yaml + - service.yaml + - ingress.yaml + - pvc.yaml \ No newline at end of file diff --git a/apps/listmonk/manifest.yaml b/apps/listmonk/manifest.yaml new file mode 100644 index 0000000..cf6d907 --- /dev/null +++ b/apps/listmonk/manifest.yaml @@ -0,0 +1,20 @@ +name: listmonk +description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. +version: 5.0.3 +icon: https://listmonk.app/static/images/logo.svg +requires: + - name: postgres +defaultConfig: + domain: listmonk.{{ .cloud.domain }} + tlsSecretName: wildcard-wild-cloud-tls + storage: 1Gi + dbHost: postgres.postgres.svc.cluster.local + dbPort: 5432 + dbName: listmonk + dbUser: listmonk + dbSSLMode: disable + timezone: UTC +requiredSecrets: + - apps.listmonk.dbPassword + - apps.listmonk.dbUrl + - apps.postgres.password \ No newline at end of file diff --git a/apps/listmonk/namespace.yaml b/apps/listmonk/namespace.yaml new file mode 100644 index 0000000..b7fe900 --- /dev/null +++ b/apps/listmonk/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: listmonk \ No newline at end of file diff --git a/apps/listmonk/pvc.yaml b/apps/listmonk/pvc.yaml new file mode 100644 index 0000000..926bf1e --- /dev/null +++ b/apps/listmonk/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: listmonk-data + namespace: listmonk +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .apps.listmonk.storage }} \ No newline at end of file diff --git a/apps/listmonk/service.yaml b/apps/listmonk/service.yaml new file mode 100644 index 0000000..1c4c18f --- /dev/null +++ b/apps/listmonk/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: listmonk + namespace: listmonk +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + component: web \ No newline at end of file