06-成品-群晖SPK打包与格式排查法
一、适用场景
为群晖 DSM 7 制作 .spk 套件包;或手动安装时 DSM 在选完文件阶段就弹「套件文件格式不正确。请联系套件开发人员。」需要排查。
适用前提:不走 Docker 的官方套件路线,纯 Python 载荷(本例为 HFMS 服务端)。
二、操作步骤
- 外层 tar 结构(决定性):在暂存目录内显式列出条目名,
INFO必须是第一个:
tar --force-local -b 20 -cf xxx.spk INFO package.tgz scripts conf PACKAGE_ICON.PNG PACKAGE_ICON_256.PNG
(Git Bash 下--force-local用于规避D:被当成网络主机名。) - 内层
package.tgz:承载载荷,内部顶层目录命名统一用./前缀:
./app ./data ./客户数据源 ./backups ./logs(postinst按此取路径)。 - INFO 字段语义与合法值(
程序源代码/deploy/synology/spk/INFO):
-package全小写标识;version只接受x.y.z或x.y.z-修订号(见反例避雷);
-arch="noarch":纯 Python 载荷不挑架构,勿填具体 CPU 型号;
-os_min_ver="7.0-40000":DSM 最低版本门槛,填高会导致老 DSM 直接拒装;
-adminport/adminurl/adminprotocol:决定套件中心「打开」按钮跳到哪里,
填了才有网页入口(本例adminport="8765"+adminurl="/"+adminprotocol="http");
-maintainer会明文显示在套件中心,样例中一律降敏,真名只留在目标机本地配置里;
- 行尾必须 LF、无 BOM(CRLF 或 BOM 会导致 DSM 解析失败)。 conf/privilege权限模型(决定能不能装上):
json { "defaults": { "run-as": "package" } }
未签名包声明 root 会被 DSM 拒绝;必须run-as: package(以套件自有用户运行)才能走「手动安装」
(接受「发布者不受信任」警告)。postinst负责把载荷从@appstore/hfms移到/volume1/hfms并
chown给套件用户;postuninst保留/volume1/hfms不删 —— 重装对真实数据安全。
锚点:程序源代码/deploy/synology/spk/conf/privilege。- 大包必做瘦身:先用
du -sh找出占绝对比重的静态资源目录(本例客户数据源5.2G,占载荷 99.4%),
单独移出载荷,只留app+data打精简包;安装后再单独拷贝该目录。 - 上传前自检:
tar -tvf xxx.spk确认首条为INFO、图标在列、条目无./前缀;
上传到 NAS 后核对文件大小(最好再核 SHA256)与本地一致。 - 精简包安装后,把移出的资源目录拷回目标路径(File Station 拖拽 /
scp -r/ U 盘);
postinst对缺失目录有守卫时,"没拷"不会让安装失败,但功能会缺(本例制度检索为空)。 - 包内排查穷尽(三层证据法)——当结构看着都对、却仍报错时,用它证明"包本身无罪",避免在同一个地方反复打转:
- ① tar 头逐字段比对:与已知可装版本比 mode/uid/gid/typeflag/magic/version/uname/gname/prefix;
- ② 全部生命周期脚本sh -n语法校验,并确认 LF、无 BOM、无 NUL、shebang 正常;
- ③ INFO 逐字节比对:确认差异只剩 version 数字本身。
三层全过 → 结构无罪,变量必在包之外(传输链路、宿主、载荷体积)。 - 基线对照包(控制变量法)——当"能装的旧包"与"失败的新包"差异项 ≥2 个时,用已知可用版本的
INFO+ 旧脚本 + 精简载荷重新组一个对照包:
- 装得上 ⇒ 问题在新改的脚本/版本号;
- 装不上 ⇒ 问题在 DSM 侧或传输环节,与本次改动无关。
锚点:暂存程序源代码/deploy/synology/spk_ctl/,产物群晖安装包/hfms-ds418play-基线对照-20261016.spk。 - 真机验证三件套取证法(v1.3 新增,2026-10-20 实证)——装机成功的判定不能只靠对方一句「装上了」,
必须由验证人回传下列三项可核验证据,缺一不视为闭环:
- ① 套件中心「已安装」列表截图:要能同时看到套件名称、图标、安装日期,且最好与另一个已知正常的套件同框(可作时间对照);
- ② 服务端口可达证据:http://<NAS内网IP>:<adminport>能打开登录页(本例:8765);
- ③ 包指纹对齐:回传所装包的精确字节数(本例 slim-20261020 =10,649,600 B),与本地产物核对,
确认装的正是本次这一版,而不是旧包或中转改名后的包。
三项齐全 → 才可把「待真机复测」从待办中划掉,并连锁订正下游产物(README 批注、评分报告复评、技能包战绩段)。
锚点:程序源代码/deploy/synology/README_SPK手动安装.mdL3-5(「✅ 真机验证通过(2026-10-20)」批注)。
三、注意边界
- DSM 7 不要在 INFO 里声明
install_dep_packages:社群源包名(如python313)与官方Python3不匹配会被拦截;
改由套件脚本绝对路径扫描解释器(/usr/local/bin/python3*、/var/packages/*/target/bin/python3*)。 - 手工上传未签名包会提示「此套件来自不受信任的发布者」→ 点「仍要安装」,属正常。
- 未签名包严禁在
conf/privilege里声明 root:会被 DSM 直接拒绝,且报错信息不指向权限配置,极难定位。 INFO的maintainer与description会明文展示在套件中心 → 样例与交付文档一律降敏,不得带入真名。- 精简包必须保证
postinst对缺失目录有守卫:[ -d "$SRC/XXX" ] && mv "$SRC/XXX" "$DST/XXX",缺失即跳过。 - 套件 UI 是网页应用:套件中心只有 启动/停止/日志;真正后台在
http://<NAS内网IP>:<adminport>。
QuickConnect 中继不代理该端口(只转发 DSM 自身 5000/5001),所以*.quickconnect.cn:<端口>打不开属正常,不是故障。 - 先问清传输路径再下结论:同一份包,走「外网网页上传」和走「QQ/微信传回本地再局域网上传」,嫌疑对象完全不同。v1.0 曾因未确认路径而误判(见反例避雷第一条)。
- ★修复完成到真机验证之间存在时差(v1.3 新增):本例 10-15 修完四段版本号、10-16 规范 tar 结构并出精简包,
直到 10-20 才由用户在异地真机装成功,期间 5 天处于「修了但没验证」状态。
这段时间应把结论挂起为待验证项,而不是当成「修复失败」继续推翻重做——后者正是本例 5 天里反复排查的浪费所在。 - ★验证人不是打包人时,证据标准要提高(v1.3 新增):跨地/跨账号验证,对方只能看到界面结果,
看不到你的排查过程;因此必须用「三件套」这种可回传、可核的事实,而不是「能装了」这类总结性陈述。 - 装机闭环后要连锁订正下游产物(v1.3 新增):至少四处——README 头部批注、评分报告的部署/打包维复评、
技能包战绩段、当日记忆日志;只更新一处会造成「文档说没装上、真机已装好」的口径冲突。
方法见00-总纲-前序结论证伪与产物连锁订正法。
四、反例避雷
- ✗
version写成四段1.1.20261015.2→ 被判格式不正确。必须x.y.z或x.y.z-修订号(官方示例0.0.1-0001)。 - ✗
install_dep_packages="Python3"的精确包名陷阱(2026-10-15 实证):
DSM 按精确包名解析依赖,社群源 SynoCommunity 的包名是python313,与官方Python3对不上
→ 用户在套件中心直接被弹「请先安装以下套件:Python3」,而这个包装不上(用户只有python313)
→ 整包无法安装。修法:删除install_dep_packages/support_dep_packages,
改由preinst打提示(exit 0不阻断),解释器交给start-stop-status绝对路径扫描。 - ✗
tar -cf x.spk -C dir .→ 条目带./前缀且顺序随机,DSM 必拒。必须显式列条目名。 - ✗ INFO 用 CRLF 行尾或带 BOM → 解析失败。
- ✗ 【v1.0 错误结论,已撤回】 ~~GB 级包从外网 / QuickConnect 中继经网页上传 → 极易截断 → 报「格式不正确」~~。
真实链路经用户澄清为:远程用 QQ 把 spk 传回本地电脑,再由该电脑在局域网内上传。
该假说与实际情况不符,本版撤回;保留的通用结论是——任何经过中转(QQ/微信/网盘/U 盘拷贝)的文件,落地后都要先核大小与哈希,而不是跳过这步去猜打包格式。 - ✗ 只在包内找原因、不核落地文件:差异对比做到"12 个条目 10 项一致"仍可能白做,因为比的是本地文件,而 DSM 收到的是中转后的文件。
- ✗ 把「已修复但未验证」当成「修复无效」继续推倒重来(v1.3 新增,2026-10-15 至 10-20):
包侧三层证据(tar 头逐字段 / 脚本sh -n/ INFO 逐字节)在 10-16 已证明结构无罪,
但真机反馈迟迟不来,于是又回到打包侧反复自查 5 天。正确做法是停手挂起 + 明确触发条件
(「等对方真机装一次」),而不是在同一层继续加码排查。 - ✗ 只凭「装上了」三个字就关闭待办(v1.3 新增):无法确认装的是哪一版、服务是否真起来。
本例靠三件套才把「装的是 slim-20261020(10,649,600 B)」与「:8765登录页可达」两件事钉死。 - 排错顺序(务必按序,v1.1 修正):
① 核对落地文件完整性(大小 + SHA256,尤其经过 QQ/微信/网盘/U 盘中转);
② 确认扩展名确为.spk(中转工具可能改名或加后缀);
③ 查INFO的version格式(须x.y.z);
④ 查 tar 结构(INFO 居首、无./前缀);
⑤ 最后才怀疑脚本与载荷,并用基线对照包做控制变量验证。
⑥(v1.3 增补)以上五步全过仍失败 → 进入挂起待验证状态,去补真机证据,不要在包内继续打转。
五、代码锚点 / 实战战绩
锚点:
- 程序源代码/deploy/synology/spk/INFO(version="1.1.20261016")
- 程序源代码/deploy/synology/spk/scripts/start-stop-status(Python 绝对路径扫描 + 补 LD_LIBRARY_PATH +
setsid 脱离 DSM 进程组 + 端口探针判就绪 + [START][ERR] 诊断输出;详见 06-成品-受限宿主守护进程防回收启动法)
- 程序源代码/deploy/synology/spk/scripts/postinst(守卫式 mv + 赋权给套件用户)
- 暂存:程序源代码/deploy/synology/spk/(完整)、spk_slim/(精简)、spk_ctl/(基线对照)
- 产物:群晖安装包/hfms-ds418play-slim-20261016.spk、hfms-ds418play-full-20261016.spk、
hfms-ds418play-基线对照-20261016.spk
- 程序源代码/deploy/synology/spk/conf/privilege(run-as: package 非 root 模型)
- 文档:程序源代码/deploy/synology/README_SPK手动安装.md(L3-5 真机验证批注)
- 附包只读自检:scripts/scan_spk.sh
战绩:
- 2026-10-14:按「INFO 三件套 + run-as: package 非 root」配置打出的 4.0GB 首版成功装上(用户确认),
证明该字段组合与权限模型在本机型/DSM 7.4 上可用。
- 2026-10-15:修掉四段版本号;移除 install_dep_packages 消除「没有 Python3」拦截,用户随后装上安装成功。
- 2026-10-16:精简包 10,721,280 B(10.7MB),较完整包 4,254,750,720 B 缩小约 400 倍;完整包重建耗时 28 秒。
- 2026-10-16:用「差异对比法」比对能装与失败的两个包——12 个条目中 10 项完全一致(含 4.25GB package.tgz 大小/权限/顺序),
tar 归档格式亦完全相同(标准 ustar、无 GNU 扩展头)→ 排除格式本身。
- 2026-10-16(同日修正):进一步做包内排查穷尽——tar 头逐字段一致、5 个生命周期脚本 sh -n 全通过、
INFO 仅 version 数字不同(354 字节同长、LF、无 BOM)→ 确认包结构与语法均无罪。
随后经用户澄清传输链路,撤回「QuickConnect 截断」假说,改列三条指纹供本地比对。
- ★2026-10-20 真机装机成功(本技能结论正式闭环):用户在异地 DS418play(DSM 7.4-90075,另一账号)实机安装
hfms-ds418play-slim-20261020.spk(10,649,600 B,较 20261016 版 10,721,280 B 小 71,680 B)安装成功。
三件套证据:① 套件中心「已安装」列表出现「家庭管理系统 HFMS」(房子+人形图标,日期 2026-10-20,与另一已知套件同框);
② http://<NAS内网IP>:8765 登录页可打开;③ 包指纹与本地产物对齐。
结论:v1.0~v1.2 的「包本身干净」判断被真机证实;最终有效修复=INFO.version 四段改三段 +
规范外层 tar(INFO 首条目、无 ./ 前缀、显式列条目)+ 精简包(10MB 级,任何链路稳定上传)。
「传输截断」假说已于 v1.1 撤销,本次再次确认无误。
- 同日连锁订正:README_SPK手动安装.md 头部加「✅ 真机验证通过(2026-10-20)」批注;
进度评估报告的部署/打包两维进入复评待办(预计总分 79 → 85±)。
六、关联笔记
- 与
06-成品-部署与开机自启SOP互补(那是常驻与自启,这是打包载体与上传链路)。 - 与
06-成品-受限宿主守护进程防回收启动法串联:先装得上(本技能),再起得来(那个技能)。 - 与
04-开发-程序版本号多处置同步SOP配套(版本号格式即出自 INFO 规范)。 - 与
06-成品-Windows双形态安装包构建法同理:GB 级产物先想"能不能只传必要部分",而不是硬传。 - 与
05-测试-QA测量环境隔离与失真排除法方法论同源:差异对比 + 控制变量,先证伪再定位。 - 与
06-成品-部署目标机硬件规格核实与参数联动法串联:规格决定WORKERS/能力裁剪,本技能决定包载体与安装链路。 - 与
00-总纲-前序结论证伪与产物连锁订正法串联(v1.3 新增):2026-10-20 的装机成功正是「新证据到来 →
四类影响面连锁订正」的实例——订正面包括代码配置、文档手册(README 批注)、技能包(本包战绩段与结论)、
记忆与评分报告。本包内的「撤回说明 + 订正过程 + 版本记录」即为该方法要求的三件套。 - 与
05-测试-已知可用基线差异对比与变量收敛排查法串联:第 8、9 步的穷尽与对照,是它的域内实例化。
七、版本记录
- v1.0(2026-10-16):首版。含外层 tar 结构、INFO 规范、瘦身法、格式排查四步法。
- v1.1(2026-10-16):① 撤回「QuickConnect 中继上传被截断」错误结论(与实际传输链路不符);
② 新增「包内排查穷尽三层证据法」与「基线对照包控制变量法」两个操作步骤;
③ 修正排错顺序为五步,把"落地文件完整性 + 扩展名"提到最前;
④ 注意边界新增「先问清传输路径再下结论」;⑤ 战绩补记同日证伪过程与三个包的体积指纹,并如实标注真机复测待办。 - v1.2(2026-10-17):① 操作步骤新增「INFO 字段语义与 conf/privilege 权限模型配置」(第 3 步扩写 + 新增第 4 步),
补齐 v1.0~v1.1 从未覆盖的arch=noarch/os_min_ver/adminport三件套与run-as: package非 root 权限模型;
② 注意边界新增「未签名包严禁声明 root」与「maintainer 字段含真名须降敏」两条;
③ 反例避雷新增install_dep_packages精确包名拦截的完整因果链(v1.1 只在注意边界提过一句);
④ 战绩补记 2026-10-14 首个可装版本与 2026-10-15 移除依赖声明后装上的两次实证;
⑤ 附包scripts/scan_spk.sh原样继承,未改动。 - v1.3(2026-10-21):① 操作步骤新增第 10 步「真机验证三件套取证法」(列表截图 + 端口可达 + 包指纹对齐),
修正此前「装机成功」无取证标准的缺口;
② 注意边界新增三条——「修复完成到真机验证存在时差,应挂起而非推翻重做」、
「验证人不是打包人时证据标准要提高」、「装机闭环后须连锁订正四处下游产物」;
③ 反例避雷新增两条——「把已修复未验证当成修复无效而反复自查(本例空转 5 天)」、
「只凭一句装上了就关闭待办」,并在五步排错顺序后增补第 ⑥ 条「进入挂起待验证」;
④ 战绩正式闭环:补记 2026-10-20 slim-20261020(10,649,600 B)真机装机成功与三件套证据,
划掉 v1.1 起的「待真机复测」待办,确认有效修复为「version 三段 + 规范 tar + 精简包」;
⑤ 关联笔记新增与00-总纲-前序结论证伪与产物连锁订正法、05-测试-已知可用基线差异对比与变量收敛排查法的串联;
⑥ 附包scripts/scan_spk.sh原样继承,未改动。
旧包 v1.2 已备份.workbuddy/trash_2026-10-21/。