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:
- serve file under
example.com/.well-known/matrix/server
The problem with that is that it needs to have proper CORS setup, which I didn’t feel like doing.
- setup
_matrix._tcp
SRV record on your domain to a subdomain
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:
- setup
_matrix._tcp
SRV record on your domain to the same domain, but on port 443
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