diff --git a/app/onlyoffice/README.md b/app/onlyoffice/README.md new file mode 100644 index 00000000..3a48441c --- /dev/null +++ b/app/onlyoffice/README.md @@ -0,0 +1,10 @@ +ONLYOFFICE Document Server +========================== + +Production running at office.hackerspace.pl. + +JWT secret kept in Kubernetes secrets. Can work with any nextcloud instance as long as the JWT secret is configured correctly. + +Has a volume for some persistent data - but this is mostly for caching. As far as I (q3k) undestand, these can be nuked with no repercussions, maybe apart from losing in flight edits. + +See [prod.jsonnet](prod.jsonnet) for more information. diff --git a/app/onlyoffice/prod.jsonnet b/app/onlyoffice/prod.jsonnet new file mode 100644 index 00000000..927d294d --- /dev/null +++ b/app/onlyoffice/prod.jsonnet @@ -0,0 +1,113 @@ +// ONLYOFFICE document server. +// JWT secret needs to be generated as follows per environment: +// kubectl -n onlyoffice-prod create secret generic documentserver-jwt --from-literal=jwt=$(pwgen 32 1) + +local kube = import "../../kube/kube.libsonnet"; +local policies = import "../../kube/policies.libsonnet"; + +{ + onlyoffice:: { + local oo = self, + local cfg = oo.cfg, + cfg:: { + namespace: error "cfg.namespace must be set", + image: "onlyoffice/documentserver:5.6.4.20", + storageClassName: "waw-hdd-redundant-3", + domain: error "cfg.domain must be set", + }, + + ns: kube.Namespace(cfg.namespace), + + pvc: oo.ns.Contain(kube.PersistentVolumeClaim("documentserver")) { + spec+: { + storageClassName: cfg.storageClassName, + accessModes: [ "ReadWriteOnce" ], + resources: { + requests: { + storage: "10Gi", + }, + }, + }, + }, + + deploy: oo.ns.Contain(kube.Deployment("documentserver")) { + spec+: { + template+: { + spec+: { + containers_: { + documentserver: kube.Container("default") { + image: cfg.image, + resources: { + requests: { memory: "4G", cpu: "100m" }, + limits: { memory: "8G", cpu: "2" }, + }, + env_: { + JWT_ENABLED: "true", + JWT_SECRET: { secretKeyRef: { name: "documentserver-jwt", key: "jwt", }}, + }, + ports_: { + http: { containerPort: 80 }, + }, + local make(sp, p) = { name: "data", mountPath: p, subPath: sp }, + volumeMounts: [ + // Per upstream Dockerfile: + // VOLUME /var/log/$COMPANY_NAME /var/lib/$COMPANY_NAME + // /var/www/$COMPANY_NAME/Data /var/lib/postgresql + // /var/lib/rabbitmq /var/lib/redis + // /usr/share/fonts/truetype/custom + make("log", "/var/log/onlyoffice"), + make("www-data", "/var/www/onlyoffice/Data"), + make("postgres", "/var/lib/postgresql"), + make("rabbit", "/var/lib/rabbitmq"), + make("redis", "/var/lib/redis"), + make("fonts", "/usr/share/fonts/truetype/custom"), + ], + }, + }, + volumes_: { + data: kube.PersistentVolumeClaimVolume(oo.pvc), + }, + }, + }, + }, + }, + + svc: oo.ns.Contain(kube.Service("documentserver")) { + target_pod:: oo.deploy.spec.template, + }, + + ingress: oo.ns.Contain(kube.Ingress("office")) { + metadata+: { + annotations+: { + "kubernetes.io/tls-acme": "true", + "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", + }, + }, + spec+: { + tls: [{ hosts: [cfg.domain], secretName: "office-tls" }], + rules: [ + { + host: cfg.domain, + http: { + paths: [ + { path: "/", backend: oo.svc.name_port, }, + ], + }, + }, + ], + }, + }, + + // Needed because the documentserver runs its own supervisor, and: + // - rabbitmq wants to mkdir in /run, which starts out with the wrong permissions + // - nginx wants to bind to port 80 + insecure: policies.AllowNamespaceInsecure(cfg.namespace), + }, + + prod: self.onlyoffice { + cfg+: { + namespace: "onlyoffice-prod", + domain: "office.hackerspace.pl", + }, + }, +}