From 4d4b48cf723a34ce557ac279032dacd1b3fd5bc5 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Fri, 19 Jun 2026 21:33:33 +0000 Subject: [PATCH] Adds zulip app. --- zulip/app.yaml | 5 + zulip/versions/9/README.md | 42 ++++++ zulip/versions/9/deployment-memcached.yaml | 46 +++++++ zulip/versions/9/deployment-postgres.yaml | 56 ++++++++ zulip/versions/9/deployment-rabbitmq.yaml | 50 ++++++++ zulip/versions/9/deployment.yaml | 142 +++++++++++++++++++++ zulip/versions/9/ingress.yaml | 26 ++++ zulip/versions/9/kustomization.yaml | 22 ++++ zulip/versions/9/manifest.yaml | 37 ++++++ zulip/versions/9/namespace.yaml | 4 + zulip/versions/9/pvc-postgres.yaml | 11 ++ zulip/versions/9/pvc.yaml | 11 ++ zulip/versions/9/service-memcached.yaml | 12 ++ zulip/versions/9/service-postgres.yaml | 12 ++ zulip/versions/9/service-rabbitmq.yaml | 12 ++ zulip/versions/9/service.yaml | 13 ++ 16 files changed, 501 insertions(+) create mode 100644 zulip/app.yaml create mode 100644 zulip/versions/9/README.md create mode 100644 zulip/versions/9/deployment-memcached.yaml create mode 100644 zulip/versions/9/deployment-postgres.yaml create mode 100644 zulip/versions/9/deployment-rabbitmq.yaml create mode 100644 zulip/versions/9/deployment.yaml create mode 100644 zulip/versions/9/ingress.yaml create mode 100644 zulip/versions/9/kustomization.yaml create mode 100644 zulip/versions/9/manifest.yaml create mode 100644 zulip/versions/9/namespace.yaml create mode 100644 zulip/versions/9/pvc-postgres.yaml create mode 100644 zulip/versions/9/pvc.yaml create mode 100644 zulip/versions/9/service-memcached.yaml create mode 100644 zulip/versions/9/service-postgres.yaml create mode 100644 zulip/versions/9/service-rabbitmq.yaml create mode 100644 zulip/versions/9/service.yaml diff --git a/zulip/app.yaml b/zulip/app.yaml new file mode 100644 index 0000000..b1adde8 --- /dev/null +++ b/zulip/app.yaml @@ -0,0 +1,5 @@ +name: zulip +is: zulip +description: Zulip is an open-source team chat application with threaded conversations, making it easy to catch up on important discussions without information overload. +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/zulip.svg +latest: "9" diff --git a/zulip/versions/9/README.md b/zulip/versions/9/README.md new file mode 100644 index 0000000..37e1b7d --- /dev/null +++ b/zulip/versions/9/README.md @@ -0,0 +1,42 @@ +# Zulip + +Zulip is an open-source team messaging platform with a unique topic-based threading model. + +## Dependencies + +- **SMTP** - For sending invitations and notifications +- **Redis** - Used for caching and real-time event queuing + +Zulip bundles its own **PostgreSQL**, **RabbitMQ**, and **Memcached** instances — these are deployed alongside the main Zulip pod and are not shared with other apps. + +## Configuration + +Key settings in `config.yaml`: + +- **domain** - Where Zulip will be accessible +- **adminEmail** - Admin account email (defaults to your operator email) +- **smtp** - Email settings inherited from your Wild Cloud SMTP service + +## First-Time Setup + +1. Add and deploy the app: + ```bash + wild app add zulip + wild app deploy zulip + ``` + +2. **First start takes 5–10 minutes** as Zulip runs hundreds of Django database migrations. Wait until the pod shows `1/1 Running`. + +3. The admin account is pre-configured with the `adminEmail` and `adminPassword` from `secrets.yaml`. Visit the app URL and log in. + +4. Complete the realm (organization) setup wizard on first login. + +## Inviting Users + +Send invitation emails from **Settings → Organization → Invitations**, or use pre-generated invite links. + +## Notes + +- The `secretKey`, `postgresPassword`, and `rabbitmqPassword` are all auto-generated in `secrets.yaml` +- Zulip's topic-based threading keeps conversations organized — each stream (channel) has multiple topics +- Mobile and desktop apps are available and connect to self-hosted instances diff --git a/zulip/versions/9/deployment-memcached.yaml b/zulip/versions/9/deployment-memcached.yaml new file mode 100644 index 0000000..d37b7a8 --- /dev/null +++ b/zulip/versions/9/deployment-memcached.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zulip-memcached + namespace: {{ .namespace }} +spec: + replicas: 1 + selector: + matchLabels: + component: memcached + template: + metadata: + labels: + component: memcached + spec: + securityContext: + runAsNonRoot: true + runAsUser: 11211 + seccompProfile: + type: RuntimeDefault + containers: + - name: memcached + image: memcached:1.6.32-alpine + args: + - -m + - "64m" + - -c + - "1024" + - -p + - "11211" + ports: + - containerPort: 11211 + name: memcached + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: "200m" + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true diff --git a/zulip/versions/9/deployment-postgres.yaml b/zulip/versions/9/deployment-postgres.yaml new file mode 100644 index 0000000..bd91315 --- /dev/null +++ b/zulip/versions/9/deployment-postgres.yaml @@ -0,0 +1,56 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zulip-postgres + namespace: {{ .namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: postgres + template: + metadata: + labels: + component: postgres + spec: + securityContext: + runAsNonRoot: false + runAsUser: 0 + seccompProfile: + type: RuntimeDefault + containers: + - name: postgres + image: zulip/zulip-postgresql:14 + ports: + - containerPort: 5432 + name: postgres + env: + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + - name: POSTGRES_DB + value: "{{ .db.name }}" + - name: POSTGRES_USER + value: "{{ .db.user }}" + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: zulip-secrets + key: postgresPassword + resources: + requests: + cpu: 50m + memory: 256Mi + limits: + cpu: "1" + memory: 1Gi + securityContext: + readOnlyRootFilesystem: false + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: zulip-postgres-data diff --git a/zulip/versions/9/deployment-rabbitmq.yaml b/zulip/versions/9/deployment-rabbitmq.yaml new file mode 100644 index 0000000..8c51a69 --- /dev/null +++ b/zulip/versions/9/deployment-rabbitmq.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zulip-rabbitmq + namespace: {{ .namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: rabbitmq + template: + metadata: + labels: + component: rabbitmq + spec: + securityContext: + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + seccompProfile: + type: RuntimeDefault + containers: + - name: rabbitmq + image: rabbitmq:3.13-alpine + ports: + - containerPort: 5672 + name: amqp + env: + - name: RABBITMQ_DEFAULT_USER + value: "{{ .rabbitmq.user }}" + - name: RABBITMQ_DEFAULT_PASS + valueFrom: + secretKeyRef: + name: zulip-secrets + key: rabbitmqPassword + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: "1" + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false diff --git a/zulip/versions/9/deployment.yaml b/zulip/versions/9/deployment.yaml new file mode 100644 index 0000000..74e0d4b --- /dev/null +++ b/zulip/versions/9/deployment.yaml @@ -0,0 +1,142 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zulip + namespace: {{ .namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: web + template: + metadata: + labels: + component: web + spec: + securityContext: + runAsNonRoot: false + runAsUser: 0 + seccompProfile: + type: RuntimeDefault + containers: + - name: zulip + image: zulip/docker-zulip:9.4-0 + ports: + - name: http + containerPort: 80 + protocol: TCP + env: + - name: SETTING_ZULIP_ADMINISTRATOR + value: "{{ .adminEmail }}" + - name: ZULIP_PASSWORD + valueFrom: + secretKeyRef: + name: zulip-secrets + key: adminPassword + - name: SETTING_EXTERNAL_HOST + value: "{{ .domain }}" + - name: SSL_CERTIFICATE_GENERATION + value: "self-signed" + - name: SECRETS_secret_key + valueFrom: + secretKeyRef: + name: zulip-secrets + key: secretKey + # Database + - name: DB_HOST + value: "{{ .db.host }}" + - name: DB_HOST_PORT + value: "{{ .db.port }}" + - name: DB_NAME + value: "{{ .db.name }}" + - name: DB_USER + value: "{{ .db.user }}" + - name: SECRETS_postgres_password + valueFrom: + secretKeyRef: + name: zulip-secrets + key: postgresPassword + # RabbitMQ + - name: SETTING_RABBITMQ_HOST + value: "{{ .rabbitmq.host }}" + - name: SETTING_RABBITMQ_USER + value: "{{ .rabbitmq.user }}" + - name: SECRETS_rabbitmq_password + valueFrom: + secretKeyRef: + name: zulip-secrets + key: rabbitmqPassword + # Redis + - name: SETTING_REDIS_HOST + value: "{{ .redis.host }}" + - name: SECRETS_redis_password + valueFrom: + secretKeyRef: + name: zulip-secrets + key: redis.password + # Memcached + - name: SETTING_MEMCACHED_LOCATION + value: "{{ .memcached.host }}:11211" + # Email + - name: SETTING_EMAIL_HOST + value: "{{ .smtp.host }}" + - name: SETTING_EMAIL_HOST_USER + value: "{{ .smtp.user }}" + - name: SETTING_EMAIL_PORT + value: "{{ .smtp.port }}" + - name: SETTING_EMAIL_USE_TLS + value: "True" + - name: SETTING_EMAIL_BACKEND + value: "django.core.mail.backends.smtp.EmailBackend" + - name: SETTING_DEFAULT_FROM_EMAIL + value: "{{ .smtp.from }}" + - name: SECRETS_email_password + valueFrom: + secretKeyRef: + name: zulip-secrets + key: smtp.password + resources: + limits: + cpu: "2" + ephemeral-storage: 1Gi + memory: 3Gi + requests: + cpu: 50m + ephemeral-storage: 100Mi + memory: 512Mi + volumeMounts: + - name: zulip-data + mountPath: /data + livenessProbe: + httpGet: + path: /accounts/home/ + port: 443 + scheme: HTTPS + httpHeaders: + - name: Host + value: "{{ .domain }}" + initialDelaySeconds: 180 + timeoutSeconds: 30 + periodSeconds: 30 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /accounts/home/ + port: 443 + scheme: HTTPS + httpHeaders: + - name: Host + value: "{{ .domain }}" + initialDelaySeconds: 120 + timeoutSeconds: 30 + periodSeconds: 15 + failureThreshold: 6 + securityContext: + readOnlyRootFilesystem: false + volumes: + - name: zulip-data + persistentVolumeClaim: + claimName: zulip-data + restartPolicy: Always diff --git a/zulip/versions/9/ingress.yaml b/zulip/versions/9/ingress.yaml new file mode 100644 index 0000000..73bd155 --- /dev/null +++ b/zulip/versions/9/ingress.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: zulip + namespace: {{ .namespace }} + annotations: + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" + external-dns.alpha.kubernetes.io/ttl: "60" +spec: + ingressClassName: traefik + rules: + - host: {{ .domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: zulip + port: + number: 80 + tls: + - hosts: + - {{ .domain }} + secretName: {{ .tlsSecretName }} diff --git a/zulip/versions/9/kustomization.yaml b/zulip/versions/9/kustomization.yaml new file mode 100644 index 0000000..c71b10e --- /dev/null +++ b/zulip/versions/9/kustomization.yaml @@ -0,0 +1,22 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: {{ .namespace }} +labels: + - includeSelectors: true + pairs: + app: zulip + managedBy: kustomize + partOf: wild-cloud +resources: + - namespace.yaml + - deployment.yaml + - service.yaml + - ingress.yaml + - pvc.yaml + - deployment-postgres.yaml + - service-postgres.yaml + - pvc-postgres.yaml + - deployment-rabbitmq.yaml + - service-rabbitmq.yaml + - deployment-memcached.yaml + - service-memcached.yaml diff --git a/zulip/versions/9/manifest.yaml b/zulip/versions/9/manifest.yaml new file mode 100644 index 0000000..60fdd83 --- /dev/null +++ b/zulip/versions/9/manifest.yaml @@ -0,0 +1,37 @@ +version: 9.4-3 +requires: + - name: smtp + - name: redis +defaultConfig: + namespace: zulip + domain: "zulip.{{ .cloud.domain }}" + externalDnsDomain: "{{ .cloud.domain }}" + tlsSecretName: wildcard-wild-cloud-tls + storage: 2Gi + adminEmail: "{{ .operator.email }}" + db: + host: zulip-postgres.zulip.svc.cluster.local + port: "5432" + name: zulip + user: zulip + storage: 2Gi + rabbitmq: + host: zulip-rabbitmq.zulip.svc.cluster.local + user: zulip + redis: + host: "{{ .apps.redis.host }}" + memcached: + host: zulip-memcached.zulip.svc.cluster.local + smtp: + host: "{{ .apps.smtp.host }}" + port: "{{ .apps.smtp.port }}" + user: "{{ .apps.smtp.user }}" + from: "{{ .apps.smtp.from }}" +defaultSecrets: + - key: adminPassword + - key: secretKey + - key: postgresPassword + - key: rabbitmqPassword +requiredSecrets: + - smtp.password + - redis.password diff --git a/zulip/versions/9/namespace.yaml b/zulip/versions/9/namespace.yaml new file mode 100644 index 0000000..054927e --- /dev/null +++ b/zulip/versions/9/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .namespace }} diff --git a/zulip/versions/9/pvc-postgres.yaml b/zulip/versions/9/pvc-postgres.yaml new file mode 100644 index 0000000..57557ea --- /dev/null +++ b/zulip/versions/9/pvc-postgres.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: zulip-postgres-data + namespace: {{ .namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .db.storage }} diff --git a/zulip/versions/9/pvc.yaml b/zulip/versions/9/pvc.yaml new file mode 100644 index 0000000..f8793f8 --- /dev/null +++ b/zulip/versions/9/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: zulip-data + namespace: {{ .namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage }} diff --git a/zulip/versions/9/service-memcached.yaml b/zulip/versions/9/service-memcached.yaml new file mode 100644 index 0000000..49afbd2 --- /dev/null +++ b/zulip/versions/9/service-memcached.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: zulip-memcached + namespace: {{ .namespace }} +spec: + selector: + component: memcached + ports: + - port: 11211 + targetPort: 11211 + name: memcached diff --git a/zulip/versions/9/service-postgres.yaml b/zulip/versions/9/service-postgres.yaml new file mode 100644 index 0000000..a5be78c --- /dev/null +++ b/zulip/versions/9/service-postgres.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: zulip-postgres + namespace: {{ .namespace }} +spec: + selector: + component: postgres + ports: + - port: 5432 + targetPort: 5432 + name: postgres diff --git a/zulip/versions/9/service-rabbitmq.yaml b/zulip/versions/9/service-rabbitmq.yaml new file mode 100644 index 0000000..6bf8b1d --- /dev/null +++ b/zulip/versions/9/service-rabbitmq.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: zulip-rabbitmq + namespace: {{ .namespace }} +spec: + selector: + component: rabbitmq + ports: + - port: 5672 + targetPort: 5672 + name: amqp diff --git a/zulip/versions/9/service.yaml b/zulip/versions/9/service.yaml new file mode 100644 index 0000000..3911e39 --- /dev/null +++ b/zulip/versions/9/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: zulip + namespace: {{ .namespace }} +spec: + selector: + component: web + ports: + - name: http + port: 80 + targetPort: 80 + protocol: TCP