背景
最近项目上需要预览&编辑 Word 文档,在网上查阅一番后决定通过集成 OnlyOffice 服务来实现,设计思路如下:
- Word 文档存储在 minio 中,不直接对外暴露,上传、下载通过业务系统接口完成
- 前端集成 OnlyOffice 插件,传入业务系统上传、下载接口
- OnlyOffice 与业务系统接口交互
- 读取文档时,OnlyOffice 调用业务系统下载接口,下载接口里从 minio 读取文档输出到响应流
- 保存文档时,调用业务系统上传接口,上传接口里先从 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 | 数据库 |
我这里的配置方式如下,仅供参考
- 日志、证书目录通过
hostPath本地挂载 - 文件缓存通过
pvc申请存储卷挂载 - 数据库连接外部 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
说明:
- 环境变量里配置了外部 MySQL,服务启动后会自动建库建表
- 没有启用
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 版本不同,个别语法关键字略有不同,请酌情参考