docs(arch-atlas): 运维域图说金样板——架构图集首件(8图:4 SVG+3 Mermaid+1单源引用)

第一个域样板,验收通过作扇出克隆标杆。house style 沿用金样板;
状态纪律到位(观测=接/k3s=缓,图顶状态约定条+元素级实心 vs 虚线);
单源引用(图1四机只链 README 不抄);frontmatter 防漂移门记三源档 commit hash。
4 张 SVG 经脚本核:XML 良构、零溢出、脚注映射+状态齐。PNG 留 mini-desktop 后续转。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
zizi 2026-06-22 11:30:43 +00:00
parent 3c008fb847
commit 891a5777c2
5 changed files with 712 additions and 0 deletions

View File

@ -0,0 +1,100 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 940" font-family="-apple-system,'PingFang SC','Microsoft YaHei',Segoe UI,sans-serif">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#334155"/></marker>
<marker id="arrowB" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#64748b"/></marker>
<style>
.t{fill:#0f172a}.mut{fill:#475569}.sm{font-size:12px}.xs{font-size:11px}
.h1{font-size:24px;font-weight:700}.h2{font-size:14px;font-weight:700}.lbl{font-size:13px;font-weight:600}
.req{stroke:#334155;stroke-width:1.8;fill:none}.ret{stroke:#64748b;stroke-width:1.5;fill:none;stroke-dasharray:6 4}
.life{stroke:#94a3b8;stroke-width:1.4;stroke-dasharray:3 4}.badge{font-size:10.5px;font-weight:700}
</style>
</defs>
<rect x="0" y="0" width="1480" height="940" fill="#f8fafc"/>
<text x="40" y="38" class="t h1">图 2 · 部署链push → pull → 重建 → 验门</text>
<text x="40" y="58" class="mut sm">内网无自建 CI人工经标准序在 mini-desktop 完成。实线=同步动作;灰虚线=回执/拉取。橙框=隔离验证安全变体(新 JAR 先在 :48090 验全live :48080 全程不动)。</text>
<!-- 泳道头 -->
<rect x="50" y="78" width="260" height="52" rx="10" fill="#e2e8f0" stroke="#0f172a" stroke-width="2"/>
<text x="180" y="100" text-anchor="middle" class="t lbl">lili-mac开发机·ARM</text>
<text x="180" y="119" text-anchor="middle" class="mut xs">出 JAR 架构中立 · 不进调度</text>
<rect x="380" y="78" width="260" height="52" rx="10" fill="#fef9c3" stroke="#ca8a04" stroke-width="2"/>
<text x="510" y="100" text-anchor="middle" class="t lbl">Aliyun Gitea中转</text>
<text x="510" y="119" text-anchor="middle" class="mut xs">:2222 push · :3000 匿名读</text>
<rect x="710" y="78" width="300" height="52" rx="10" fill="#dcfce7" stroke="#16a34a" stroke-width="2"/>
<text x="860" y="100" text-anchor="middle" class="t lbl">mini-desktop权威验收·x86</text>
<text x="860" y="119" text-anchor="middle" class="mut xs">构建 + 隔离验证实例 :48090</text>
<rect x="1130" y="78" width="300" height="52" rx="10" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
<text x="1280" y="100" text-anchor="middle" class="t lbl">live 后端 :48080</text>
<text x="1280" y="119" text-anchor="middle" class="mut xs">在跑的服务 · 验全才切</text>
<!-- 生命线 -->
<line x1="180" y1="130" x2="180" y2="838" class="life"/>
<line x1="510" y1="130" x2="510" y2="838" class="life"/>
<line x1="860" y1="130" x2="860" y2="838" class="life"/>
<line x1="1280" y1="130" x2="1280" y2="838" class="life"/>
<!-- ① push -->
<line x1="180" y1="166" x2="508" y2="166" class="req" marker-end="url(#arrow)"/>
<text x="186" y="160" class="xs t">① git push默认远程 :2222</text>
<text x="186" y="184" class="xs mut">scp/rsync 源码树被分类器拦 → 必须走 Gitea 中转;同仓 push 串行(撞 ref 锁)</text>
<!-- ② pull -->
<line x1="510" y1="216" x2="862" y2="216" class="ret" marker-end="url(#arrowB)"/>
<text x="540" y="210" class="xs mut">② HTTP :3000 匿名 clone / pull只读端口非 SSH</text>
<!-- ③ reset+build -->
<rect x="725" y="240" width="270" height="44" rx="8" fill="#ffffff" stroke="#16a34a" stroke-width="1.6"/>
<text x="735" y="260" class="xs t">③ git reset --hard origin/dev/2.0.0</text>
<text x="735" y="277" class="xs t">  mvn clean install → 出 fat JAR</text>
<!-- ④ 字节码实证 -->
<rect x="725" y="296" width="270" height="40" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="1.6"/>
<text x="735" y="315" class="xs t">④ 字节码实证unzip -p 核 .class 含本次改动</text>
<text x="735" y="330" class="xs mut">防「构建源 ≠ 运行的 JAR」翻车</text>
<!-- 隔离验证安全变体框 -->
<rect x="700" y="352" width="600" height="232" rx="10" fill="none" stroke="#ea580c" stroke-width="1.8" stroke-dasharray="6 4"/>
<text x="712" y="372" class="lbl" fill="#ea580c">隔离验证安全变体(高风险 / 整机变更走这条)</text>
<!-- ⑤ 起隔离实例 :48090 -->
<rect x="725" y="386" width="270" height="40" rx="8" fill="#ffffff" stroke="#16a34a" stroke-width="1.6"/>
<text x="735" y="405" class="xs t">⑤ 新 JAR 起隔离实例 :48090</text>
<text x="735" y="420" class="xs mut">live :48080 全程不动</text>
<!-- ⑥ 隔离验全 -->
<path d="M 860,448 q 56,0 56,15 q 0,15 -54,15" class="req" marker-end="url(#arrow)"/>
<text x="922" y="468" class="xs t">⑥ 在 :48090 验全health 200 · 四模板就绪 · Flyway up-to-date · 冒烟门 12 项</text>
<!-- ⑦ 验全才切 -->
<line x1="860" y1="506" x2="1278" y2="506" class="req" marker-end="url(#arrow)"/>
<text x="866" y="500" class="xs t">⑦ 验全过 → 停旧实例释放端口 → 切 :48080</text>
<!-- ⑧ 失败回滚 -->
<line x1="1130" y1="548" x2="712" y2="548" class="ret" marker-end="url(#arrowB)"/>
<text x="735" y="542" class="xs" fill="#b91c1c" font-weight="700">⑧ 任一步失败 → /tmp 备份 JAR 把 :48080 恢复回去5 分钟内)</text>
<!-- ⑨ 切后复验 -->
<line x1="860" y1="612" x2="1278" y2="612" class="req" marker-end="url(#arrow)"/>
<text x="866" y="606" class="xs t">⑨ 切后复验:冒烟门 deploy/smoke-test.sh详见图 4</text>
<!-- ⑩ 真 UI 走查 -->
<rect x="50" y="638" width="1380" height="40" rx="8" fill="#fef2f2" stroke="#dc2626" stroke-width="1.4"/>
<text x="62" y="663" class="xs t" font-weight="700">红线API 全绿 ≠ UI 通 ——</text>
<text x="262" y="663" class="xs mut">编排器旁路会掩盖 UI 缺陷;用户可见波次收口前,必须另在 mini-desktop 经 CDP 做一次真浏览器 UI 走查</text>
<!-- 目标态对照 -->
<rect x="50" y="694" width="1380" height="46" rx="8" fill="#f1f5f9" stroke="#94a3b8" stroke-width="1.4" stroke-dasharray="7 5"/>
<text x="62" y="714" class="xs t" font-weight="700">目标态蓝图(现实未建·勿当现状):</text>
<text x="62" y="732" class="xs mut">开发团队版文档那套「push 触发 CI → 自动构建镜像 → 滚动更新」与现实系统性脱节(文档自带审计横幅);现行是人工标准序,无 docker-compose、无自建 CI 流水线。</text>
<!-- 图例 -->
<line x1="60" y1="772" x2="110" y2="772" class="req" marker-end="url(#arrow)"/><text x="118" y="776" class="t xs">同步动作 / 命令</text>
<line x1="280" y1="772" x2="330" y2="772" class="ret" marker-end="url(#arrowB)"/><text x="338" y="776" class="t xs">回执 / 拉取(灰虚线)</text>
<rect x="540" y="763" width="34" height="18" rx="4" fill="none" stroke="#ea580c" stroke-width="1.8" stroke-dasharray="6 4"/><text x="582" y="776" class="t xs">橙框=隔离验证安全变体</text>
<g class="badge"><rect x="800" y="763" width="56" height="18" rx="3" fill="#16a34a"/><text x="805" y="776" fill="#fff">可靠</text>
<rect x="864" y="763" width="56" height="18" rx="3" fill="#dc2626"/><text x="869" y="776" fill="#fff">安全</text>
<rect x="928" y="763" width="56" height="18" rx="3" fill="#16a34a"/><text x="933" y="776" fill="#fff">成本</text></g>
<text x="998" y="776" class="mut xs">隔离切换/备份回滚=可靠 · 分类器/串行=安全 · 内网物理机人工部署=成本</text>
<text x="40" y="828" class="mut xs">映射:运维/README.md §1.2 | 状态:现 | 设计变动须同步本图</text>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,114 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 860" font-family="-apple-system,'PingFang SC','Microsoft YaHei',Segoe UI,sans-serif">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#334155"/></marker>
<style>
.t{fill:#0f172a}.mut{fill:#475569}.sm{font-size:12px}.xs{font-size:11px}.xxs{font-size:10px}
.h1{font-size:24px;font-weight:700}.h2{font-size:14px;font-weight:700}.lbl{font-size:13px;font-weight:600}
.flow{stroke:#334155;stroke-width:2;fill:none}.badge{font-size:10.5px;font-weight:700}
.item{font-size:11px}
</style>
</defs>
<rect x="0" y="0" width="1480" height="860" fill="#f8fafc"/>
<text x="40" y="38" class="t h1">图 4 · 冒烟门 12+1</text>
<text x="40" y="58" class="mut sm">deploy/smoke-test.sh部署后秒级就绪检查以读为主、可反复跑逐项 PASS/FAIL末尾给退出码0=全过 / 1=有 FAIL可直接挂部署脚本当卡口。不是深度 e2e。</text>
<!-- 基础设施 + 鉴权2 项)-->
<rect x="40" y="86" width="280" height="118" rx="12" fill="#eef2ff" stroke="#4f46e5" stroke-width="2"/>
<text x="55" y="110" class="t h2">基础设施 / 鉴权2 项)</text>
<rect x="55" y="122" width="250" height="34" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="63" y="143" class="item t">1 · GET /actuator/health200</text>
<rect x="55" y="162" width="250" height="34" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="63" y="183" class="item t">2 · GET /app-api/passport/metoken 有效)</text>
<!-- 链路①创作→生成→预览2 项)-->
<rect x="340" y="86" width="280" height="118" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="355" y="110" class="t h2">链路① 创作→生成→预览2 项)</text>
<rect x="355" y="122" width="250" height="34" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="363" y="143" class="item t">3 · GET aigc/template/list四模板≥4</text>
<rect x="355" y="162" width="250" height="34" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="363" y="178" class="item t">4 · POST studio/draft建草稿拿 gameId</text>
<text x="363" y="191" class="xxs mut">唯一写status 0 草稿,不发布、无下游副作用</text>
<!-- 链路②发布→审核→游戏流3 项)-->
<rect x="640" y="86" width="280" height="118" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="655" y="110" class="t h2">链路② 发布→审核→游戏流3 项)</text>
<rect x="655" y="122" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="663" y="138" class="item t">5 · GET feed/stream内容池非空</text>
<rect x="655" y="150" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="663" y="166" class="item t">6 · GET feed/zones分区结构</text>
<rect x="655" y="178" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="663" y="194" class="item t">7 · GET project/my创作者项目区</text>
<!-- 链路③试玩→互动→分享1 项)-->
<rect x="940" y="86" width="500" height="118" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="955" y="110" class="t h2">链路③ 试玩→互动→分享1 项)</text>
<rect x="955" y="122" width="470" height="34" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="963" y="143" class="item t">8 · GET runtime/package/{versionId}(试玩取包)</text>
<rect x="955" y="162" width="470" height="34" rx="7" fill="#fef2f2" stroke="#dc2626" stroke-width="1.3"/>
<text x="963" y="183" class="item t" fill="#b91c1c">feed item 的 packageUrl 恒为 null —— 取包走 runtime/package别拿它当入口</text>
<!-- 链路④广告→收益→钱包3 项)-->
<rect x="40" y="224" width="280" height="118" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="55" y="248" class="t h2">链路④ 广告→收益→钱包3 项)</text>
<rect x="55" y="260" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="63" y="276" class="item t">9 · GET ad/slot/list-enabled广告位</text>
<rect x="55" y="288" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="63" y="304" class="item t">10 · GET trade/account/mine钱包</text>
<rect x="55" y="316" width="250" height="24" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="63" y="332" class="item t">11 · GET trade/income/page收益流水</text>
<!-- 链路⑤数据回路1 项)-->
<rect x="340" y="224" width="280" height="118" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="355" y="248" class="t h2">链路⑤ 数据回路1 项)</text>
<rect x="355" y="262" width="250" height="40" rx="7" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="363" y="280" class="item t">12 · feed 首条携带 qualityScore</text>
<text x="363" y="295" class="xxs mut">结构断言feed 排序由质量分驱动 = 回路已回灌</text>
<text x="355" y="326" class="xs mut">遥测 → 质量分 → feed 重排,闭环结构性可见</text>
<!-- deep 写路径 +1 项 -->
<rect x="640" y="224" width="280" height="118" rx="12" fill="#fffbeb" stroke="#d97706" stroke-width="2" stroke-dasharray="7 5"/>
<text x="655" y="248" class="t h2">--deep+1 项 · 按需)</text>
<rect x="655" y="262" width="250" height="44" rx="7" fill="#fff" stroke="#d97706" stroke-width="1.4"/>
<text x="663" y="281" class="item t">13 · POST studio/generate生成入队</text>
<text x="663" y="296" class="xxs mut">走真实写路径:触发生成入队 + 遥测落库</text>
<text x="655" y="326" class="xs mut">默认不跑;只验入队 200/code=0不等生成完成</text>
<!-- 判定盒 -->
<rect x="940" y="224" width="500" height="118" rx="12" fill="#f1f5f9" stroke="#475569" stroke-width="2"/>
<text x="955" y="248" class="t h2">总判 + 退出码(可挂 CI</text>
<rect x="955" y="262" width="225" height="34" rx="7" fill="#dcfce7" stroke="#16a34a" stroke-width="1.6"/>
<text x="965" y="283" class="item t">全过 → SMOKE_PASS · exit 0</text>
<rect x="1200" y="262" width="225" height="34" rx="7" fill="#fee2e2" stroke="#dc2626" stroke-width="1.6"/>
<text x="1210" y="283" class="item t">有 FAIL → SMOKE_FAIL · exit 1</text>
<text x="955" y="324" class="xs mut">职责边界:就绪检查 ≠ 深度 e2e深度 e2e 由 agent-loop 编排器批跑,不重叠)</text>
<!-- 流向汇聚 -->
<line x1="180" y1="204" x2="180" y2="224" class="flow"/>
<line x1="480" y1="204" x2="480" y2="224" class="flow"/>
<line x1="780" y1="204" x2="780" y2="224" class="flow"/>
<line x1="1190" y1="204" x2="1190" y2="224" class="flow" marker-end="url(#arrow)"/>
<text x="1196" y="218" class="xxs mut">链路③汇入判定</text>
<!-- 调用约定 -->
<rect x="40" y="372" width="1400" height="70" rx="12" fill="#ffffff" stroke="#475569" stroke-width="1.6"/>
<text x="55" y="396" class="t h2">调用约定</text>
<text x="55" y="418" class="xs mut">BASE=http://100.64.0.7:48080默认 staging 后端) · TOKEN=test1种子创作者测试态 token · ORIGIN=http://100.64.0.7:4173验 CORS 同源放行)</text>
<text x="55" y="434" class="xs mut">内网地址 / 测试 token 可入仓内网非密真实密钥严禁写入脚本。鉴权头Authorization: Bearer $TOKEN · tenant-id: $TENANT。</text>
<!-- 与观测衔接 -->
<rect x="40" y="454" width="1400" height="48" rx="12" fill="#f1f5f9" stroke="#94a3b8" stroke-width="1.4" stroke-dasharray="7 5"/>
<text x="55" y="474" class="t h2" fill="#475569">与观测体系衔接(设计已出·待接线):</text>
<text x="305" y="474" class="xs mut">冒烟门是「部署那一刻的就绪点检」,观测体系是「部署之后的常态监控」——两者互补不重叠。</text>
<text x="55" y="492" class="xs mut">衔接点:冒烟门 12 项结果可打成指标推 Prometheus让「每次部署的健康度」也进可观测历史而非只在终端闪一下。详见图 6 / 图 7。</text>
<!-- 图例 -->
<text x="40" y="546" class="t h2">图例:</text>
<rect x="120" y="532" width="34" height="20" rx="5" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/><text x="162" y="547" class="t xs">五链路就绪项</text>
<rect x="290" y="532" width="34" height="20" rx="5" fill="#fffbeb" stroke="#d97706" stroke-width="2" stroke-dasharray="7 5"/><text x="332" y="547" class="t xs">--deep 写路径(按需)</text>
<rect x="510" y="532" width="34" height="20" rx="5" fill="#fef2f2" stroke="#dc2626" stroke-width="1.6"/><text x="552" y="547" class="t xs">已踩坑 / 红线</text>
<g class="badge"><rect x="690" y="533" width="56" height="18" rx="3" fill="#16a34a"/><text x="695" y="546" fill="#fff">可靠</text>
<rect x="754" y="533" width="56" height="18" rx="3" fill="#dc2626"/><text x="759" y="546" fill="#fff">安全</text></g>
<text x="824" y="547" class="mut xs">逐项就绪 + 退出码可卡口=可靠 · 鉴权/CORS 结构验证=安全</text>
<text x="40" y="588" class="mut xs">映射:运维/README.md §1.3 · deploy/smoke-test.sh逐项以脚本为准·分组为讲解性归组 | 状态:现 | 设计变动须同步本图</text>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,153 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 900" font-family="-apple-system,'PingFang SC','Microsoft YaHei',Segoe UI,sans-serif">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#334155"/></marker>
<marker id="arrowB" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#64748b"/></marker>
<style>
.t{fill:#0f172a}.mut{fill:#475569}.sm{font-size:12px}.xs{font-size:11px}.xxs{font-size:10px}
.h1{font-size:24px;font-weight:700}.h2{font-size:14px;font-weight:700}.lbl{font-size:13px;font-weight:600}
.flow{stroke:#334155;stroke-width:2;fill:none}.flowb{stroke:#64748b;stroke-width:1.6;fill:none;stroke-dasharray:6 4}
.badge{font-size:10.5px;font-weight:700}.todo{font-size:10px;font-weight:700;fill:#b45309}
</style>
</defs>
<rect x="0" y="0" width="1480" height="900" fill="#f8fafc"/>
<text x="40" y="38" class="t h1">图 6 · 观测体系OTel → Grafana / 夜莺</text>
<text x="40" y="58" class="mut sm">采集 → 管道 → 存储 → 看板/告警 一条链。创始人 2026-06-21 定栈OTel 统一采集 + Prometheus + Grafana+ 夜莺(告警)。除标「已在」的件外,整链均为待接线。</text>
<!-- 状态约定条 -->
<rect x="40" y="76" width="1400" height="34" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="1.4" stroke-dasharray="7 5"/>
<text x="52" y="98" class="xs t" font-weight="700">状态约定:</text>
<text x="128" y="98" class="xs mut">实心块 = 已在(地基已就位);虚线框 + 「待接线」= 设计已出、代码未接,绝非现行已建。本图整体状态 = 接。</text>
<!-- 采集侧 -->
<rect x="40" y="128" width="380" height="370" rx="12" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="55" y="152" class="t h2">采集侧(被观测的进程)</text>
<!-- 后端单体(混合:已在 + 待接)-->
<rect x="55" y="164" width="350" height="150" rx="8" fill="#ffffff" stroke="#0891b2" stroke-width="1.5"/>
<text x="65" y="184" class="t lbl">huijing 后端单体</text>
<rect x="65" y="194" width="330" height="32" rx="6" fill="#dcfce7" stroke="#16a34a" stroke-width="1.4"/>
<text x="73" y="214" class="xs t">已在SAA 节点 observation每节点一条 Micrometer span</text>
<rect x="65" y="232" width="330" height="34" rx="6" fill="#fff7ed" stroke="#d97706" stroke-width="1.4" stroke-dasharray="6 4"/>
<text x="73" y="246" class="xs t">待接OTel Java Agent自动 spanHTTP/JDBC/Redis/出网)</text>
<text x="73" y="260" class="xxs mut">monitor starter 未进 aigc 部署单元 → 要先引 actuator/micrometer</text>
<rect x="65" y="272" width="330" height="34" rx="6" fill="#fff7ed" stroke="#d97706" stroke-width="1.4" stroke-dasharray="6 4"/>
<text x="73" y="286" class="xs t">待埋:生成业务指标 gen_task/duration/queue/gate/cost</text>
<text x="73" y="300" class="xxs mut">5 指标当前代码零命中,需补 MeterRegistry 注册</text>
<!-- 前端 -->
<rect x="55" y="322" width="350" height="56" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.5" stroke-dasharray="6 4"/>
<text x="65" y="342" class="t lbl">game-studio / game-admin 前端</text>
<text x="65" y="362" class="xs mut">待接OTel Web SDK首屏 / JS 错误 / 前端 trace· 第三期</text>
<text x="280" y="342" class="todo">待接线</text>
<!-- 主机中间件 -->
<rect x="55" y="386" width="350" height="100" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.5" stroke-dasharray="6 4"/>
<text x="65" y="406" class="t lbl">主机 / 中间件</text>
<text x="65" y="426" class="xs mut">待接node-exporter · MySQL/Redis exporter</text>
<text x="65" y="446" class="xs mut">CPU / 内存 / 磁盘 / GC对应 OOM、磁盘涨满</text>
<text x="280" y="406" class="todo">待接线</text>
<text x="65" y="470" class="xxs mut">区分:业务遥测(谁玩了哪款)走现有 /app-api不动、不重复造</text>
<!-- 管道 -->
<rect x="460" y="190" width="240" height="120" rx="12" fill="#fff7ed" stroke="#d97706" stroke-width="2" stroke-dasharray="6 4"/>
<text x="475" y="214" class="t h2">管道OTel Collector</text>
<text x="475" y="236" class="xs mut">OTLP 统一入口</text>
<text x="475" y="254" class="xs mut">收 trace / metrics / log</text>
<text x="475" y="272" class="xs mut">批处理 / 脱敏 / 采样 / 路由</text>
<text x="475" y="296" class="xxs t" font-weight="700">脱敏在此集中做(手机号/token</text>
<text x="600" y="214" class="todo">待接线</text>
<!-- 存储后端 -->
<rect x="460" y="334" width="240" height="164" rx="12" fill="#fff7ed" stroke="#d97706" stroke-width="2" stroke-dasharray="6 4"/>
<text x="475" y="358" class="t h2">存储后端(各管一类)</text>
<rect x="475" y="370" width="210" height="32" rx="6" fill="#fff" stroke="#d97706" stroke-width="1.3"/>
<text x="483" y="390" class="xs t">Prometheus指标时序</text>
<rect x="475" y="408" width="210" height="34" rx="6" fill="#fff" stroke="#d97706" stroke-width="1.3"/>
<text x="483" y="424" class="xs t">trace 后端 Tempo/Jaeger</text>
<text x="483" y="437" class="xxs mut">倾向 Tempo · 选型待定</text>
<rect x="475" y="448" width="210" height="34" rx="6" fill="#fff" stroke="#d97706" stroke-width="1.3"/>
<text x="483" y="464" class="xs t">日志后端 Loki 等</text>
<text x="483" y="477" class="xxs mut">倾向 Loki · 选型待定</text>
<!-- 看板与告警 -->
<rect x="740" y="128" width="380" height="370" rx="12" fill="#f1f5f9" stroke="#475569" stroke-width="2"/>
<text x="755" y="152" class="t h2">看板与告警</text>
<rect x="755" y="166" width="350" height="120" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.6" stroke-dasharray="6 4"/>
<text x="765" y="188" class="t lbl">Grafana —— 看read-only 的眼睛)</text>
<text x="765" y="210" class="xs mut">统一看板:指标 / trace / 日志三联下钻</text>
<text x="765" y="230" class="xs mut">admin 一键进的「监控大盘」即 Grafana</text>
<text x="765" y="252" class="xs mut">SLO 可用性 + Error Budget 燃尽图(详见图 5</text>
<text x="765" y="274" class="xxs t" font-weight="700">从一条慢请求点进它的 trace、再点进日志</text>
<text x="1030" y="188" class="todo">待接线</text>
<rect x="755" y="298" width="350" height="120" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.6" stroke-dasharray="6 4"/>
<text x="765" y="320" class="t lbl">夜莺 Nightingale —— 叫(会响的告警)</text>
<text x="765" y="342" class="xs mut">告警规则引擎 + 值班通知分发</text>
<text x="765" y="362" class="xs mut">把 P0P3 升级链落成真规则 + 真通道</text>
<text x="765" y="382" class="xs mut">从 Prometheus 拉指标算规则,口径与 Grafana 一致</text>
<text x="765" y="404" class="xxs t" font-weight="700">补「告警通道一根没接」这个最大空</text>
<text x="1030" y="320" class="todo">待接线</text>
<rect x="755" y="430" width="350" height="56" rx="8" fill="#ffffff" stroke="#475569" stroke-width="1.4"/>
<text x="765" y="450" class="t lbl">关键告警三类(创始人点名)</text>
<text x="765" y="470" class="xs mut">可用性 P0 · 错误率(5xx&gt;2%) P1 · 生成失败率(&lt;70%) P1</text>
<!-- 通知通道 -->
<rect x="1160" y="166" width="280" height="120" rx="12" fill="#fff7ed" stroke="#d97706" stroke-width="2" stroke-dasharray="6 4"/>
<text x="1175" y="190" class="t h2">通知通道</text>
<text x="1175" y="212" class="xs mut">MVP 先接:飞书 / 钉钉群机器人 webhook</text>
<text x="1175" y="232" class="xs mut">(零成本、当天可接,先全打通)</text>
<text x="1175" y="254" class="xs mut">P0 电话 / 短信:随支付/短信真实化补</text>
<text x="1175" y="276" class="xxs t" font-weight="700">webhook 密钥进《内网凭据与端点.md》</text>
<!-- admin 入口 -->
<rect x="1160" y="298" width="280" height="120" rx="12" fill="#fff7ed" stroke="#d97706" stroke-width="2" stroke-dasharray="6 4"/>
<text x="1175" y="322" class="t h2">game-admin 观测入口</text>
<text x="1175" y="344" class="xs mut">控制台「观测」菜单:观测大图 + 跳转</text>
<text x="1175" y="364" class="xs mut">SSO 免登进盘(详见图 7</text>
<text x="1175" y="386" class="xs mut">现状 = 零,整套新建</text>
<text x="1175" y="408" class="xxs t" font-weight="700">权限守门,不裸暴露 Grafana/Prometheus</text>
<!-- 连线 -->
<!-- 采集侧 → Collector -->
<line x1="420" y1="250" x2="458" y2="250" class="flowb" marker-end="url(#arrowB)"/>
<text x="424" y="244" class="xxs mut">OTLP</text>
<!-- Collector → 存储后端(竖向,两框上下堆叠) -->
<line x1="580" y1="310" x2="580" y2="332" class="flowb" marker-end="url(#arrowB)"/>
<text x="586" y="326" class="xxs mut">metrics/trace/log 分路</text>
<!-- 存储(Prometheus) → 看板告警 -->
<line x1="700" y1="386" x2="738" y2="386" class="flowb" marker-end="url(#arrowB)"/>
<text x="702" y="380" class="xxs mut">Prometheus 取数</text>
<!-- 夜莺 → 通知通道 -->
<line x1="1105" y1="340" x2="1158" y2="240" class="flowb" marker-end="url(#arrowB)"/>
<text x="1118" y="316" class="xxs mut">webhook</text>
<!-- admin入口 → Grafana(回指看板) -->
<line x1="1158" y1="338" x2="1107" y2="240" class="flowb" marker-end="url(#arrowB)"/>
<text x="1116" y="362" class="xxs mut">嵌入 + SSO 免登</text>
<!-- 已在的那段(高亮)-->
<rect x="40" y="516" width="1400" height="72" rx="12" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.8"/>
<text x="55" y="540" class="t h2" fill="#15803d">唯一已就位的观测信号(不要当成「全都接好了」):</text>
<text x="55" y="562" class="xs mut">aigc-server 已引 spring-ai-alibaba-starter-graph-observationSAA 裸图每个节点发 spring.ai.alibaba.graph.node.&lt;id&gt; 的 Micrometer observation带 trace + 耗时,失败反映在指标里)。</text>
<text x="55" y="580" class="xs mut">缺的只是:① 一个把它收走的后端;② 一个非 NOOP 的 ObservationRegistry要 actuator/micrometer 装配在席。其余采集件、存储、看板、告警、admin 入口全部待接线。</text>
<!-- 旁路铁律 -->
<rect x="40" y="600" width="1400" height="48" rx="12" fill="#fef2f2" stroke="#dc2626" stroke-width="1.4"/>
<text x="55" y="620" class="xs t" font-weight="700">旁路铁律:</text>
<text x="130" y="620" class="xs mut">埋点开关默认关、经 profile 显式开agent 异步批量上报、Collector 不可达时本地丢弃。</text>
<text x="55" y="638" class="xs mut">硬验收:停掉 Collector生成主链路与各 API 行为不变、冒烟门仍全绿——观测栈本身挂掉,绝不影响被观测的服务。</text>
<!-- 图例 -->
<text x="40" y="688" class="t h2">图例:</text>
<rect x="120" y="674" width="34" height="20" rx="5" fill="#dcfce7" stroke="#16a34a" stroke-width="1.8"/><text x="162" y="689" class="t xs">已在(地基就位)</text>
<rect x="300" y="674" width="34" height="20" rx="5" fill="#fff7ed" stroke="#d97706" stroke-width="1.8" stroke-dasharray="6 4"/><text x="342" y="689" class="t xs">待接线(设计已出·未接码)</text>
<line x1="560" y1="684" x2="610" y2="684" class="flowb" marker-end="url(#arrowB)"/><text x="618" y="688" class="t xs">数据流OTLP/scrape</text>
<g class="badge"><rect x="800" y="675" width="62" height="18" rx="3" fill="#0ea5e9"/><text x="805" y="688" fill="#fff">可观测</text>
<rect x="870" y="675" width="56" height="18" rx="3" fill="#dc2626"/><text x="875" y="688" fill="#fff">安全</text>
<rect x="934" y="675" width="56" height="18" rx="3" fill="#16a34a"/><text x="939" y="688" fill="#fff">可靠</text>
<rect x="998" y="675" width="56" height="18" rx="3" fill="#16a34a"/><text x="1003" y="688" fill="#fff">成本</text></g>
<text x="1066" y="688" class="mut xs">三件齐全=可观测 · Collector 脱敏=安全 · 旁路降级=可靠 · 缓存命中哨兵=成本</text>
<text x="40" y="728" class="mut xs">映射:运维/观测体系.md+ README.md §4 | 状态:接(设计已出·待接线) | 设计变动须同步本图</text>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,161 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 920" font-family="-apple-system,'PingFang SC','Microsoft YaHei',Segoe UI,sans-serif">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#334155"/></marker>
<marker id="arrowB" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L8,3 L0,6 Z" fill="#64748b"/></marker>
<style>
.t{fill:#0f172a}.mut{fill:#475569}.sm{font-size:12px}.xs{font-size:11px}.xxs{font-size:10px}
.h1{font-size:24px;font-weight:700}.h2{font-size:14px;font-weight:700}.lbl{font-size:13px;font-weight:600}
.flow{stroke:#334155;stroke-width:2;fill:none}.flowb{stroke:#64748b;stroke-width:1.6;fill:none;stroke-dasharray:6 4}
.badge{font-size:10.5px;font-weight:700}.todo{font-size:10px;font-weight:700;fill:#7c3aed}
</style>
</defs>
<rect x="0" y="0" width="1480" height="920" fill="#f8fafc"/>
<text x="40" y="38" class="t h1">图 8 · k3s 单节点迁移(收窄 + 缓做)</text>
<text x="40" y="58" class="mut sm">创始人 2026-06-22 定:范围收窄(单节点 k3s + staging 应用 + 观测栈,库不进集群,多节点/高可用/prod 推迟)、时机缓做(排在 W-G1 之后)。整张图是目标态,不是现行已建。</text>
<!-- 状态约定条 -->
<rect x="40" y="76" width="1400" height="34" rx="8" fill="#f5f3ff" stroke="#7c3aed" stroke-width="1.4" stroke-dasharray="7 5"/>
<text x="52" y="98" class="xs t" font-weight="700">状态约定:</text>
<text x="128" y="98" class="xs mut">紫色虚线框 + 「缓做」= 目标态、本阶段不做(排 W-G1 之后);实心块 = 今天就在跑、迁移期全程保留的兜底路。本图整体状态 = 缓。</text>
<!-- 目标拓扑mini-desktop k3s 单节点 -->
<rect x="40" y="128" width="760" height="440" rx="12" fill="#faf5ff" stroke="#7c3aed" stroke-width="2.5" stroke-dasharray="6 4"/>
<text x="55" y="152" class="t h2">mini-desktop · 100.64.0.7 · x86 —— k3s 单节点control-plane + worker 同机)</text>
<text x="685" y="152" class="todo">缓做</text>
<text x="55" y="172" class="xs mut">选 k3s单二进制 / 自带 containerd / 内置 local-path装时 --disable traefik --disable servicelbservice-node-port-range=4000-50000</text>
<!-- k3s 集群框 -->
<rect x="60" y="186" width="500" height="280" rx="10" fill="#ffffff" stroke="#7c3aed" stroke-width="1.6" stroke-dasharray="5 4"/>
<text x="72" y="206" class="t lbl">k3s 集群ns: huijing-staging / observability</text>
<rect x="72" y="218" width="476" height="56" rx="8" fill="#eff6ff" stroke="#2563eb" stroke-width="1.6"/>
<text x="82" y="238" class="t lbl">后端单体 Deployment取代裸 java -jar</text>
<text x="82" y="256" class="xs mut">image · -Xmx2g · requests 2Gi/limits 2.5Gi(Burstable) · 探针</text>
<text x="82" y="270" class="xxs t" font-weight="700">hostNetwork:true → 直占宿主 48080 + 连 127.0.0.1 库</text>
<rect x="72" y="282" width="232" height="44" rx="8" fill="#ffffff" stroke="#475569" stroke-width="1.4"/>
<text x="82" y="300" class="xs t">game-studio Deployment</text>
<text x="82" y="316" class="xxs mut">静态产物 nginx 镜像 · NodePort 4173</text>
<rect x="316" y="282" width="232" height="44" rx="8" fill="#ffffff" stroke="#475569" stroke-width="1.4"/>
<text x="326" y="300" class="xs t">game-admin Deployment</text>
<text x="326" y="316" class="xxs mut">NodePort 4174</text>
<text x="72" y="350" class="xs mut" font-weight="700">observability namespace观测栈 workload</text>
<rect x="72" y="358" width="150" height="40" rx="7" fill="#f1f5f9" stroke="#475569" stroke-width="1.3"/>
<text x="82" y="382" class="xs t">OTel Collector</text>
<rect x="230" y="358" width="150" height="40" rx="7" fill="#f1f5f9" stroke="#475569" stroke-width="1.3"/>
<text x="240" y="382" class="xs t">Grafana</text>
<rect x="388" y="358" width="160" height="40" rx="7" fill="#f1f5f9" stroke="#475569" stroke-width="1.3"/>
<text x="398" y="382" class="xs t">夜莺 Nightingale</text>
<text x="72" y="424" class="xxs mut">观测埋点/看板设计见图 6k3s 就绪前可先裸 docker-compose 过渡,对应用侧埋点零差异(都是 OTLP</text>
<text x="72" y="446" class="xxs mut">requests/limits + QoS 给观测栈设内存上限,别让 Prometheus 时序库吃垮同机 live 后端</text>
<!-- 库不进集群(实心:保留)-->
<rect x="576" y="218" width="208" height="100" rx="10" fill="#e2e8f0" stroke="#0f172a" stroke-width="2"/>
<text x="586" y="238" class="t lbl">隔离 MySQL / Redis</text>
<text x="586" y="258" class="xs mut">:13306 / :16379</text>
<text x="586" y="276" class="xs mut">裸容器 · 只 bind 127.0.0.1</text>
<text x="586" y="296" class="xs t" font-weight="700">不进集群(第一阶段保留)</text>
<text x="586" y="312" class="xxs mut">有状态迁移是另一量级风险</text>
<!-- 本地镜像 registry -->
<rect x="576" y="330" width="208" height="60" rx="10" fill="#faf5ff" stroke="#7c3aed" stroke-width="1.6" stroke-dasharray="5 4"/>
<text x="586" y="350" class="t lbl">镜像进集群</text>
<text x="586" y="368" class="xs mut">ctr import 导本地 tar</text>
<text x="586" y="384" class="xs mut">(第一阶段不引 registry</text>
<!-- 兜底逃生口(实心,最关键)-->
<rect x="60" y="478" width="724" height="78" rx="10" fill="#fee2e2" stroke="#dc2626" stroke-width="2"/>
<text x="72" y="500" class="t h2" fill="#b91c1c">逃生口(实心·迁移全程保留,不退役):裸 JAR + /tmp 备份</text>
<text x="72" y="522" class="xs mut">任一阶段、任一时刻 kubectl 出问题 → kubectl delete 集群 workload → start-app.sh + /tmp 备份 JAR 把 :48080 拉回 → 回到今天形态5 分钟内。</text>
<text x="72" y="540" class="xs mut">单节点 k3s 节点挂了集群全没(不买高可用);新路没稳定前,旁边始终留一条已验证的老路。集群版稳跑一个完整迭代 + 一次无事故发版,才考虑退役裸 JAR。</text>
<!-- mini-infra实心不进集群-->
<rect x="820" y="128" width="290" height="180" rx="12" fill="#e2e8f0" stroke="#0f172a" stroke-width="2"/>
<text x="835" y="152" class="t h2">mini-infra · 100.64.0.8</text>
<text x="835" y="172" class="xs mut">共享基建 · 不进集群 · 不装 kubelet</text>
<text x="835" y="192" class="xs mut">free 仅约 569Mi · 8 个常驻容器</text>
<rect x="835" y="204" width="260" height="28" rx="6" fill="#fff" stroke="#475569" stroke-width="1.3"/>
<text x="843" y="222" class="xs t">new-api · PostgreSQL · MinIO · Gitea · Redis</text>
<text x="835" y="252" class="xs t" font-weight="700">集群经 ExternalName Service 走 Tailscale IP 访问</text>
<text x="835" y="272" class="xxs mut">与裸 JAR 用 100.64.0.8:3000 一致 · baseUrl 不带 /v1</text>
<text x="835" y="294" class="xxs mut">凭据仍读《内网凭据与端点.md》</text>
<!-- 6c6g kubectl 控制端 -->
<rect x="820" y="324" width="290" height="120" rx="12" fill="#f1f5f9" stroke="#475569" stroke-width="2"/>
<text x="835" y="348" class="t h2">6c6g · 100.64.0.9</text>
<text x="835" y="368" class="xs mut">无人值守 · 不当节点、不跑 workload</text>
<text x="835" y="388" class="xs t" font-weight="700">当 kubectl 控制端kubeconfig 指 mini-desktop</text>
<text x="835" y="408" class="xs mut">声明式部署 / rollout / 状态巡检 cron 落这</text>
<text x="835" y="430" class="xxs mut">符合「禁跑重活」铁律:只发 kubectl 命令</text>
<!-- lili-mac -->
<rect x="820" y="460" width="290" height="96" rx="12" fill="#e2e8f0" stroke="#0f172a" stroke-width="2"/>
<text x="835" y="484" class="t h2">lili-mac · ARM</text>
<text x="835" y="504" class="xs mut">开发 / 本地 dev / 快构建 · 会休眠不进调度</text>
<text x="835" y="524" class="xs t" font-weight="700">镜像必须 mini-desktop x86 出</text>
<text x="835" y="542" class="xxs mut">Mac 的 ARM 镜像不同构 = 半假门staging-ops 铁律延伸)</text>
<!-- 连线 -->
<line x1="800" y1="246" x2="818" y2="246" class="flowb" marker-end="url(#arrowB)"/>
<text x="640" y="206" class="xxs mut">ExternalName → Tailscale IP</text>
<line x1="965" y1="324" x2="700" y2="200" class="flowb" marker-end="url(#arrowB)"/>
<text x="720" y="330" class="xxs mut">kubectl 远程驱动</text>
<!-- 四阶段迁移路 -->
<rect x="40" y="572" width="1400" height="178" rx="12" fill="#ffffff" stroke="#475569" stroke-width="1.6"/>
<text x="55" y="596" class="t h2">迁移路四阶段每阶段可独立验收、可回滚live :48080 全程或可瞬时恢复)</text>
<rect x="55" y="610" width="320" height="120" rx="9" fill="#dcfce7" stroke="#16a34a" stroke-width="1.6"/>
<text x="65" y="630" class="t lbl">阶段 0 · 容器化(零 k8s 风险·可先行)</text>
<text x="65" y="650" class="xs mut">后端单体出镜像Dockerfile 已存在)</text>
<text x="65" y="668" class="xs mut">JDK21 运行 / Java 17 编译,保留不降</text>
<text x="65" y="686" class="xs mut">门:镜像内 JAR 字节码实证 + docker run 跑冒烟</text>
<text x="65" y="710" class="xxs t" font-weight="700">是上云前提,无论范围/时机都该做</text>
<rect x="391" y="610" width="320" height="120" rx="9" fill="#faf5ff" stroke="#7c3aed" stroke-width="1.6" stroke-dasharray="5 4"/>
<text x="401" y="630" class="t lbl">阶段 1 · 装 k3s空集群·live 仍裸跑)</text>
<text x="401" y="650" class="xs mut">mini-desktop 单节点</text>
<text x="401" y="668" class="xs mut">Ready + 底噪 ≤1.5G + 装完仍 ≥6G 余量</text>
<text x="401" y="686" class="xs mut">装完掉到 6G 以下 → 单节点方案不成立,降级</text>
<text x="401" y="710" class="xxs mut">回滚k3s-uninstall.sh 一键卸,回纯裸跑</text>
<rect x="727" y="610" width="320" height="120" rx="9" fill="#faf5ff" stroke="#7c3aed" stroke-width="1.6" stroke-dasharray="5 4"/>
<text x="737" y="630" class="t lbl">阶段 2 · 后端上集群(流量切换在此)</text>
<text x="737" y="650" class="xs mut">隔离期 Pod 用 server.port=48092 起(避撞 live</text>
<text x="737" y="668" class="xs mut">门:隔离 48092 冒烟全绿 → 切 48080 → 复验 + UI 走查</text>
<text x="737" y="686" class="xs mut">回滚delete + /tmp 备份 JAR 拉起 :48080</text>
<text x="737" y="710" class="xxs t" font-weight="700">风险最高一步;裸 JAR 路径始终在手边</text>
<rect x="1063" y="610" width="362" height="120" rx="9" fill="#faf5ff" stroke="#7c3aed" stroke-width="1.6" stroke-dasharray="5 4"/>
<text x="1073" y="630" class="t lbl">阶段 3 · 前端 + 观测栈上集群</text>
<text x="1073" y="650" class="xs mut">studio/admin 静态产物 nginx 镜像(--mode staging</text>
<text x="1073" y="668" class="xs mut">观测栈进 observability ns · admin 补观测入口</text>
<text x="1073" y="686" class="xs mut">UI 走查 + 看板出图 + 至少一条告警自测</text>
<text x="1073" y="710" class="xxs mut">观测栈是旁路挂了不咬主链路delete 即可</text>
<!-- 阶段箭头 -->
<line x1="375" y1="670" x2="389" y2="670" class="flow" marker-end="url(#arrow)"/>
<line x1="711" y1="670" x2="725" y2="670" class="flow" marker-end="url(#arrow)"/>
<line x1="1047" y1="670" x2="1061" y2="670" class="flow" marker-end="url(#arrow)"/>
<!-- 买到什么 / 买不到什么 -->
<rect x="40" y="762" width="1400" height="46" rx="12" fill="#f5f3ff" stroke="#7c3aed" stroke-width="1.4" stroke-dasharray="7 5"/>
<text x="55" y="782" class="xs t" font-weight="700">本阶段上 k8s 买到的:</text>
<text x="225" y="782" class="xs mut">声明式部署 + rollout undo 一键回滚 + requests/limits 共存保护 + 观测栈编排。</text>
<text x="780" y="782" class="xs t" font-weight="700">买不到的:</text>
<text x="870" y="782" class="xs mut">高可用(单节点节点挂了集群全没)——要等第二台有余量的 x86 机器 + 多节点。别误以为「上了 k8s 就更稳」。</text>
<text x="55" y="800" class="xs mut">部署链 git push → Gitea → mini-desktop 拉取不变;冒烟门接口零改动(仍打 :48080构建门红线一条不丢字节码实证从「核 JAR」升级成「核镜像里的 JAR」。</text>
<!-- 图例 -->
<text x="40" y="838" class="t h2">图例:</text>
<rect x="120" y="824" width="34" height="20" rx="5" fill="#e2e8f0" stroke="#0f172a" stroke-width="2"/><text x="162" y="839" class="t xs">实心=今天就在跑·全程保留</text>
<rect x="360" y="824" width="34" height="20" rx="5" fill="#faf5ff" stroke="#7c3aed" stroke-width="1.8" stroke-dasharray="6 4"/><text x="402" y="839" class="t xs">紫虚线=缓做目标态W-G1 后)</text>
<line x1="640" y1="834" x2="690" y2="834" class="flowb" marker-end="url(#arrowB)"/><text x="698" y="838" class="t xs">跨机访问 / 控制</text>
<g class="badge"><rect x="860" y="825" width="56" height="18" rx="3" fill="#7c3aed"/><text x="865" y="838" fill="#fff">伸缩</text>
<rect x="924" y="825" width="56" height="18" rx="3" fill="#16a34a"/><text x="929" y="838" fill="#fff">可靠</text>
<rect x="988" y="825" width="56" height="18" rx="3" fill="#16a34a"/><text x="993" y="838" fill="#fff">成本</text></g>
<text x="1056" y="838" class="mut xs">声明式/平滑长多节点=伸缩 · 共存保护/一键回滚=可靠 · 不硬凑第二机=成本</text>
<text x="40" y="878" class="mut xs">映射:运维/k8s迁移.md+ README.md §4 | 状态:缓(收窄 + 缓做·排 W-G1 之后) | 设计变动须同步本图</text>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,184 @@
---
date: 2026-06-22
topic: 运维域图说——把「部署在哪、怎么变成在跑的服务、靠什么持续看见它」画成一套图 + 讲解(架构图集金样板·运维域首件)
status: 现行 + 待接(观测)+ 缓做k3s三态并存 · 防漂移门记源档 commit hash
映射源档:
- docs/architecture/运维/README.md @ 15b707fd
- docs/architecture/运维/观测体系.md @ 3e71715a
- docs/architecture/运维/k8s迁移.md @ 15b707fd
---
# 运维域图说
> **这是什么**绘境AI 运维域的「看图入口」。运维域回答三件事——这套系统**部署在哪些机器上**、代码**怎么从一行 commit 变成在运行的服务**、靠**什么确认它还活着并且活得够好**。这份图说把这三件事连同两件「设计已出但还没接上」的事线上观测体系、k3s 迁移),用一套图加配套讲解画清楚。复杂、跨机的用手绘 SVG 大图,简单、线性的用 Mermaid已有的图一律单源引用、不复制。
>
> **给谁看**:负责部署与值守的工程师、做发版的人、排查线上故障的人,以及关心可用性与运维成本的创始人。判断「这套运维方案是不是想要的那个」看这份图就够建立全局轮廓,逐字节的命令仍去 `deploy/` 脚本与 `.agents/skills/staging-ops.md`
---
## 0. 阅读约定与同步纪律
- **映射的设计档**:本图说不另立设计,只把运维域三份 canonical 设计档画出来——部署链与四机分工出自 [`运维/README.md`](README.md),线上观测体系出自 [`观测体系.md`](观测体系.md)k3s 迁移出自 [`k8s迁移.md`](k8s迁移.md)。frontmatter 里记了这三份的当前 commit hash作为**防漂移门**源档一旦变更、hash 对不上,这份图说与对应 SVG 即标「待复核」,由收口脚本比对。
- **同步纪律****设计一变动,本图说与对应 SVG 必须同步更新**,每张 SVG 脚注注明映射源档与状态。已并入 wave 收口清单。
- **三种状态贯穿全图,必须看清**:运维域的特殊之处是它同时承载「现行已建」「设计已出待接线」「收窄后缓做」三类内容,绝不能把后两类画成已建。图 6观测整体是**接**(待接线)、图 8k3s整体是**缓**(缓做、排在 W-G1 之后),其余六张是**现**。每张图内部还会用实心块 / 虚线框 + 「待接线」「缓做」小标把单个元素的状态再标一层。
- **产物形式**SVG 入仓GitHub 与编辑器直接渲染矢量PNG 在 mini-desktop 转6c6g 禁 chrome、无转换器。本图说只出 SVG。
## 1. 全图通用图例
**生产维度徽章**(用小色块 chip + 白字标在每张图相关的维度上,运维域主要关心其中四个):
- **可靠**`#16a34a`):隔离验证安全变体、备份 JAR 一键回滚、冒烟门退出码可卡口、观测旁路降级、k8s 共存保护与 rollout undo。
- **可观测**`#0ea5e9`OTel 统一采集、Grafana 三联下钻、夜莺告警必达——这是图 6 的主轴。
- **安全**`#dc2626`push 走 Gitea 中转scp/rsync 被分类器拦、Collector 集中脱敏、admin 观测入口权限守门不裸暴露后端。
- **成本**`#16a34a`):内网物理机 + 人工部署而非重 CI、不硬凑第二台机器上多节点、缓存命中率哨兵——都是 < ¥5,000/月成本盒子的取舍。
(另两个维度 **数据** `#475569`、**伸缩** `#7c3aed` 在 k3s 图上点到:声明式编排与平滑长成多节点 = 伸缩。)
**复用 / 边界三线语义**
- **实线**`#334155`):现成直接用、同步动作或命令。
- **虚线**`#64748b``stroke-dasharray="6 4"`):自建 / 解耦 / 回执 / 待接线 / 缓做的目标态。
- **双线 / 加粗框**:跨域共享的公共件或需要强调的边界。
> 运维域图说里,虚线还额外承担一层**状态语义**凡是「待接线」观测或「缓做」k3s的元素一律用虚线框 + 文字小标画出,与「现行已建」的实心块在视觉上一眼区分开。这是本域最该守的纪律点——观测体系和 k3s 迁移都是「设计已出、代码未接」,绝不能因为画得好看就让人误以为已经建好了。
---
## 2. 图集
### 图 1 · 四机分工拓扑〔引·现〕
> 单源引用,不复制:四机分工拓扑的 Mermaid 已在 **[运维/README.md §1.1](README.md#11-跑在哪里四台机器各司其职)** 内嵌,是该图的唯一来源。这里只链接、不抄一份进来——同一张图存两处、改一处漏一处,正是这份图集要消灭的漂移面。
这张图回答「服务跑在哪里」。绘境AI 在内网阶段刻意不上云托管、不上 Kubernetes而是用一组通过 Tailscale 连起来的物理机,按角色硬分工:**lili-mac** 是创作者本地工作站,跑开发主会话与快构建,但它会休眠合盖,所以不进 Tailscale 调度、也不承担任何「门」;**mini-desktop** 是权威验收机staging 全栈、重型构建、浏览器端到端测试都在这里,且与生产同构;**mini-infra** 是共享基建机Gitea / PostgreSQL / Redis / MinIO / new-api 都在这台,它绝不跑项目 app 或重型构建;**6c6g** 是常驻无人值守机跑常开的编排、定时任务、git 操作,但禁跑重活(重型前端构建会 OOM
读这张图要抓住一条最硬的边界:**Mac 是 ARM 架构,产出的 JAR 与前端产物架构中立可用,但 Docker 镜像与冒烟门必须在 x86 的 mini-desktop 出**,否则镜像架构与生产不同构,等于半假的门。这条边界在后面图 8k3s 迁移)里会再次出现并延伸——到了 k8s 时代,「进集群的镜像必须 mini-desktop x86 出」依然成立。这张图没有现行/远期的灰度它就是当前真相唯一的「设计缝」其实在别处——README §1.1 自己点明 mini-infra 上跑的关系型库是 PostgreSQL而 mini-desktop 上是隔离的 staging MySQL两者不是一回事端点口径以凭据 SoT《内网凭据与端点.md》为准别混。
### 图 2 · 部署链push → pull → 重建 → 验门SVG新·时序·现
![图 2 部署链 push→pull→重建→验门](assets/02-部署链时序.svg)
这张时序图回答「代码怎么变成在跑的服务」。它要先破除一个误解开发团队版文档里那套「push 触发 CI、自动构建镜像、滚动更新」是**目标态蓝图,与现实系统性脱节**(那份文档顶部自带审计横幅说明这点)。现行的部署没有 docker-compose、也没有自建 CI 流水线,而是**人工经标准序在 mini-desktop 上完成**——图里把它画成四条泳道之间的一串动作,并在底部用一个虚线框单独把这套蓝图标成「现实未建·勿当现状」,免得有人照着蓝图去找不存在的 CI。
核心三步在图上从左到右展开。**第一步同步代码**:代码经 `git push` 推到 Aliyun Gitea默认远程SSH `:2222`mini-desktop 再从同一个 Gitea 以匿名 HTTP `:3000` 拉取(注意是 HTTP 只读端口、不是 SSH。这里画出了两条已经踩过的坑直接 `scp / rsync` 源码树会被分类器拦下,所以必须走 Gitea 中转;大资产 push 在途时再发 push 会撞 Gitea 的 ref 锁,所以同仓 push 要串行。**第二步重建**:在 mini-desktop 上 `git reset --hard` 到目标分支、`mvn clean install` 出新的 fat JAR收口前**以字节码实证**新 JAR 确实含本次改动(曾因「构建源 ≠ 运行的 JAR」翻过车图上单画一格强调。**第三步验门**:重启后验 health 200、四模板就绪、Flyway up-to-date再跑冒烟门即图 4
整张图最该让人看出的,是中间那个橙色虚线框——**隔离验证安全变体**。高风险或整机变更不直接动 live而是先用新 JAR 在隔离端口 `:48090` 起一个实例验全,**live 的 `:48080` 全程不动**,验全过才切;任一步失败就用 `/tmp` 里的备份 JAR 把 `:48080` 恢复回去。这套「验全才切、失败即回」的安全变体是运维域可靠性的支点,后面图 8 把它原样平移到了 k8s 的隔离端口切换。图底还有一条红线值得记住:**API 全绿 ≠ UI 通**,编排器旁路会掩盖 UI 缺陷,用户可见波次收口前必须另做一次真浏览器 UI 走查。
### 图 3 · 隔离验证安全变体Mer新·流程·现
这张图把图 2 里那个橙框单独放大,讲清「为什么验全才切、失败怎么退」。它是一条状态/分支流程:新 JAR 不直接顶替 live而是先在隔离端口 `:48090` 起一个实例跑完整验证health、四模板、Flyway、冒烟门 12 项);只有**全部通过**才停旧实例、释放端口、把新实例切到 `:48080`**任一步失败,立即用 `/tmp` 备份 JAR 把 `:48080` 恢复**,回到改动前的形态,全程 live 不受影响。这条流程让一次高风险发版的下行风险被牢牢兜住——最坏情况也只是「白验一次、live 没动」,而不是「切了一半、服务挂了、退不回去」。
```mermaid
flowchart TB
START["新 JAR 已构建<br/>(字节码实证含本次改动)"] --> ISO["在隔离端口 :48090<br/>起一个新实例"]
LIVE["live 后端 :48080<br/>全程不动 · 继续服务"]:::live
ISO --> V{"在 :48090 验全?<br/>health 200 · 四模板就绪<br/>Flyway up-to-date · 冒烟门 12 项"}
V -- "全过" --> SWITCH["停旧实例 → 释放端口<br/>把新实例切到 :48080"]
V -- "任一失败" --> ROLLBACK["/tmp 备份 JAR<br/>把 :48080 恢复回去<br/>(5 分钟内 · live 本就没动)"]:::danger
SWITCH --> REVERIFY["切后复验冒烟门<br/>+ 真 UI 走查"]
SWITCH -.->|稳定观察一两天后| CLEAN["再删 /tmp 备份 JAR"]
ROLLBACK --> BACK["回到改动前形态<br/>排查后重来"]
classDef live fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
classDef danger fill:#fee2e2,stroke:#dc2626,stroke-width:2px;
```
这张图没有现行/远期边界,它就是现行高风险发版的标准动作;它和图 2 的关系是「图 2 给全链路、图 3 把其中最关键的安全机制放大」。要注意的设计缝只有一个:这套变体是**人工经标准序**执行的,不是声明式的——这正是图 8k3s想用 `kubectl rollout undo` 改进的地方,但在 k8s 落地前、乃至落地后的过渡期,这条人工兜底路始终保留。
### 图 4 · 冒烟门 12+1SVG新·流程·现
![图 4 冒烟门 12+1 项](assets/04-冒烟门12项.svg)
这张图回答「靠什么确认它健康」。每次 staging 部署之后跑一遍 `deploy/smoke-test.sh`——它是「部署后是否健康」的**就绪检查**(秒级、以读为主、可反复跑),逐项 PASS / FAIL末尾给总判与退出码0 = 全过1 = 有 FAIL所以能直接挂到部署脚本里当卡口。图上把 12 个默认项按「基础设施 / 鉴权 + 五条端到端闭环链路」分组画出来,让人一眼看出冒烟门验的不是零散接口,而是**五条业务链的关键 API 是否都在岗**:① 创作→生成→预览、② 发布→审核→游戏流、③ 试玩→互动→分享、④ 广告→收益→钱包、⑤ 数据回路遥测→质量分→feed 重排)。
读这张图要抓三个细节。其一,**12 项里唯一的写操作**是建一条无副作用的草稿(`POST /app-api/studio/draft`status 0、不发布、无下游副作用用于验证创作入口 + 鉴权 + gameId 分配在岗;其余全是读。其二,`--deep` 才加的第 13 项(图上用橙色虚线框单独标「按需」)走真实写路径,触发一次生成入队 + 遥测落库,默认不跑、只验入队 `200/code=0`,不等生成完成。其三,图上用红框钉死了一个反复出现的坑:**feed 列表项的 `packageUrl` 字段恒为 null**,真实取游戏包要走 `GET /app-api/runtime/package/{versionId}`,别拿 `packageUrl` 当取包入口。
这张图的「设计缝」画在右下角那个虚线框里:冒烟门是「部署那一刻的就绪点检」,它**不是**深度 e2e深度 e2e 由 agent-loop 编排器批跑,职责不重叠),也**还没有**常态监控来补它的另一半——这正好衔接到图 6 的观测体系。衔接点写在图上:冒烟门那 12 项的结果可以打成指标推给 Prometheus让「每次部署的健康度」也进可观测历史而不是只在部署当时的终端里闪一下。
### 图 5 · 可用性 SLO / Error BudgetMer新·讲解·现
这张图回答「健康到什么程度才算达标」。运维域的硬指标是**服务可用性 ≥ 99.5%**,与之配套的是 MVP 基础设施成本控制在 **< ¥5,000/月**——这两个数字是运维域所有取舍(不上云托管、单体而非微服务、人工部署而非重 CI的约束来源。图把可用性目标拆成三档 SLO来自 `security-and-reliability.md` §5.1:游戏流 99.5%/月 ≈ error budget 3.6 小时、AI 生成 99%/月 ≈ 7.2 小时、支付 99.9%/月 ≈ 43 分钟),并点明这些目标怎么落进成本盒子。
```mermaid
flowchart TB
GOAL["可用性目标 ≥ 99.5%(MVP)<br/> 基础设施成本 ¥5,000/月以内"]:::goal
subgraph SLO["三档 SLO + Error Budget(security-and-reliability §5.1)"]
direction LR
S1["游戏流<br/>99.5% / 月<br/>容错预算 ≈ 3.6 小时"]
S2["AI 生成<br/>99% / 月<br/>容错预算 ≈ 7.2 小时"]
S3["支付<br/>99.9% / 月<br/>容错预算 ≈ 43 分钟"]
end
subgraph COST["成本盒子怎么撑住目标"]
direction LR
C1["内网物理机<br/>不上云托管"]
C2["单体<br/>而非微服务"]
C3["人工部署<br/>而非重 CI"]
end
GOAL --> SLO
GOAL --> COST
SLO -.->|"现状:只有一个目标数字,<br/>没有东西在持续度量它"| GAP["缺口error budget 无人消耗与记录<br/>→ 由观测体系落地(图 6)<br/>用 health 成功率算实际可用性 + burn rate 看板"]:::gap
classDef goal fill:#f0fdf4,stroke:#16a34a,stroke-width:2px;
classDef gap fill:#fff7ed,stroke:#d97706,stroke-width:2px,stroke-dasharray:5 4;
```
这张图最该让人看出的是那条虚线指向的**缺口**≥99.5% 现在是一个**目标数字**,但没有任何东西在持续度量它、没有 error budget 在被消耗和记录。换句话说,达标线画出来了,举证手段还没建。这个缺口的归宿就是图 6 的观测体系——用 health 探测的成功率算游戏流 API 的实际可用性,对着三档 SLO 做 burn rate 看板和告警,让「达没达标」从一句承诺变成一张有数据、有容错预算余量的看板。所以图 5 和图 6 是一对:图 5 立目标、点缺口,图 6 给落地手段。
### 图 6 · 观测体系OTel → Grafana / 夜莺SVG新·架构·接设计已出·待接线
![图 6 观测体系 OTel→Grafana/夜莺](assets/06-观测体系.svg)
这张图回答「线上靠什么持续观测」——也是本域**最该验状态纪律**的一张。它整体是**接**(待接线):创始人 2026-06-21 定了栈OTel 统一采集 + Prometheus + Grafana 主看板 + 夜莺主告警),正式设计稿已出,但**代码大半没接、没后端**。所以图上做了一件最要紧的事:把「现在已经有什么」和「还得新建什么」用实心块 / 虚线框严格分开,绝不让人误以为观测已经建好。
图按「采集 → 管道 → 存储 → 看板/告警」一条链画,逐段标状态。**唯一已就位的实心块**在图正下方高亮aigc-server 已引入 `spring-ai-alibaba-starter-graph-observation`SAA 裸图每个节点已发 `spring.ai.alibaba.graph.node.<id>` 的 Micrometer observation带 trace 和耗时,失败反映在指标里)——这是后端唯一一段已经在以标准产出、且依赖已就位的观测信号。但图上同样标清楚:它缺一个把它收走的后端、缺一个非 NOOP 的 `ObservationRegistry`(要 actuator/micrometer 装配在席)。**其余全是虚线框 + 「待接线」**OTel Java Agent自动 spanmonitor starter 当前根本没进 aigc 部署单元)、五个生成业务指标(`gen_task_total` / `gen_duration_seconds` / `gen_queue_depth` / `gen_gate_fail_total` / `llm_cost`,目前在代码里**全部零命中**,要补 MeterRegistry 注册才有数据,其中成本指标还额外依赖一个尚未落地的 new-api `logs.quota` 采集薄片、OTel Collector、Prometheus / trace 后端 / 日志后端trace 倾向 Tempo、日志倾向 Loki但都标「选型待定」、Grafana、夜莺、通知通道、admin 观测入口。
读这张图要抓住三层设计意图。其一,**为什么 Collector 居中而不是各组件直连后端**:让每个进程直接推各自后端会把地址、协议、脱敏逻辑硬编码进每个应用,上 k8s 或换后端就得改一圈;中间放一个 Collector 当统一入口,脱敏(手机号/token、批处理、采样、路由全在这一层集中做换后端只改 Collector 导出配置、应用零改动——这正是「先单体可跑、后平滑上 k8s」能成立的技术支点。其二**Grafana 和夜莺不是冗余而是分工**Grafana 负责「你主动去看时看得清」(三联下钻),夜莺负责「你没在看时它把你叫来」(把 P0P3 升级链变成真规则真通道,补上「告警通道一根没接」这个最大的空);创始人点名的三类关键告警都在图上有家——可用性走 P0、错误率5xx>2%)走 P1、生成失败率<70% P1其三图底那条红线是观测体系的底线**埋点开关默认关 profile 显式开agent 异步批量上报Collector 不可达时本地丢弃**硬验收是停掉 Collector主链路与各 API 行为不变冒烟门仍全绿观测栈本身挂掉绝不能影响被观测的服务
除图上画出的「trace/日志后端选型、admin 嵌入方式与 SSO详见图 7」这几条待核外源档《观测体系.md》§6 还留了两条待创始人拍板的口径,读图时一并记住、别当已定:一是**观测数据保留期与成本**——trace 与 metrics 存多久直接吃 mini-desktop 的磁盘,要对一下账「预算里留的那笔监控冗余够不够这套栈的存储」;二是**生成成功率告警阈值**——现在 P1 写的是「成功率 < 70%已经很糟该紧急处理的线而验收线是 80%是否要在 70% 之外再加一条 80% 的趋势预警让成功率从 80% 往下掉时就先有提醒而不是等到 70% 才报也待拍
### 图 7 · admin 观测入口Mer新·流程·接待接线
这张图把图 6 右侧「admin 观测入口」那一块放大,讲清运营怎么从后台一键进监控大盘。它整体也是**接**——而且这块的现状是**零**,要整套新建:`game-admin/src` 下没有任何观测相关的路由、菜单或组件,后端也没有任何给 admin 用的观测查询接口。所以「控制台一键进盘」不是接一根线,而是要补齐前端菜单/路由/组件、后端管理员专属查询接口、嵌入安全处理三件,缺一不可。图用虚线把这三件标成「待接线」,并画出 admin 进盘的链路与那个必须解决的体验问题:**别让运营进个监控还要再登一次 Grafana**。
```mermaid
flowchart LR
OPS["运营<br/>(system_users 已登录 admin)"] --> ADMIN["game-admin 控制台<br/>『观测』菜单(待建)"]:::todo
ADMIN -->|"观测大图:嵌入只读大盘"| EMBED["Grafana 嵌入面板<br/>可用性/错误率/生成成功率"]:::todo
ADMIN -->|"深挖跳转"| PROXY["admin 后端 auth-proxy<br/>透传 system_users 身份头(待建)"]:::todo
PROXY -->|"可信头免登(SSO)"| GRAF["Grafana 完整大盘<br/>trace/metrics/log 三联下钻"]
ADMIN -.->|"告警概览 API"| N9E["夜莺告警列表<br/>最近告警 / 值班状态"]
EMBED --> GRAF
classDef todo fill:#fff7ed,stroke:#d97706,stroke-width:1.5px,stroke-dasharray:5 4;
```
这张图要让人看出两处尚未拍板的设计缝,都还**待核**,不能当成已定。其一,**嵌入方式**iframe 嵌 Grafana 不是写个 `<iframe src>` 就完——Grafana 默认带 `X-Frame-Options: deny` 和自身 CSP浏览器会直接拒绝被嵌入要让嵌入成立得开 `grafana.ini``allow_embedding` 并放 CSP `frame-ancestors`;另一条路是不嵌 iframe、改由 admin 后端查询接口取数、前端自渲核心曲线,绕开嵌入安全开关但要自己画图。其二,**SSO 免登**:倾向 auth-proxy 透传admin 后端把已登录的 `system_users` 身份经可信请求头透给 Grafana体验最好但要核 Grafana auth proxy 在 iframe 场景下的 cookie/同源限制,以及 admin 代理层的安全边界——**不能让未授权 admin 用户读到观测数据,更不能把 Grafana / Prometheus 裸暴露出去**。这两处待核是这块落地前必须先定的,图上据实标出、不臆造结论。
### 图 8 · k3s 单节点迁移(收窄 + 缓做SVG新·架构·缓缓做·排 W-G1 之后)〕
![图 8 k3s 单节点迁移](assets/08-k3s迁移.svg)
这张图回答「部署形态往哪走」——也是本域**第二个最该验状态纪律**的图。它整体是**缓**:创始人 2026-06-22 拍板「范围收窄、时机缓做」,所以图上整张是**目标态、本阶段不做**,用紫色虚线框 + 「缓做」标清楚,绝不能画成现行已建。范围收窄为单节点 k3s 跑在 mini-desktop 上、只迁 staging 应用与观测栈、数据库不进集群、多节点 / 高可用 / prod 全部推迟;时机缓做、排在 W-G1生成质量到 80%)告一段落之后(其中阶段 0 容器化零 k8s 风险、是上云前提,可先行)。
图分三块。**左上是目标拓扑**紫虚线mini-desktop 单节点 k3scontrol-plane 与 worker 同机),里面是后端单体 Deployment、studio/admin Deployment、observability namespace 的三件观测 workload旁边两个**实心块**是迁移期**全程保留**的东西——隔离 MySQL/Redis 裸容器(标「不进集群」,因为有状态迁移是另一个量级的风险)和「裸 JAR + /tmp 备份」逃生口(用红框单画,强调任一阶段、任一时刻 kubectl 出问题就 5 分钟内退回今天形态)。**右侧三块**是 mini-infra共享基建不进集群、不装 kubelet集群经 ExternalName Service 走 Tailscale IP 访问它、6c6g不当节点、不跑 workload只当 kubectl 控制端、lili-mac镜像必须 x86 出,与图 1 的边界一脉相承)。**底部是四阶段迁移路**:阶段 0 容器化(绿色实心、可先行)→ 阶段 1 装 k3s空集群、live 仍裸跑)→ 阶段 2 后端上集群(流量切换在此、风险最高)→ 阶段 3 前端 + 观测栈上集群,每阶段都标了独立验收门与回滚手法。
读这张图,最要让人看清的是「**买到什么、买不到什么**」那一栏:本阶段上 k8s 买到的是声明式部署 + `rollout undo` 一键回滚 + requests/limits 共存保护 + 观测栈编排;**买不到的是高可用**——单节点 k3s 一旦节点挂了,集群和所有 workload 一起没,这和今天裸 JAR 挂了没本质区别,反而多背了一整套 k8s 控制平面的复杂度。如果创始人的预期是「上了 k8s 就更稳了」,这里要先校准:高可用要等多节点,而多节点要等有第二台有内存余量的 x86 机器(现在没有)。技术细节上还有两个被图钉住的关键决定:后端走 `hostNetwork: true`(一举两得——既直占宿主 48080 让对外端口零变化,又能连只 bind 在 `127.0.0.1` 的库,`hostAliases` 和 host-gateway 都做不到);隔离期 Pod 用 `server.port=48092` 起(避开正被 live 裸 JAR 占着的 48080这正是图 2/图 3 的隔离验证安全变体平移到了 k8s。
---
## 3. 图清单与状态表
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|---|---|---|---|---|---|
| 1 | 四机分工拓扑 | 架 | 引(链 README §1.1 | 现 | lili-mac / mini-desktop / mini-infra / 6c6g 角色边界 + Gitea 中转 + ARM/x86 镜像门铁律 |
| 2 | 部署链 push→pull→重建→验门 | 时 | SVG新 | 现 | Gitea 中转 + push 串行 + 字节码实证 + 隔离验证安全变体 + 真 UI 走查红线 + 目标态蓝图对照 |
| 3 | 隔离验证安全变体 | 流 | Mer新内联 | 现 | 新 JAR 在 :48090 验全才切、live :48080 全程不动、失败用 /tmp 备份回滚 |
| 4 | 冒烟门 12+1项 | 流 | SVG新 | 现 | 基础设施/鉴权 2 项 + 五链路 10 项 + --deep 写路径 1 项 + 退出码卡口 + packageUrl 恒 null 坑 |
| 5 | 可用性 SLO / Error Budget | 讲 | Mer新内联 | 现 | ≥99.5% + 成本 <¥5,000/月 约束来源 + 三档 SLO + 「无人持续度量」缺口指向图 6 |
| 6 | 观测体系 OTel→Grafana/夜莺 | 架 | SVG新 | **接** | 采集→管道→存储→看板/告警全链;唯一已就位=SAA 节点 observation其余待接线Collector 居中/双看板分工/旁路铁律 |
| 7 | admin 观测入口 | 流 | Mer新内联 | **接** | 控制台一键进盘链路 + SSO 免登 + 嵌入方式/SSO 两处待核;现状=零、整套新建 |
| 8 | k3s 单节点迁移 | 架 | SVG新 | **缓** | 单节点 k3s + staging 应用 + 观测栈,库不进集群;四阶段迁移路;裸 JAR 兜底全程保留;买到/买不到边界 |
> **状态分布**:现 ×6、接 ×2图 6/7观测体系待接线、缓 ×1图 8k3s 收窄缓做)。**防漂移门**:本图说 frontmatter 记三份源档的 commit hashREADME/k8s迁移 @ 15b707fd、观测体系 @ 3e71715a源档变更即比对hash 对不上则本图说与对应 SVG 标「待复核」。
>
> **PNG 后续**8 张图中 4 张为 SVG图 2/4/6/8SVG 入仓后在 mini-desktop 批量转 PNG6c6g 禁 chrome3 张 Mermaid图 3/5/7GitHub 直接渲染、无需转换;图 1 单源引用 README、不产新图。