Fam Zheng 011e7ddb98 README: 平台约定(栈/部署/CI 一锅端)
把脚手架决策定下来,作为 cube 上所有 app 必须遵守的"宪法":

- 域名:<app>.famzheng.me,零 DNS 操作
- 后端:Rust + Axum,每 app 独立仓库,cube-core crate 复用样板
- 前端:Vite + Vue 3 + TS(选 Vue 是因为 AI 写得稳)
- 构建:host musl 编译 + scratch 容器
- Registry:gitea 自带(registry.famzheng.me 反代 /v2/*)
- CI:gitea Actions + 现有 instance-level act_runner
- 通用约定:/healthz, stdout JSON log, env+Secret 配置, 禁 config 文件挂载
2026-05-04 11:08:01 +01:00

cube

Fam 的小 app 平台。

是什么

cube 是一个跑在 famzheng.me 节点hostname famzheng.com,单节点 k3s + traefik + gitea,公网 IP 178.104.186.206)上的小 app 平台,专门收纳 Fam 自己写的一堆小工具/玩具 web app。底层硬件、k3s、Gitea、act_runner 等基础设施详见 ~/.claude/memory/infra.md

主要任务:把目前散落在 oci.euphon.netOracle Cloud ARM VM)上值得留下的 Fam 个人小 app 迁过来。oci 主机本身不退役,留给 Hera 同学继续用。

设计目标:反 Karpathy "web app 像拼宜家家具" 的困境 —— 全部自有基础设施,零跨 dashboard 配置,新 app 上线压缩到 5 分钟内。


平台约定

这是 cube 上所有 app 的"宪法",所有 app 必须遵守,破例必须改这份文档并经 Fam 拍板。

部署目标

单一目标:famzheng.me 节点的 k3skubectl context default),不双轨。

  • 每 app 一个 k8s namespacens 名 = app 名,不加 cube- 前缀)
  • traefik ingress + 通配符 LE 证书自动签

域名

  • <app>.famzheng.mewildcard A 记录已配,零 DNS 操作
  • 不嵌 cube 子域(冲突检查 = 起新 ingress 时 traefik 自然报错,不需要额外心智)
  • 旧域名(如 portfolio.oci.euphon.net)让 oci ingress 兜底 308 redirect 到新地址,过渡期后下掉

后端:Rust + Axum,每 app 独立仓库

  • gitea repo fam/<app>,单 axum 服务
  • 公共代码通过 cube-core crate 复用:cube-core = { git = "https://famzheng.me/gitea/fam/cube-core", tag = "v0.x" }
  • cube-core 提供:
    • /healthz router200 = ok
    • ServeDir 静态前端 fallback 到 index.html
    • tracing 配 JSON stdout
    • SIGTERM graceful shutdown
    • env → struct 配置加载(envy crate
  • 业务 app 只写 /api/* 路由 + handler
    Router::new()
        .merge(cube_core::base("dist"))
        .nest("/api", api_routes())
    
  • 不上 cargo workspace —— 每 app 一个 repo 彻底分

前端:Vite + Vue 3

  • 默认栈:Vite + Vue 3 + TypeScript + Pinia + Vue Router
  • 选 Vue 而不是 Svelte 的原因:AIClaude / GPT)写 Vue 3 <script setup> + Composition API 训练语料密度大、bug 少;Svelte 5 runes 出来后 AI 经常混 4/5 语法
  • build 输出到 frontend/dist/axum 用 ServeDir 同进程同容器同域名 serve
  • 不搞前后端分离部署、不搞独立前端域名、不搞独立 CI

构建:host musl + scratch 容器

host 上直接 cargo build,不在容器里跑 cargo

cargo build --release --target x86_64-unknown-linux-musl
(cd frontend && npm ci && npm run build)

Dockerfile

FROM scratch
COPY target/x86_64-unknown-linux-musl/release/<app> /app
COPY frontend/dist /dist
ENTRYPOINT ["/app"]
  • 镜像 < 20MB
  • runner 上不跑 docker buildx 套娃,build 速度爆表
  • prereq(首次设置 host):apt install musl-tools + rustup target add x86_64-unknown-linux-musl

Container Registry

  • gitea 自带 Container RegistryPackages 功能,gitea 1.20+ 自带)
  • gitea 挂在 /gitea/ 子路径下,docker daemon 默认拼 https://famzheng.me/v2/... 会 404
  • 方案:加一条 ingress registry.famzheng.me 反代 /v2/*gitea-svc:3000/v2/*,复用 gitea token 鉴权
  • 镜像命名:registry.famzheng.me/fam/<app>:<sha>
  • 未实施:第一个 app 上线时再搞 ingress;过渡期可本地 build 直接 docker save + k3s ctr image import

CI/CD

走 gitea Actions,复用现有 instance-level act_runnergnoc 用户,host shell 模式,labels *:host新 repo 不用注册 runner)。

每个 app repo 一份 .gitea/workflows/deploy.yml,固定 5 步:

  1. cargo build --release --target x86_64-unknown-linux-musl
  2. (cd frontend && npm ci && npm run build)
  3. docker build -t registry.famzheng.me/fam/<app>:$GITHUB_SHA .
  4. docker push registry.famzheng.me/fam/<app>:$GITHUB_SHA
  5. kubectl -n <app> set image deploy/<app> <app>=registry.famzheng.me/fam/<app>:$GITHUB_SHA

host shell PATH 注意:workflow 第一行 export PATH="$HOME/.cargo/bin:$PATH"gnoc 的 rustup 装在 ~/.cargo)。

不做 PR 预览环境 —— 个人小 app 不需要,徒增复杂度。

通用约定(每个 app 都要遵守)

  • 暴露 /healthz200 = ok),k8s liveness/readiness 共用同一个 endpoint
  • 日志统一 stdoutcube-core 的 tracing 配 JSON),让 k3s 收
  • 配置走 env var + k8s Secret禁止 config.yaml 文件挂载(partiverse 那个"空目录顶替 config 文件"的坑别再踩)
  • 数据持久化只走 PVC + 每天 minio backup CronJobcube-core 提供 base 模板)
  • 镜像 tag 用 git SHA,不用 latest

当前状态

  • 仓库刚初始化(2026-05-04),脚手架/cube-core 都还没动手。
  • 迁移源端清单见 doc/todo.md

迁移名单(截至 2026-05-04

  • portfoliohost systemd portfolio.serviceuvicorn :8890不在 k3s 里;迁过来要重写成 Rust + axum 还是直接装 python 运行时?待定)
  • repo-vis
  • simpleasm
  • guitar
  • pyroblem(详情待补)

相关

  • 宿主节点:famzheng.me / hostname famzheng.com —— 详见 ~/.claude/memory/infra.md
  • 迁移源:oci.euphon.netARM Ubuntu 22.04 + k3s
S
Description
Fam 的小 app 平台 — famzheng.me k3s 上的部署/脚手架
Readme 26 MiB
Languages
Vue 38.8%
Rust 26.1%
Python 12.8%
TypeScript 8.1%
JavaScript 8%
Other 6.2%