We would like to add custom fonts to our wopi editor. I understand we need to fill the /opt/cool/systemplate/tmpfonts folder with the fonts.
Can someone please explain how we can do a volume mount to this folder with the Helm chart?
We would like to add custom fonts to our wopi editor. I understand we need to fill the /opt/cool/systemplate/tmpfonts folder with the fonts.
Can someone please explain how we can do a volume mount to this folder with the Helm chart?
Hii @jaapglasbergen
It sounds like you’re looking to add custom fonts to your WOPI editor by configuring a volume mount in the Helm chart. To help you better, could you share your current values.yaml
or any other Helm configuration file you’re using to set up Collabora Online?
This will allow me to provide more specific guidance on how to modify the configuration to include a volume mount for custom fonts.
Although just for example you can mount fonts like this, but this can work or may not work first i need to know your config settings…
collabora:
extraVolumeMounts:
- name: custom-fonts
mountPath: /opt/cool/systemplate/tmpfonts
extraVolumes:
- name: custom-fonts
hostPath:
path: /path/to/custom/fonts
type: Directory
Hi Darshan,
It looks like these settings will help me to get the fonts in the editor.
This is how my values.yaml looks like in my test cluster.
collabora:
aliasgroups:
- host: http://webapp:8000
- host: https://test.casereditions.local
extra_params: --o:ssl.enable=false --o:ssl.termination=true --o:num_prespawn_children=4
server_name: test.casereditions.local
existingSecret:
enabled: false
secretName: ""
usernameKey: "username"
passwordKey: "password"
password: adminadmin
username: admin
env: []
autoscaling:
minReplicas: 1
# securityContext:
# privileged: true
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
replicaCount: 1
dynamicConfig:
ingress:
hosts:
- host: test.casereditions.local
paths:
- path: /
pathType: ImplementationSpecific
tls:
hosts:
- test.casereditions.local
secretName: test-casereditions
podLabels:
networking/data.egress: "true"
networking/internet.egress: "true"
networking/internet.ingress: "true"
networking/service.egress: "true"
networking/service.gress: "true"
networking/webapp.egress: "true"
networking/webapp.ingress: "true"
hi @jaapglasbergen How you are using Collabora Online is it any integration with any app like Nextcloud ?
We are using Collabora Online in our own application. We are building this app with a Django backend and a React frontend.
The editor is used by running it in a iframe within the app.
The Helm chart can typically handle both local paths and remote URLs for font configuration, but it depends on how the volume and configuration are set up in the chart. Here’s how each option works:
If you want to use a local path on the host machine where Kubernetes nodes are running, you can mount a directory into the container by specifying it in the extraVolumes
and extraVolumeMounts
configuration. This requires that the Kubernetes nodes have access to the local path you want to use.
For example:
extraVolumes:
- name: custom-fonts
hostPath:
path: /path/on/host/to/fonts
type: Directory
extraVolumeMounts:
- name: custom-fonts
mountPath: /opt/cool/systemplate/tmpfonts
In this setup, the local directory /path/on/host/to/fonts
will be mounted inside the container at /opt/cool/systemplate/tmpfonts
.
If the fonts are hosted on a remote server, you would need to download them as part of the container initialization or use a ConfigMap/Secret if feasible. Helm charts do not directly handle downloading files from remote URLs, so you would typically include a script in the Docker image or an init container that pulls fonts from a remote URL and places them in the appropriate directory.
For example, you could include an init container in your values.yaml
:
initContainers:
- name: fetch-fonts
image: busybox
command:
- wget
- -P
- /opt/cool/systemplate/tmpfonts
- "https://example.com/path/to/fonts/font.ttf"
volumeMounts:
- name: custom-fonts
mountPath: /opt/cool/systemplate/tmpfonts
hostPath
to mount local directories on the Kubernetes nodes.Check your Helm chart documentation to confirm support for extraVolumes
and extraVolumeMounts
, or consider modifying it to include this flexibility if it does not exist yet.
Thanks,
Darshan
@jaapglasbergenone more suggestion
Could you please take a look at this documentation: Collabora Online SDK - Configuration. You can use a JSON config to set up font configurations. This is how Nextcloud do there fonts configurations so maybe you can also take some inspiration from this and see how things go ?
Go through the steps and see if it aligns with your app setup.
Thanks Darshan,
I will change my setup with the info you provided.
Hi Darshan,
I changed my values.yaml like this.
collabora:
aliasgroups:
- host: http://webapp:8000
- host: https://test.casereditions.local
extra_params: --o:ssl.enable=false --o:ssl.termination=true --o:num_prespawn_children=4
server_name: test.casereditions.local
existingSecret:
enabled: false
secretName: ""
usernameKey: "username"
passwordKey: "password"
password: adminadmin
username: admin
env: []
extraVolumes:
- name: wopi-fonts
hostPath:
path: /run/desktop/mnt/host/c/k8s-volumes/wopi-fonts
type: Directory
extraVolumeMounts:
- name: wopi-fonts
mountPath: /opt/cool/systemplate/tmpfonts
autoscaling:
minReplicas: 1
resources: {}
replicaCount: 1
dynamicConfig:
ingress:
hosts:
- host: test.casereditions.local
paths:
- path: /
pathType: ImplementationSpecific
tls:
hosts:
- test.casereditions.local
secretName: test-casereditions
podLabels:
networking/data.egress: "true"
networking/internet.egress: "true"
networking/internet.ingress: "true"
networking/service.egress: "true"
networking/service.gress: "true"
networking/webapp.egress: "true"
networking/webapp.ingress: "true"
Helm is deploying this without a problem. But I don’t see the volume in the pod.
I am using the latest collabora-online Helm chart.
The path on the host is showing the folder with the extra fonts.
/ # ls -l /run/desktop/mnt/host/c/k8s-volumes/wopi-fonts
total 20132
-rwxrwxrwx 1 root root 2259616 Sep 4 23:11 GothicA1-Black.ttf
-rwxrwxrwx 1 root root 2285888 Sep 4 23:11 GothicA1-Bold.ttf
-rwxrwxrwx 1 root root 2279996 Sep 4 23:11 GothicA1-ExtraBold.ttf
-rwxrwxrwx 1 root root 2297240 Sep 4 23:11 GothicA1-ExtraLight.ttf
-rwxrwxrwx 1 root root 2296968 Sep 4 23:11 GothicA1-Light.ttf
-rwxrwxrwx 1 root root 2287684 Sep 4 23:11 GothicA1-Medium.ttf
-rwxrwxrwx 1 root root 2294192 Sep 4 23:11 GothicA1-Regular.ttf
-rwxrwxrwx 1 root root 2287416 Sep 4 23:11 GothicA1-SemiBold.ttf
-rwxrwxrwx 1 root root 2307184 Sep 4 23:11 GothicA1-Thin.ttf
/ #
But in the pod there is nothing under systemplate.
cool@wopi-client-collabora-online-666d54d55f-9dvv6:/$ ls -l /opt/cool/systemplate/
total 36
drwxr-xr-x 2 root root 4096 Oct 11 15:05 dev
drwxr-xr-x 5 root root 4096 Oct 11 15:05 etc
drwxr-xr-x 3 root root 4096 Oct 11 15:05 lib
drwxr-xr-x 2 root root 4096 Oct 11 15:05 lib64
drwxr-xr-x 2 root root 4096 Oct 11 15:05 lo
drwxr-xr-x 2 root root 4096 Oct 11 15:05 opt
drwxr-xr-x 3 root root 4096 Oct 11 15:05 tmp
drwxr-xr-x 4 root root 4096 Oct 11 15:05 usr
drwxr-xr-x 3 root root 4096 Oct 11 15:05 var
cool@wopi-client-collabora-online-666d54d55f-9dvv6:/$
Can you see what I am doing wrong?
I did some further research in this matter and I think the deployment.yaml has no code to handle the extraVolumes and extraVolumeMounts.
Am I correct in my conclusion?
@jaapglasbergen I’ve also done some research on this, and so far, I haven’t found a way to mount the font path. I’m consulting with others about possible solutions, and I’ll share any findings here soon.
Thanks,
Darshan
@darshan I made some changes to the deployment.yaml file and it is now mounting the proper folder to the /opt/cool/systemplate/tmpfonts folder.
I hope you guys can add this to the Helm chart.
deployment.yaml
{{- if eq .Values.deployment.kind "Deployment" -}}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "collabora-online.fullname" . }}
labels:
{{- include "collabora-online.labels" . | nindent 4 }}
spec:
minReadySeconds: {{ .Values.deployment.minReadySeconds }}
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
strategy:
type: {{ .Values.deployment.type }}
{{- if eq .Values.deployment.type "RollingUpdate"}}
rollingUpdate:
maxSurge: {{ .Values.deployment.maxSurge }}
maxUnavailable: {{ .Values.deployment.maxUnavailable }}
{{- end}}
selector:
matchLabels:
{{- include "collabora-online.selectorLabels" . | nindent 6 }}
type: main
template:
metadata:
annotations:
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
confighash: config-{{ .Values.collabora | toYaml | sha256sum | trunc 32 }}
cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
labels:
{{- include "collabora-online.selectorLabels" . | nindent 8 }}
type: main
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.deployment.hostAliases }}
hostAliases:
{{- toYaml . | nindent 8 }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "collabora-online.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.deployment.containerPort }}
protocol: TCP
{{- if .Values.probes.startup.enabled }}
startupProbe:
httpGet:
path: /
port: {{ .Values.deployment.containerPort }}
scheme: HTTP
failureThreshold: {{ .Values.probes.startup.failureThreshold }}
periodSeconds: {{ .Values.probes.startup.periodSeconds }}
{{- end }}
{{- if .Values.probes.liveness.enabled }}
livenessProbe:
httpGet:
path: /
port: {{ .Values.deployment.containerPort }}
scheme: HTTP
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
successThreshold: {{ .Values.probes.liveness.successThreshold }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
{{- end }}
{{- if .Values.probes.readiness.enabled }}
readinessProbe:
httpGet:
path: /
port: {{ .Values.deployment.containerPort }}
scheme: HTTP
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
successThreshold: {{ .Values.probes.readiness.successThreshold }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
{{- end }}
envFrom:
- configMapRef:
name: {{ include "collabora-online.fullname" . }}
env:
- name: username
valueFrom:
secretKeyRef:
{{- if (.Values.collabora.existingSecret).enabled }}
name: {{ .Values.collabora.existingSecret.secretName | quote }}
key: {{ .Values.collabora.existingSecret.usernameKey | quote }}
{{- else }}
name: {{ include "collabora-online.fullname" . }}
key: username
{{- end }}
- name: password
valueFrom:
secretKeyRef:
{{- if (.Values.collabora.existingSecret).enabled }}
name: {{ .Values.collabora.existingSecret.secretName | quote }}
key: {{ .Values.collabora.existingSecret.passwordKey | quote }}
{{- else }}
name: {{ include "collabora-online.fullname" . }}
key: password
{{- end }}
{{- with .Values.collabora.env }}
{{ toYaml . | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: tmp
mountPath: /tmp
{{- if .Values.collabora.extraVolumeMounts }}
{{ toYaml .Values.collabora.extraVolumeMounts | indent 12 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: tmp
emptyDir: {}
{{- if .Values.collabora.extraVolumes }}
{{ toYaml .Values.collabora.extraVolumes | indent 8 }}
{{- end }}
{{- end }}
values.yaml
---
# Default values for newchart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
image:
repository: collabora/code
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
terminationGracePeriodSeconds: 60
serviceAccount:
# Specifies whether a service account should be created
create: false
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
collabora:
# example to add aliasgroups
# - host: "<protocol>://<host-name>:<port>"
# aliases: ["<protocol>://<its-first-alias>:<port>, <protocol>://<its-second-alias>:<port>"]
aliasgroups: []
extra_params: --o:ssl.enable=false
# External hostname:port of the server running coolwsd.
# If empty, it's derived from the request (please set it if this doesn't work).
# May be specified when behind a reverse-proxy or when the hostname is not reachable directly.
server_name: null
existingSecret:
enabled: false
secretName: ""
usernameKey: "username"
passwordKey: "password"
password: examplepass
username: admin
env: []
extraVolumes:
- name: wopi-fonts
hostPath:
path: /run/desktop/mnt/host/c/k8s-volumes/wopi-fonts
type: Directory
extraVolumeMounts:
- name: wopi-fonts
mountPath: /opt/cool/systemplate/tmpfonts
prometheus:
servicemonitor:
enabled: false
labels: {}
rules:
enabled: false
additionalLabels: {}
defaults:
enabled: true
docs:
duplicated: 0
pod:
critical: 10
warning: 8
info: 5
sum:
critical: 500
warning: 200
info: 50
errorServiceUnavailable:
critical: 50
warning: 2
info: 0
errorUnauthorizedRequest:
observationInterval: "60m"
eventCounter: 8
errorStorageConnections:
critical: 50
warning: 2
info: 0
viewers:
pod:
critical: 100
warning: 80
info: 60
doc:
critical: 50
warning: 40
info: 30
sum:
critical: 15000
warning: 12000
info: 5000
additionalRules: []
grafana:
dashboards:
enabled: false
labels:
grafana_dashboard: "1"
annotations: {}
# Logging
# This HelmChart could also deploy Flow for the [Logging-Operator](https://kube-logging.github.io/docs/)
# Configuration is optimzed for deliever to elasticsearch
logging:
# -- Deploy Flow for logging-operator
enabled: false
# -- Enable record filter for record_modify to the [ElasticCommonSchema](https://www.elastic.co/guide/en/ecs/current/index.html)
ecs: false
# -- if an filter (here or global) for dedot is active - for disable set `null`
dedot:
# -- Add other filters to Flow
additionalFilters: []
# -- Flows localOutputRefs for use of Outputs
localOutputRefs: []
# -- Flows globalOutputRefs for use of ClusterOutputs
globalOutputRefs:
- "default"
podAnnotations: {}
podLabels: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# readOnlyRootFilesystem: false
# privileged: true
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 9980
annotations: {}
deployment:
# Use StatefulSet or Deployment
kind: Deployment
containerPort: 9980
type: RollingUpdate
minReadySeconds: 0
maxUnavailable: 0
maxSurge: 1
# info on how to use hostAliases: https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/
# note: different from aliasgroups
hostAliases: null
probes:
startup:
enabled: true
failureThreshold: 30
periodSeconds: 3
readiness:
enabled: true
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 30
successThreshold: 1
failureThreshold: 2
liveness:
enabled: true
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 30
successThreshold: 1
failureThreshold: 4
ingress:
enabled: false
className: ""
annotations: {}
# # nginx
# nginx.ingress.kubernetes.io/upstream-hash-by: "$arg_WOPISrc"
# # block admin urls from outside
# nginx.ingress.kubernetes.io/server-snippet: |
# location /cool/getMetrics { deny all; return 403; }
# location /cool/adminws/ { deny all; return 403; }
# location /browser/dist/admin/admin.html { deny all; return 403; }
#
# # HAProxy
# haproxy.org/timeout-tunnel: "3600s"
# haproxy.org/backend-config-snippet: |
# mode http
# balance leastconn
# stick-table type string len 2048 size 1k store conn_cur
# http-request set-var(txn.wopisrcconns) url_param(WOPISrc),table_conn_cur()
# http-request track-sc1 url_param(WOPISrc)
# stick match url_param(WOPISrc) if { var(txn.wopisrcconns) -m int gt 0 }
# stick store-request url_param(WOPISrc)
#
# # HAProxy - Community: https://haproxy-ingress.github.io/
# haproxy-ingress.github.io/timeout-tunnel: 3600s
# haproxy-ingress.github.io/balance-algorithm: url_param WOPISrc check_post
# haproxy-ingress.github.io/config-backend:
# hash-type consistent
# # block admin urls from outside
# acl admin_url path_beg /cool/getMetrics
# acl admin_url path_beg /cool/adminws/
# acl admin_url path_beg /browser/dist/admin/admin.html
# http-request deny if admin_url
#
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
replicaCount: 1
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 100
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 50
scaleDownDisabled: false
dynamicConfig:
enabled: false
logging:
enabled: false
ecs: false
dedot:
additionalFilters: []
localOutputRefs: []
globalOutputRefs:
- "default"
image:
repository: nginx
tag: 1.25
pullPolicy: IfNotPresent
replicaCount: 1
podAnnotations: []
podSecurityContext: {}
securityContext: {}
# configVolumeType: configMap # configMap or pvc
existingConfigMap:
enabled: false
name: ""
upload:
enabled: false
image:
repository: "twostoryrobot/simple-file-upload"
digest: 547fc4360b31d8604b7a26202914e87cd13609cc938fd83f412c77eb44aa1cc4
key: TESTKEY
pvc:
size: 1Gi
accessMode: "ReadWriteOnce"
# storageClassName: ""
service:
port: 8090
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
logging:
enabled: false
ecs: false
dedot:
additionalFilters: []
localOutputRefs: []
globalOutputRefs:
- "default"
containerPort: 80
probes:
startup:
enabled: true
failureThreshold: 30
periodSeconds: 2
readiness:
enabled: true
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 30
successThreshold: 1
failureThreshold: 2
liveness:
enabled: true
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 30
successThreshold: 1
failureThreshold: 4
env: []
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
service:
port: 8080
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
configuration: |
{}
trusted_certs_install:
enabled: false
trusted_certs: []
nodeSelector: {}
tolerations: []
affinity: {}
hii @jaapglasbergen i just check your deployment.yaml file.
What is reason behind removing this part ?
{{- if .Values.collabora.proofKeysSecretRef }}
- name: wopi-proof
mountPath: /etc/coolwsd/proof_key
subPath: proof_key
- name: wopi-proof
mountPath: /etc/coolwsd/proof_key.pub
subPath: proof_key.pub
{{- end }}
Also is it possible to mount local folder using helm chart ? Have you tried it ? Does the custom fonts are working now ?
I think the proofKeySecretRef was lost in the copy/paste. I didn’t remove it on purpose.
The change is only adding the 2 blocks for extraVolumes and extraVolumeMounts.
{{- if .Values.collabora.extraVolumeMounts }}
{{ toYaml .Values.collabora.extraVolumeMounts | indent 12 }}
{{- end }}
{{- if .Values.collabora.extraVolumes }}
{{ toYaml .Values.collabora.extraVolumes | indent 8 }}
{{- end }}
I mounted a local path with hostPath and this works fine. I run a local cluster on my workstation and mounted a folder from my C drive in the pod.
Unfortunately the custom fonts don’t work. If I link the fonts in /opt/cool/systemplate/tmpfonts the fonts are not visible in the fonts dropdown.
I also linked them in /usr/local/share/fonts/truetype/ and then I do see the fonts in the dropdown. However, if I select one of the fonts the cursor disappears from the editor. If I then click on a place in the editor the default font is selected again.
If I select a piece of text and then select the font from the dropdown the piece of text disappears.
@jaapglasbergen i think it’s a feature that is missing, Can you help me to file a GH issue ? Collabora Online Github
Thanks,
Darshan