在线升级:替换一个正在运行的程序
0.1.3 起,后台「关于」页可以直接把 Lumo 升到新版本。这篇讲升级前做的四项检查、Linux 与 Windows 上替换文件的不同写法,以及一次在 1Panel 上判断失误之后改掉的判据。
单文件部署的好处之一是升级简单:换掉那个文件,重启。0.1.3 起,这件事可以在后台做:打开「关于」页,看到新版本,点「升级」,等它自己重启回来。
本站就是这样一路升上来的:0.1.4 到 0.1.5,再到 0.1.7。它跑在 1Panel 的 Go 运行环境里,这个环境恰好让在线升级的第一版判断错了,后面会讲。
升级前的四项检查
替换一个正在运行的程序,失败的代价是站点起不来,而这时后台也打不开了,没法在网页上补救。所以动手前有四项检查,任何一项不通过都不装:
- 必须有校验和。 发布里没有
checksums.txt不装,下载下来的包 SHA-256 对不上也不装。 - 先试跑新版本。 从包里解出新的二进制后,先执行一次
lumo version -json,确认它能在这台机器上运行,报出的版本号和要装的一致。校验和只能证明下载的东西没被改过,证明不了它能跑:CPU 架构拿错、被杀毒软件掏空、包里装的是别的版本,都会让校验和照样对得上。 - 先备份再替换。 把当前的二进制复制(不是移动)到
data/backups,替换失败就原样恢复。默认保留最近 3 份,可以在同一页里逐份删除。 - 确认换上去的文件不会消失。 如果替换之后,文件会随着容器重建一起丢掉,就不做就地升级,并把原因写在按钮旁边。
检查每 24 小时自动做一次,也可以手动点「检查更新」。GitHub 对未登录的接口请求按 IP 限流,每小时 60 次,所以间隔最短只能设到 1 小时。
替换文件:Linux 和 Windows 各写一份
Linux 和 macOS 上,用 rename 把新文件移到旧文件的位置是安全的,即使旧文件正在运行:内核认的是 inode,正在运行的进程继续使用旧 inode,新的路径指向新文件。
重启用 syscall.Exec:当前进程直接变成新程序,PID 不变。systemd 或 supervisor 看到的是同一个进程一直活着,不会把升级当成一次崩溃。Exec 必须等所有模块和数据库连接都关闭之后才调用,否则新进程会继承一堆半开的连接。
Windows 不允许覆盖正在运行的 .exe,但允许给它改名。所以先把旧文件改名为 lumo.exe.old,再把新文件移到原位置,任何一步失败就把名字改回去。那个 .old 文件要等下次启动时才能删掉。
后台上看到的进度
升级卡片上最大的一行是「当前版本 → 最新版本」。下载时显示百分比和字节数;校验和替换的耗时没法预估,只显示进行中。
重启期间,后台的接口本身是断开的,页面改为轮询 /healthz 等服务回来。升级是否完成,看的是服务报出来的版本号有没有变,而不是某个中间状态:本地网络下整个过程可能在一次轮询的间隔里就走完了,页面根本看不到「正在重启」那一拍。
一次判断失误
第一版的第四项检查是这样写的:如果运行在容器里,就不做就地升级。道理是官方 Docker 镜像里二进制在镜像层中,换掉之后容器一重建就回到旧版。
0.1.3 发布当天,这个判断在两个地方出了错。
第一处是 LXC。 最初把 LXC 和 OpenVZ 也算作容器,但它们大多是「系统容器」,就是按 VPS 卖给你的那台机器,文件系统是持久的,就地升级完全有效。0.1.4 把它们从容器判定里去掉了,原则也反过来:宁可漏判,不可误判。漏判由后面的回退检测兜底,误判则会让一台正常的机器直接失去这个功能。
第二处是 1Panel。 1Panel 的「运行环境 → Go」本身就是一个 Docker 容器,但站点目录是从宿主机挂进去的,二进制实际躺在宿主机的磁盘上,容器重建也不会丢。宝塔的 Go 项目管理器情况类似。
问题出在把「是不是在容器里」当成了「换掉的文件会不会消失」。这两个问题在官方镜像上答案相同,在面板部署上就分开了。
0.1.4 改成直接回答后一个问题:启动时读 /proc/self/mountinfo,找到覆盖程序所在目录的最长挂载点。如果是 /(容器自己的 overlay)或者 tmpfs,判定为不持久;如果是从宿主机挂进来的目录或卷,判定为持久。挂载点会显示在「关于」页的「部署形态」一栏里,本站显示的是「容器,程序文件在挂载卷上(/app)」。
官方镜像怎么升级
官方镜像里二进制在 / 下,进程以非 root 身份运行,程序目录写不进去,在线升级在那里不可用。这时「关于」页会直接给出该换成的镜像标签和一条可以复制的命令:
docker compose pull && docker compose up -d
另外附上 1Panel、宝塔里改镜像标签的位置,以及用 Watchtower 自动跟随新版本的办法。
版本回退检测
每次在线升级成功,Lumo 都会把版本号写进 data/update-state.json。这个文件在数据目录里,活得比容器长。
启动时如果发现正在运行的版本比记录里的旧,就在日志里记一条警告,并在「关于」页写明装过哪个版本、现在运行的是哪个,提醒多半是容器被重建过。主动降级也会触发这条提示,这没有问题,它陈述的就是事实,再升一次就消失了。
评论
还没有评论,来说两句。