K8s cluster - dendrite monolith

Why?

I wanted that fancy bonus:bonusplay.pl on matrix. Why dendrite? Well, it’s the new thing and I thought it might be good. Well, it did work, but there were some features missing, so I switched to using regular matrix.org. Nevertheless I’m making this post as documentation, as it might be useful to someone.

Caveats

If you want to host dendrite on subdomain, you probably want to setup delegation (so that you get :example.com instead of :matrix.example.com). There are 2 ways of doing that:

The problem with that is that it needs to have proper CORS setup, which I didn’t feel like doing.

The problem with that, is that matrix servers will perform requests to specified subdomain (matrix.example.com), with domain in Host header (Host: example.com). This causes k8s ingress to route it to example.com instead of matrix.example.com.

That’s why I opted for third option:

This way traffic is routed into example.com. Then, specify on ingress path: /_matrix to route matrix requests to our homeserver.

k8s config

I won’t post full dendrite config here, as it’s quite long. The secret itself I’ve created with kubectl create cm dendrite --from-file=dendrite.yaml --from-file=matrix_key.pem. Here are the things I modified:

global:
  server_name: dendrite.bonusplay.pl
  use_naffka: true
  naffka_database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_naffka?sslmode=disable
app_service_api:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_appservice?sslmode=disable
  registration_disabled: true
federation_sender:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_federationsender?sslmode=disable
key_server:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_keyserver?sslmode=disable
media_api:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_mediaapi?sslmode=disable
room_server:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_roomserver?sslmode=disable
signing_key_server:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_signingkeyserver?sslmode=disable
sync_api:
  database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_syncapi?sslmode=disable
user_api:
  account_database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_account?sslmode=disable
  device_database:
    connection_string: postgresql://dendrite:[email protected]/dendrite_device?sslmode=disable

dendrite:

apiVersion: apps/v1
kind: Deployment
metadata:
    name: dendrite
    namespace: matrix
    labels:
        app: dendrite
spec:
    replicas: 1
    selector:
        matchLabels:
            app: dendrite
    template:
        metadata:
            labels:
                app: dendrite
        spec:
            containers:
              - name: dendrite
                image: matrixdotorg/dendrite-monolith:latest
                imagePullPolicy: IfNotPresent
                ports:
                  - name: http
                    containerPort: 8008
                    protocol: TCP
                volumeMounts:
                  - name: config-volume
                    mountPath: /etc/dendrite
                  - name: matrix-pv
                    mountPath: /var/dendrite/media
                    subPath: media
            volumes:
              - name: config-volume
                configMap:
                    name: dendrite
              - name: matrix-pv
                persistentVolumeClaim:
                    claimName: matrix

---
apiVersion: v1
kind: Service
metadata:
    name: dendrite
    namespace: matrix
    labels:
        app: dendrite
spec:
    type: ClusterIP
    selector:
        app: dendrite
    ports:
        - name: http
          port: 8008
          protocol: TCP
          targetPort: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: dendrite
    namespace: matrix
    labels:
        app: dendrite
    annotations:
        cert-manager.io/cluster-issuer: bonusplay
spec:
    tls:
      - secretName: cert-wildcard
        hosts:
          - "bonusplay.pl"
          - "*.bonusplay.pl"
    rules:
        - host: bonusplay.pl
          http:
              paths:
                  - path: /_matrix
                    pathType: ImplementationSpecific
                    backend:
                        service:
                            name: dendrite
                            port:
                                name: http

postgres:

apiVersion: apps/v1
kind: Deployment
metadata:
    name: postgres
    namespace: matrix
    labels:
        app: postgres
spec:
    replicas: 1
    selector:
        matchLabels:
            app: postgres
    template:
        metadata:
            labels:
                app: postgres
        spec:
            containers:
                - name: postgres
                  image: postgres:11
                  imagePullPolicy: IfNotPresent
                  ports:
                      - name: postgres
                        containerPort: 5432
                        protocol: TCP
                  volumeMounts:
                      - mountPath: /var/lib/postgresql/data
                        name: matrix-pv
                        subPath: postgres
                      - name: init-pv
                        mountPath: /docker-entrypoint-initdb.d
                  env:
                      - name: POSTGRES_USER
                        value: "dendrite"
                      - name: POSTGRES_PASSWORD
                        value: "REDACTED"
            volumes:
                - name: matrix-pv
                  persistentVolumeClaim:
                      claimName: matrix
                - name: init-pv
                  configMap:
                      name: postgres-init
---
apiVersion: v1
kind: Service
metadata:
    name: postgres
    namespace: matrix
    labels:
        app: postgres
spec:
    type: ClusterIP
    selector:
        app: postgres
    ports:
        - name: postgres
          port: 5432
          protocol: TCP
          targetPort: postgres
---
apiVersion: v1
kind: ConfigMap
metadata:
    name: postgres-init
    namespace: matrix
data:
    20-create_db.sh: |
        for db in account device mediaapi syncapi roomserver signingkeyserver keyserver federationsender appservice naffka; do
            createdb -U dendrite -O dendrite dendrite_$db
        done

pvc:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: matrix
    namespace: matrix
    labels:
        app: matrix
spec:
    accessModes:
        - ReadWriteOnce
    resources:
        requests:
            storage: 5Gi
    storageClassName: matrix
    volumeMode: Filesystem