1. 离线部署这件事,难的不是 Docker
内网环境里把 OnlyOffice 的文档服务跑起来,如果只看命令,一行docker run就完事了;真正耗时间的是前面那一堆准备工作。标题里说的“Docker + Windows + 离线”,这三个词叠在一起,意味着你手上没有可用的公网、没有能直接pull的镜像源、也没有随时能yum install的依赖仓库,所有物料都得靠一台能联网的机器提前搬到内网。我前后做过几次类似的交付,第一次踩的坑最多,镜像拷过去加载一半报磁盘空间不足,容器起来了但文档打开白屏,中文字体全是方块,改完字体又发现保存按钮点不动。这些问题单看都不复杂,堆在同一个下午就很考验心态。这篇内容讲的就是 OnlyOffice 文档服务在内网 Windows 宿主机上,用 Docker 离线跑起来的完整链路:从外网侧备料、镜像导出,到宿主机底座搭建、容器启动参数,再到字体、反向代理与后续的故障排查。适合正在做内网协同办公落地的人看,也适合第一次接触离线镜像搬运的新手照着抄。我不打算只给一份命令清单,因为命令你查文档就有,真正值钱的是“为什么这么配”和“哪一步最容易翻车”。
1.1 三个约束叠在一起会变成什么局面
先把场景说清楚。OnlyOffice 的文档服务(Document Server)本质是一个提供在线编辑能力的后端服务,浏览器打开一个 docx、xlsx、pptx,编辑、协作、保存、转 PDF,都靠它。它不是一个单文件程序,而是一整套服务集合,内部跑着转换服务、缓存、数据库、消息队列这些东西,全部打包在一个镜像里。官方文档给出的最简启动方式就是一条 docker 命令,但这个“最简”建立在三个前提上:能联网拉镜像、宿主机是 Linux、端口和域名可以随便调。内网 Windows 的场景把这三个前提全打破了。
第一,不能联网,意味着镜像、Docker 运行时本身、宿主机补丁包,全部要离线搬运。第二,Windows 做宿主机,意味着你用的不是原生 Linux 内核,而是通过一层虚拟化跑 Linux 容器,这层东西在离线环境下的安装顺序、内核组件版本匹配,都有讲究。第三,内网往往还有安全策略,端口不能随便开,域名要走内部解析,HTTPS 证书可能是自签的或者内部 CA 签的。三件事叠一起,排错的复杂度不是相加而是相乘:容器起不来,可能是镜像坏了,可能是虚拟化层没配好,也可能是端口被别的服务占了,你得一层一层剥。
我的经验是,把整件事拆成四个可以独立验证的阶段:物料是否正确、底座是否健康、容器是否起来、链路是否通。每个阶段有自己的验收标准,前一个不过关绝不往下走。很多人一上来就docker run,容器挂了就开始改参数,改到最后连问题出在哪一层都不知道。
1.2 版本与组件选型:稳比新重要
离线环境最大的特点是“改起来成本极高”。在线环境出问题,重拉一个镜像、换一个版本,十分钟的事情;离线环境要重新走一遍导出、传输、审核、导入的流程,可能是一天。所以选型的第一原则是保守。
镜像版本我一般不去追最新的大版本。做法是看发布节奏,选一个已经推出了一段时间、小版本迭代过几轮的稳定版,把镜像标签固定到具体的完整版本号,而不是latest。latest在离线场景里是个灾难,你今天导出的和三个月后别人导出的可能完全不是一个东西,出了问题没法复现。固定版本号之后,把镜像的摘要值一并记录下来,写进交付文档里,这是后面排查问题时唯一可靠的依据。
宿主机的 Docker 运行时同理。Windows 上跑 Linux 容器,主流路径是装一个带虚拟化后端的桌面版运行时,它内部依赖一套轻量的 Linux 子系统组件。这套组件的版本和宿主机系统版本有对应关系,新版本的系统配老组件,或者反过来,都可能出现启动卡住、容器网络不通的现象。我的做法是把运行时安装包和它依赖的内核更新组件一起下载,版本组合先在外网的测试机上跑通一遍,确认能正常docker run hello-world,再整体搬到内网。
还有一个容易忽略的点:宿主机的系统版本。老版本的 Windows 对虚拟化和容器的支持有差异,某些版本甚至需要额外开启特定功能才能跑起来。这个在离线环境里改起来很麻烦,因为开启功能可能需要系统安装介质。所以在动手之前先确认宿主机版本,不确定就换一台,别在这上面死磕。
2. 离线物料清单:把能下载的一次备齐
离线部署最痛苦的不是技术,是“又漏了一个”。我见过最典型的场景:镜像搬过去了,运行时装好了,容器启动成功,结果要配 HTTPS 的时候发现没有合适的证书工具,要改字体的时候发现中文字体文件还在外网机器上。来回折腾的沟通成本远比技术成本高。所以物料清单这一步,宁可多备,不要少备。
2.1 外网侧的准备动作
外网机器的作用是“把内网需要的一切变成文件”。先在那台机器上装好同版本的 Docker 运行时,然后按顺序做三件事:拉镜像、导出镜像、生成校验值。拉镜像的时候建议先docker images确认一下大小,再决定怎么传。这个镜像不算小,导出成 tar 之后体积会更大,如果传输通道有限制,可以考虑在导出时直接压缩。
# 外网机器上操作 docker pull onlyoffice/documentserver:8.0.1 docker images | grep documentserver # 直接导出并压缩,体积能小一半以上 docker save onlyoffice/documentserver:8.0.1 | gzip > onlyoffice-ds-8.0.1.tar.gz # 记录校验值,内网侧导入前必须核对 sha256sum onlyoffice-ds-8.0.1.tar.gz > onlyoffice-ds-8.0.1.sha256这里有个细节值得说:docker save加管道压缩,比先导出成 tar 再手动压缩要省事,也省一次磁盘读写。但要注意管道中途断开会导致文件不完整,所以导出完务必看一眼文件大小是否合理,再生成校验值。如果文件只有几百兆,而你知道这个镜像正常导出应该更大,那基本就是中断了。
镜像标签要写全。onlyoffice/documentserver:8.0.1是完整写法,不要简写成documentserver,因为导入之后本地镜像仓库里如果存在同名不同标签的镜像,简写会指向不确定的那个,容器可能跑到旧版本上去,这种问题排查起来非常费劲。
2.2 一份可照抄的物料清单
下面这张表是我自己用的清单,每次交付前逐项打勾。表里的“备注”列是我踩过坑之后加上的,不是凑数。
| 序号 | 物料名称 | 用途说明 | 备注 |
|---|---|---|---|
| 1 | 文档服务镜像压缩包 | 核心服务 | 固定完整版本号,附校验文件 |
| 2 | 容器运行时安装包 | 提供 Docker 能力 | 与宿主机系统版本匹配 |
| 3 | 虚拟化内核更新组件 | 运行时依赖 | 缺这个运行时可能装不上 |
| 4 | 中文字体文件(ttf/otf) | 避免文档显示方块 | 至少备常用办公字体 |
| 5 | 反向代理配置样例 | 统一入口与加密 | 纯文本,可直接改 |
| 6 | 内部证书文件 | HTTPS 使用 | 私钥单独管控 |
| 7 | 启动脚本与目录结构说明 | 减少人为失误 | 用脚本代替手敲命令 |
| 8 | 校验工具 | 校验文件完整性 | 系统自带即可 |
表格里第 3 项很多人会忽略。在纯离线环境里,如果运行时安装程序提示需要某个系统组件而本地没有,整个流程就卡死了。我一般会把可能用到的东西提前准备好,哪怕最后没用上,也比中途发现缺东西再走一遍审批流程强。
第 7 项也值得展开。容器启动命令参数多,手敲容易错,尤其是路径和大小写。Windows 环境下路径分隔符和大小写敏感度跟 Linux 不一样,把命令写成脚本文件,每次执行前检查一遍,能省掉大量低级错误。脚本文件要注意编码和换行符,从网页复制下来的脚本经常带着特殊字符,在命令行里执行会报奇怪的错。
2.3 传输与完整性问题
文件从外网搬到内网,中间可能经过多种介质:移动存储、内部文件交换区、带审批的传输通道。无论哪种,都有可能出现文件损坏或者被截断。这不是危言耸听,我遇到过压缩包在传输过程中被中间环节重新编码,导致解压报错的情况。
所以校验这一步不能省。外网侧生成校验值,内网侧导入前重新计算一次,两个值对上再往下走。计算校验值用系统自带命令就行,不需要额外装工具:
# 内网 Windows 侧计算校验值 Get-FileHash .\onlyoffice-ds-8.0.1.tar.gz -Algorithm SHA256如果发现值对不上,不要抱有“可能只是压缩包坏了但里面镜像是好的”这种侥幸心理,重新传一遍。镜像文件内部是分层的,某一段损坏可能导致导入时看起来成功,但运行到某个功能才报错,那种问题排查成本极高。
传输过程中还有一个细节:文件名不要用特殊字符,不要用中文,不要带空格。有些环节对文件名处理不规范,可能把文件改得面目全非。用纯英文加数字加短横线,最保险。
3. Windows 宿主上的运行时底座怎么搭
底座这一层是很多人翻车的地方,因为它不像容器那样有明确的报错,往往是“装完了但就是跑不起来”。我把它单独拎出来讲,是因为这一层的验收标准很清晰:能正常跑一个最小容器,并且容器能访问网络。达不到这两条,后面所有工作都是白费。
3.1 先确认容器类型:必须是 Linux 容器
文档服务的镜像基于 Linux,所以宿主机上的容器运行时必须工作在 Linux 容器模式下。Windows 上的运行时支持两种模式,默认可能停在另一种模式上,这时候你去docker run一个 Linux 镜像,会直接报“镜像操作系统不匹配”之类的错误。
切换模式的操作在运行时的托盘菜单里,点一下等它重启就行。但要注意,切换模式本质上是在切换底层虚拟化后端,这个过程在离线环境下可能因为缺少组件而失败。所以正确顺序是:先确认组件装全了,再切换模式,最后验证。
验证的方法很简单,跑一个最小镜像:
docker run --rm hello-world如果这个都跑不起来,别往下走了。常见原因是虚拟化功能没在系统层面开启,或者运行时依赖的组件版本不匹配。前者需要在系统设置里开启对应功能(可能需要重启),后者要回退到匹配的版本组合。
我个人的习惯是每次交付前,在新机器上先跑一遍这个验证,截图存证。一方面确认环境正常,另一方面出问题时有个基线可以对比。
3.2 离线安装运行时的实操顺序
在线安装一路下一步就完了,离线安装要按顺序来,顺序错了会报依赖缺失。我的顺序是这样的:
第一步,安装虚拟化内核更新组件,装完按要求重启。这个组件是运行时跑 Linux 容器的基础,缺了它运行时可能装得上但起不了容器。
第二步,安装容器运行时主程序。安装过程中可能会提示启用某些系统功能,全部同意。安装完成后不要急着启动,先确认安装目录下的文件完整。
第三步,首次启动运行时,等待初始化完成。这一步它会创建虚拟磁盘、初始化内部环境,耗时可能几分钟,别以为卡死了就去强制关闭。
第四步,验证模式是否为 Linux 容器,如果不是就切换。
第五步,跑最小镜像验证,同时验证网络(容器内能正常访问宿主暴露的端口)。
这五步里第三步最容易出问题。初始化过程中如果宿主机磁盘空间不足,或者杀毒软件在实时扫描虚拟磁盘文件,都可能卡住。我的做法是提前把运行时的数据目录加到杀毒软件白名单里,同时确保系统盘至少留出几十个 G 的空闲空间。这个空间不是给镜像用的,是给内部虚拟磁盘和镜像解压用的,很多人只算了镜像大小,忽略了运行时的开销。
3.3 资源与磁盘的预分配
资源分配这块,官方文档给出的最低要求是勉强能跑,实际用起来会很难受。文档服务在打开一个稍大的表格、或者做格式转换的时候,内存和 CPU 的瞬时占用会明显上升。我一般按“最低要求的两倍”来配,并且把资源上限在运行时的设置里显式写死,避免它把宿主机吃干。
磁盘方面,除了镜像本身,还要考虑三个增长点:文档缓存、日志、数据库数据。这三块都在容器内部的目录里,如果不做持久化挂载,容器一删数据全没;如果挂载了但没规划空间,跑一段时间就写满。我一般的做法是把数据目录放在容量较大的数据盘上,单独建一个目录,并且给这个目录设一个监控,使用率超过阈值就告警。
Windows 下的路径挂载有个常见坑:路径分隔符。运行时对 Windows 路径的处理跟 Linux 不一样,建议统一用正斜杠加盘符的形式,避免反斜杠被当成转义字符。另外路径里不要有空格和中文,有些版本的运行时处理不好,挂载会静默失败——容器起来了,但挂载目录是空的,数据全写在容器内部,你以为持久化了其实没有。这个问题我在第一次部署时就中招了,好在数据量小,重新挂载了一次。
4. 镜像导入与容器启动实操
前面都是准备,这一节开始真正落地。我把这一步拆成“导入校验、目录规划、启动参数、首启观察”四个动作,每个动作都有明确的判断依据。
4.1 加载镜像并核对
内网侧拿到压缩包后,先解压再加载。如果外网侧是带压缩导出的,内网侧要先解压成 tar,再执行加载:
# 解压(如使用压缩导出) tar -xzf onlyoffice-ds-8.0.1.tar.gz # 加载镜像 docker load -i .\onlyoffice-ds-8.0.1.tar # 核对镜像信息 docker images docker inspect onlyoffice/documentserver:8.0.1 --format "{{.Id}} {{.Created}}"加载过程可能比较慢,因为镜像层要逐层解包写盘。这时候如果磁盘空间不够,会报出明确的空间不足错误,看到这个错误不要反复重试,先清空间。另外加载过程中不要中断,中断可能导致镜像仓库里留下半截数据,后续docker images会显示成<none>的悬空镜像,占着空间还删不干净。
加载完成后核对两件事:镜像标签是否正确、镜像创建时间是否合理。创建时间能帮你判断拿到的是不是预期版本,避免版本搞错。
4.2 目录结构规划
在启动之前,先把宿主机上的数据目录建好。我习惯的结构是这样的:
D:/onlyoffice/ ├── data/ # 文档数据、证书 ├── lib/ # 内部数据库与索引 ├── log/ # 运行日志 └── fonts/ # 自定义字体四个目录各自对应容器内的一个挂载点。分开挂载而不是挂一个总目录,是为了后续备份和迁移方便:日志目录可以单独清理,字体目录可以单独更新,数据目录独立做备份策略。
建好目录之后,先确认运行时对这些目录有读写权限。Windows 下权限问题不像 Linux 那么直观,但确实存在:某些情况下容器内进程以非 root 用户运行,对挂载目录没有写权限,表现为服务能起来但保存文档报错。验证方法很简单,进入容器写一个测试文件,能写成功就说明权限没问题。
4.3 启动命令与参数逐条拆解
启动命令我建议写成脚本,下面是完整的一个示例。参数不是随便写的,每一条都有对应的问题背景:
docker run -d \ --name onlyoffice-ds \ --restart=always \ -p 8080:80 \ -e JWT_ENABLED=true \ -e JWT_SECRET=ChangeThisToALongRandomValue \ -e JWT_HEADER=Authorization \ -e TZ=Asia/Shanghai \ -v D:/onlyoffice/data:/var/www/onlyoffice/Data \ -v D:/onlyoffice/lib:/var/lib/onlyoffice \ -v D:/onlyoffice/log:/var/log/onlyoffice \ -v D:/onlyoffice/fonts:/usr/share/fonts/truetype/custom \ onlyoffice/documentserver:8.0.1参数逐条说明:
| 参数 | 作用 | 为什么这么配 |
|---|---|---|
--restart=always | 自动重启策略 | 宿主机重启后容器自动拉起,离线环境没人守着 |
-p 8080:80 | 端口映射 | 不占 80 端口,避免与宿主机已有服务冲突 |
JWT_ENABLED | 开启访问令牌校验 | 内网也不等于可信,接口裸露会被任意调用 |
JWT_SECRET | 令牌密钥 | 必须足够长且随机,与调用方保持一致 |
JWT_HEADER | 令牌传递头 | 与调用方的配置对齐,不一致会报鉴权失败 |
TZ | 时区 | 与调用方时区不一致会导致文档时间显示错乱 |
四个-v | 持久化挂载 | 数据、索引、日志、字体分离管理 |
令牌这块要重点说一下。开启之后,所有对文档服务的接口调用都要带上签名令牌,调用方(比如内部的协同平台)必须用同一个密钥去签。密钥不一致或者时钟偏差过大,都会导致鉴权失败,表现是文档打不开或者保存时报“权限不足”。我遇到过一个问题:密钥配对了,但宿主机时间比标准时间慢了十几分钟,令牌校验一直失败,排查了半天才定位到时间上。后来所有部署我都强制开启时区设置,并且把宿主机的自动时间同步也检查一遍。
端口映射的选择也有讲究。映射到高位端口再通过反向代理暴露,比直接占用 80/443 更灵活,后续换端口、加服务都不用动容器。但要注意反向代理到容器这一跳要支持长连接,文档服务传输大文件和保持编辑会话都依赖长连接,代理配置里如果没开对应的支持,会表现为“文档能打开但一直加载中”或者“编辑一段时间后断开”。
4.4 首启观察与状态确认
容器启动后不要马上去浏览器验证,先看日志。首次启动需要初始化内部环境,日志会刷比较久,这个阶段的错误信息最直接:
docker logs -f onlyoffice-ds正常情况下能看到一系列服务逐个启动的日志,最后停下来进入运行状态。如果日志里反复出现某个服务启动失败然后重试,那说明初始化没成功,常见原因是挂载目录权限不足或者磁盘空间不够。
日志稳定之后,用健康检查接口验证:
curl http://127.0.0.1:8080/healthcheck返回true说明服务内部状态正常。这一步很关键,它能区分“容器在跑”和“服务可用”,容器状态是运行中但健康检查失败的情况我见过不少,大多是资源不足或者挂载问题。
健康检查通过之后,再用浏览器访问首页。首页能打开只能说明前端资源加载正常,不代表编辑功能可用;真正的功能验证要拿一个实际的文档去打开、编辑、保存。这三步我都走一遍,全部通过才算启动成功。
5. 验证、字体与反向代理联调
服务跑起来只是开始,能不能用是另一回事。这个章节讲的三件事,是内网部署里最容易留下隐患的地方。
5.1 三层验证法
我的验证顺序是自下而上的三层:
第一层,容器内自检。进入容器,确认关键进程都在,日志没有明显报错,磁盘写入正常。这一层排除的是镜像和挂载问题。
第二层,宿主机访问。在宿主机上通过映射端口访问健康检查和首页,确认端口映射生效、防火墙没有拦截。这一层排除的是网络配置问题。
第三层,跨机访问。从内网另一台机器访问,确认服务对网段可见。这一层排除的是宿主机防火墙和网络策略问题。
三层全部通过,才算网络层面没问题。很多人卡在第二层就以为结束了,结果调用方在别的机器上访问不了,回头查半天发现是宿主机的入站规则没放行。
另外还要验证文档的实际编辑能力。拿一个包含中文、表格、图片的文档,打开、修改、保存、再打开,确认内容没丢失、格式没错乱。这个测试能顺带暴露字体问题——如果中文变成方块或者排版错乱,就是字体缺失。
5.2 中文字体:最容易被忽略的一环
文档服务内部自带的字体集里,中文字体覆盖不全。表现是打开文档时中文显示为方块、方框,或者字体被替换成别的样子导致排版跑偏。这个问题在内网环境特别常见,因为没法在线下载字体包。
解决办法是把常用的中文字体文件放到宿主机的字体目录,挂载进容器,然后触发字体缓存重建。命令是容器内自带的脚本:
docker exec onlyoffice-ds documentserver-generate-allfonts.sh执行完要重启容器,让缓存生效。这一步耗时跟字体数量有关,字体多的话可能几分钟,执行期间不要中断。
字体文件的选择上,办公场景至少要覆盖常用的黑体、宋体、仿宋、楷体这几类,否则别人发来的文档打开就是一排方块。字体文件本身要注意授权问题,只放自己有使用权的。
还有一个细节:字体目录是挂载进去的,但你更新字体文件之后,容器内的缓存不会自动刷新,必须手动执行重建脚本。如果改了字体没生效,先确认是不是漏了这一步。
5.3 反向代理与 HTTPS
直接暴露容器端口在内网里也能用,但不推荐。统一走反向代理有几个好处:可以挂加密证书、可以统一路径、可以在代理层做访问控制和限流。
代理配置里最关键的是三件事:转发真实来源信息、支持长连接、放开上传体积限制。文档编辑和转换涉及大文件传输,如果代理层的请求体大小限制没放开,表现是上传大文档时直接报错,小文档却正常,很容易误判。长连接的支持同样重要,缺少它会导致编辑会话频繁断开。
路径的处理也要注意。如果代理配了子路径,要让文档服务知道自己的对外路径,否则服务内部生成的资源地址会指向错误的位置,表现是首页白屏或者资源 404。这类配置一般在服务的配置文件里调整,改完需要重启容器。
加密这块,内网可以用内部签发的证书,也可以用自签证书。用自签证书的话,调用方需要信任该证书,否则浏览器会拦截混合内容,导致编辑功能异常。我的建议是统一用同一套内部证书,把根证书下发给所有客户端,比逐个加例外省事得多。
6. 常见故障排查速查
排查这类问题,最有效的方法不是猜,是缩小范围。先确认容器状态,再看日志,再验证健康检查,最后才去查业务功能。顺序乱了会浪费大量时间。
6.1 启动类问题
启动阶段的问题大多集中在资源、权限和镜像三块。下面这张表是我整理的高频问题对照:
| 现象 | 可能原因 | 排查动作 | 处理方式 |
|---|---|---|---|
| 镜像加载报空间不足 | 镜像层解压需要额外空间 | 查磁盘剩余 | 清理空间后重试,别中断 |
| 容器反复重启 | 内存不足或挂载失败 | 看docker logs首段 | 调大资源,检查挂载路径 |
| 容器运行但健康检查失败 | 内部服务未初始化完成 | 等待几分钟再查 | 持续失败检查权限 |
| 首页打不开 | 端口未映射或被占用 | netstat查端口 | 换端口重新映射 |
| 日志显示权限拒绝 | 挂载目录不可写 | 容器内写测试文件 | 调整目录权限 |
| 加载后镜像标签为 none | 加载被中断 | docker images查看 | 删除悬空镜像重新加载 |
表里第一行和最后一行其实是同一个问题的两个阶段。加载中断会留下不完整的镜像层,这些层占着空间但不可用,反复重试只会让空间越来越紧张。所以遇到空间不足,先清理再重试,不要连着点。
6.2 编辑与保存类问题
服务能访问但编辑功能不正常,问题一般在配置层。最常见的三个原因:令牌不一致、时区偏差、代理配置不当。
令牌不一致的表现是打开文档时报鉴权错误,或者保存时提示无权限。排查方法是核对调用方和服务端的密钥是否完全一致,包括大小写和特殊字符。时区偏差的表现更隐蔽一些,可能是令牌校验偶尔失败,也可能是文档里显示的时间不对。我一般是把宿主机的时间同步打开,同时容器里也显式设置时区,两头对齐。
代理配置问题的表现比较有规律:小文档正常、大文档失败,说明是体积限制;编辑一会儿就断开,说明是长连接没开;首页能开但资源报 404,说明是路径配置不对。按现象倒推配置项,比逐项检查快得多。
6.3 资源与性能类问题
跑一段时间之后开始变慢、卡顿、甚至服务无响应,通常是资源问题。文档服务的资源消耗跟使用强度强相关,多人同时编辑大文档时,CPU 和内存在短时间内会冲到很高。
我的处理思路是:先用容器状态命令看实时资源占用,确认是哪一项先到瓶颈:
docker stats onlyoffice-ds --no-stream如果内存接近上限,先考虑调高上限,而不是急着优化。内存不足会导致内部服务被杀掉重启,表现为编辑会话莫名中断。如果 CPU 长期跑满,要看是不是转换任务堆积,转换是 CPU 密集型操作,大文档集中转换时排队是正常现象,但如果排队一直不消化,就要考虑提升 CPU 配额或者错峰。
磁盘写满是最容易被忽略的。日志和数据都在挂载目录里,日志如果不做轮转,几个月就能吃掉大量空间。我的做法是给日志目录单独设监控,同时配置日志轮转,避免单文件无限增长。
7. 备份、升级与日常运维
离线环境的运维有个特点:出问题的代价高,所以预防性工作要做得更足。备份和升级这两件事,平时看不出价值,真出事的时候是救命的。
7.1 备份策略与恢复演练
需要备份的是三块:数据目录、内部数据库目录、配置文件。数据目录里有用户上传的文档和证书,数据库目录里有索引和元数据,配置文件里有密钥和路径。三块缺一不可,只备数据不备数据库,恢复之后文档列表是空的。
备份方式我一般用两种结合:定期全量打包,加上重要变更前的手动快照。全量打包在容器运行状态下做,可能有一致性问题,稳妥的做法是先停容器再打包,或者用文件系统层面的快照功能。对于内网这种变更频率不高的场景,停机打包完全可以接受。
恢复演练这事我一定要强调。备份文件躺在那里不代表能恢复,我见过备份脚本写错路径,跑了半年备份的全是空目录,真出事的时候才发现。演练方法很简单:找一台测试机,把备份文件还原,启动服务,验证文档能正常打开。这个过程走通一次,心里就有底了。
7.2 离线升级与回滚路径
升级的流程跟首次部署类似,但要更谨慎,因为涉及数据兼容。我的做法是:
第一步,在外网机器上导出新版本镜像,连同校验值一起搬到内网。
第二步,停掉现有容器,做一次完整备份。这一步不能省,升级失败要靠它回滚。
第三步,加载新镜像,用新版本启动一个新容器(换个名字和端口),让它连到同一份数据目录的副本上,验证功能是否正常。这一步叫并行验证,比直接覆盖升级安全得多。
第四步,验证通过后,停掉旧容器,把新容器切到正式端口,保留旧镜像一段时间作为回滚手段。
并行验证这一步很多人嫌麻烦跳过,直接原地升级,出问题再回滚。但离线环境下回滚也要时间,如果业务不能中断,并行验证是唯一稳妥的做法。数据目录的副本可以用文件复制实现,注意复制的时候容器要停掉,否则可能拷到不一致的状态。
7.3 几件我自己踩过的事
说几个具体的小事,都是文档里不会写、但实际会遇到的。
第一件是路径大小写。Windows 对路径大小写不敏感,但容器内部是敏感的。挂载的时候路径写错一个字母,可能不会报错,只是挂载失败,数据写进了容器内部。等你哪天真需要迁移,发现数据根本不在你以为的地方。我的对策是挂载之后立刻进容器验证目录内容,确认挂载生效。
第二件是脚本换行符。从各种地方复制来的启动脚本,可能带着特殊字符,在命令行里执行时报“命令不存在”或者参数解析错误。解决方法是把脚本另存为无特殊字符的纯文本,或者用专门的工具转换一下。这类问题排查起来很浪费时间,因为报错信息完全不指向真正的原因。
第三件是端口冲突。内网服务器上往往已经跑着别的服务,8080 这个端口被占用的概率不低。启动前先用端口查看命令确认一下,比启动失败再回头查省事。如果确实冲突,换个高位端口,同时记得反向代理配置也要同步改。
第四件是浏览器缓存。改了配置重启服务之后,如果浏览器还开着旧页面,可能看到的是缓存内容,误以为配置没生效。验证的时候强制刷新,或者换个无痕窗口,能排除这类干扰。
第五件是时间同步。前面提过,这里再强调一次:宿主机时间漂移会导致各种奇怪的问题,包括令牌校验失败、日志时间错乱、证书校验异常。内网环境如果不能连外部时间源,就在内网搭一个时间服务,所有机器统一对齐。
8. 最后说点配置之外的体会
内网离线部署这类活儿,技术难度其实不高,难的是把不确定性一个个消掉。我现在的习惯是,每做完一次就把遇到的问题和解决办法记下来,形成一份自己的检查清单。下次换一台机器、换一个版本,照着清单走,能省掉大半的返工。清单里最值钱的不是那些成功经验,而是失败记录——哪个参数漏了会出什么现象,哪个目录没建会报什么错,这些才是别人抄不走的东西。
还有一个建议,如果你准备做这件事,尽量在动手之前把“验收标准”跟相关方对齐。什么叫部署完成?首页能打开算不算?还是要所有人能正常编辑保存?标准不同,需要做的工作量差好几倍。提前说清楚,后面少很多扯皮。