OnlyOffice on k8s 部署指南

520 阅读3分钟

背景

最近项目上需要预览&编辑 Word 文档,在网上查阅一番后决定通过集成 OnlyOffice 服务来实现,设计思路如下:

  1. Word 文档存储在 minio 中,不直接对外暴露,上传、下载通过业务系统接口完成
  2. 前端集成 OnlyOffice 插件,传入业务系统上传、下载接口
  3. OnlyOffice 与业务系统接口交互
    1. 读取文档时,OnlyOffice 调用业务系统下载接口,下载接口里从 minio 读取文档输出到响应流
    2. 保存文档时,调用业务系统上传接口,上传接口里先从 OnlyOffice 读取最新数据,再上传至 minio

时序图如下:

sequenceDiagram
    participant 前端页面
    participant OnlyOffice服务
    participant 业务系统
    participant minio

    %% 预览文档流程
    rect rgba(200,220,255,0.5)
        Note over 前端页面,minio: 预览文档流程
        前端页面->>OnlyOffice服务: 1. 加载插件并打开界面
        activate OnlyOffice服务
        OnlyOffice服务->>业务系统: 2. 调用下载文档接口
        activate 业务系统
        业务系统->>minio: 3. 请求下载文档
        activate minio
        minio-->>业务系统: 4. 返回文档流
        deactivate minio
        业务系统-->>OnlyOffice服务: 5. 返回文档流
        deactivate 业务系统
        OnlyOffice服务-->>前端页面: 6. 加载文档到编辑器
        deactivate OnlyOffice服务
    end

    %% 保存文档流程
    rect rgba(180,255,200,0.5)
        Note over 前端页面,minio: 保存文档流程
        前端页面->>OnlyOffice服务: 1. 触发保存操作
        activate OnlyOffice服务
        OnlyOffice服务->>业务系统: 2. 调用保存文档接口
        activate 业务系统
        业务系统->>OnlyOffice服务: 3. 请求获取最新文档
        activate OnlyOffice服务
        OnlyOffice服务-->>业务系统: 4. 返回最新文档内容
        deactivate OnlyOffice服务
        业务系统->>minio: 5. 上传文档到minio
        activate minio
        minio-->>业务系统: 6. 返回上传成功
        deactivate minio
        业务系统-->>OnlyOffice服务: 7. 返回操作成功
        deactivate 业务系统
        OnlyOffice服务-->>前端页面: 8. 显示保存成功
        deactivate OnlyOffice服务
    end

将 OnlyOffice 部署到 K8S 中

OnlyOffice 版本是 7.5,由于项目环境是 K8S 集群,OnlyOffice 最好也能部署在 K8S 中,折腾一番后部署成功,以下步骤供有需要的小伙伴参考

挂载配置文件

OnlyOffice 基础配置在/etc/onlyoffice/documentserver/default.json中,在同级目录下还有其他配置文件,我选择使用production-linux.json文件,这个文件是提前从容器里复制出来,然后增加了如下配置

"request-filtering-agent" : {
  "allowPrivateIPAddress": true,
  "allowMetaIPAddress": true
}

说明:OnlyOffice 限制了私有IP,导致调用业务系统接口时报错,加上以上配置即可,也可以直接修改default.json里对应的配置,然后挂载default.json

完整 ConfigMap yaml 文件如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: onlyoffice-config
  namespace: onlyoffice
data:
  production-linux.json: |
    {
      "log": {
        "filePath": "/etc/onlyoffice/documentserver/log4js/production.json"
      },
      "storage": {
        "fs": {
          "folderPath": "/var/lib/onlyoffice/documentserver/App_Data/cache/files"
        }
      },
      "wopi": {
        "htmlTemplate" : "/var/www/onlyoffice/documentserver/web-apps/apps/api/wopi"
      },
      "services": {
        "CoAuthoring": {
          "server": {
            "newFileTemplate" : "/var/www/onlyoffice/documentserver/document-templates/new",
            "static_content": {
              "/fonts": {
                "path": "/var/www/onlyoffice/documentserver/fonts",
                "options": {"maxAge": "7d"}
              },
              "/sdkjs": {
                "path": "/var/www/onlyoffice/documentserver/sdkjs",
                "options": {"maxAge": "7d"}
              },
              "/web-apps": {
                "path": "/var/www/onlyoffice/documentserver/web-apps",
                "options": {"maxAge": "7d"}
              },
              "/welcome": {
                "path": "/var/www/onlyoffice/documentserver/server/welcome",
                "options": {"maxAge": "7d"}
              },
              "/info": {
                "path": "/var/www/onlyoffice/documentserver/server/info",
                "options": {"maxAge": "7d"}
              },
              "/sdkjs-plugins": {
                "path": "/var/www/onlyoffice/documentserver/sdkjs-plugins",
                "options": {"maxAge": "7d"}
              },
              "/dictionaries": {
                "path": "/var/www/onlyoffice/documentserver/dictionaries",
                "options": {"maxAge": "7d"}
              }
            }
          },
          "utils": {
            "utils_common_fontdir": "/usr/share/fonts"
          },
          "sockjs": {
            "sockjs_url": "/web-apps/vendor/sockjs/sockjs.min.js"
          },
          "request-filtering-agent" : {
            "allowPrivateIPAddress": true,
            "allowMetaIPAddress": true
          }
        }
      },
      "license": {
        "license_file": "/var/www/onlyoffice/documentserver/../Data/license.lic",
        "warning_limit_percents": 70,
        "packageType": 0
      },
      "FileConverter": {
        "converter": {
          "fontDir": "/usr/share/fonts",
          "presentationThemesDir": "/var/www/onlyoffice/documentserver/sdkjs/slide/themes",
          "x2tPath": "/var/www/onlyoffice/documentserver/server/FileConverter/bin/x2t",
          "docbuilderPath": "/var/www/onlyoffice/documentserver/server/FileConverter/bin/docbuilder"
        }
      },
      "SpellChecker": {
        "server": {
          "dictDir": "/var/www/onlyoffice/documentserver/dictionaries"
        }
      }
    }

存储卷

OnlyOffice 有以下几个目录需要挂载,详细配置请参考官方文档:helpcenter.onlyoffice.com/docs/instal…

目录说明
/data/logs/onlyoffice日志
/var/www/onlyoffice/Data证书
/var/lib/onlyoffice文件缓存
/var/lib/postgresql数据库

我这里的配置方式如下,仅供参考

  1. 日志、证书目录通过hostPath本地挂载
  2. 文件缓存通过pvc申请存储卷挂载
  3. 数据库连接外部 MySQL
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: onlyoffice-lib-pvc
  namespace: onlyoffice
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: cluster-nfs-storage

Deployment 配置文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: onlyoffice-ds
  namespace: onlyoffice
spec:
  replicas: 1
  selector:
    matchLabels:
      app: onlyoffice-ds
  template:
    metadata:
      labels:
        app: onlyoffice-ds
    spec:
      containers:
        - name: documentserver
          image: onlyoffice/documentserver:7.5
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
          env:
            - name: pod_name
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.name
            - name: TZ
              value: Asia/Shanghai
            - name: DB_TYPE
              value: mysql
            - name: DB_HOST
              value: "xxx.xxx.xxx.xxx"
            - name: DB_PORT
              value: "3306"
            - name: DB_NAME
              value: "onlyoffice"
            - name: DB_USER
              value: "root"
            - name: DB_PWD
              value: "123456"
            - name: JWT_ENABLED
              value: "false"
#            - name: JWT_SECRET
#              value: ""
          volumeMounts:
            - mountPath: /etc/onlyoffice/documentserver/production-linux.json
              name: config-volume
              subPath: production-linux.json
            - mountPath: /var/log/onlyoffice
              name: logdir
              subPathExpr: $(pod_name)
            - mountPath: /var/www/onlyoffice/Data
              name: datadir
              subPathExpr: $(pod_name)
            - mountPath: /var/lib/onlyoffice
              name: lib-volume
              subPathExpr: $(pod_name)
            - mountPath: /etc/localtime
              name: timezone
              readOnly: true
          resources:
            limits:
              cpu: 2
              memory: 4Gi
            requests:
              cpu: 2
              memory: 2Gi
          readinessProbe:
            httpGet:
              path: /healthcheck
              port: 80
            initialDelaySeconds: 30
            periodSeconds: 15
      volumes:
        - name: config-volume
          configMap:
            name: onlyoffice-config
        - hostPath:
            path: /data/logs/onlyoffice
            type: DirectoryOrCreate
          name: logdir
        - hostPath:
            path: /data/onlyoffice/Data
            type: DirectoryOrCreate
          name: datadir
        - name: lib-volume
          persistentVolumeClaim:
            claimName: onlyoffice-lib-pvc
        - hostPath:
            path: /etc/localtime
            type: ""
          name: timezone
      restartPolicy: Always

说明:

  1. 环境变量里配置了外部 MySQL,服务启动后会自动建库建表
  2. 没有启用 JWT 鉴权

SVC 服务

apiVersion: v1
kind: Service
metadata:
  labels:
    app: onlyoffice-ds
  name: onlyoffice-ds-svc
  namespace: onlyoffice
spec:
  ports:
  - name: "80"
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: onlyoffice-ds
  sessionAffinity: None
  type: ClusterIP

Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Forwarded-Prefix "/onlyoffice";
  labels:
    app: onlyoffice-ds
  name: onlyoffice-ds-ingress
  namespace: onlyoffice
spec:
  rules:
  - http:
      paths:
      - path: /onlyoffice(/|$)(.*)
        pathType: Prefix
        backend:
          serviceName: onlyoffice-ds-svc
          servicePort: 80

Ingress 配置中增加了路径前缀:/onlyoffice,且在 header 里携带 X-Forwarded-Prefix "/onlyoffice",这样前端请求可通过前缀路由到 onlyoffice 服务,如:http://ingress-ip/onlyoffice/web-apps/apps/api/documents/api.js

总结

依次执行上述 yaml 文件即可,另外,因 K8S 版本不同,个别语法关键字略有不同,请酌情参考