Yggdrasil 构建与发布流水线要点

沉淀自会话记忆,含方案演变;以当前 Makefile、Dockerfile*、.github/workflows/ci.yml 为准。

交叉编译(x86_64 镜像)

  • 早期 cross 工具方案(.cross-out/server + make build-server-cross + CROSS_TARGET_X86_64_UNKNOWN_LINUX_MUSL_IMAGE 指向南大镜像)已废弃。
  • 现方案:Dockerfile.cross 全容器内构建,两个 native-arm64 builder 零 QEMU——Stage A rust:*-trixie(glibc 2.41,dx CLI 预编译二进制需 GLIBC 2.39,Bookworm 2.36 不够)编前端;Stage B rust:*-alpine(musl)+ cargo-zigbuild + zig 交叉编 server 到 x86_64-unknown-linux-musl;Stage C linux/amd64 FROM scratch 组装两个产物。builder 钉 --platform=$BUILDPLATFORM。

下载与镜像坑

  • zig 预编译 tarball 只在 ziglang.org/download,GitHub Releases 没有;中国境内镜像对该路径返回 HTML 壳页(HTTP 200)。必须 sha256 校验或查 xz magic(fd377a585a00),别只信 HTTP code / HEAD。
  • .dockerignore 排除 .git 时,用 build args 注入 git describe/hash/date 给 build.rs。
  • .dockerignore 里写 .cross-out/server(不带 !)=排除它 → COPY 报 not found;正确做法是完全不写(默认包含,target/ 排除不影响)。

运行镜像

  • scratch/non-root 运行镜像必须预建并授权 uploads/、backups/ 等写目录;曾因 backups 被忽略 + 父目录 root-owned → 备份创建 EACCES。不要静默吞掉 create_dir_all 错误。
  • /doc 在线文件必须在 Docker builder 里真实执行 cargo doc 并复制产物,宿主本地生成不保证镜像含文档。
  • GHCR 镜像名必须小写;docker image ls 的 formatter 不支持 .Architecture,用 docker image inspect。
  • SSH 目标默认 Fish 时,POSIX 部署脚本要显式 bash -lc。
  • 增加 workspace 包时同步检查 Dockerfile 的 manifest COPY,漏包会导致依赖缺失。

发布

  • 发布提交通常只含 CHANGELOG.md、Cargo.toml、Cargo.lock;cargo metadata --locked 是一致性验证、不会自动修锁,Cargo.lock 只应改本包版本。
  • 按 Keep a Changelog 风格在 Unreleased 下插入 ## [X.Y.Z] - YYYY-MM-DD,用中文条目。
  • annotated tag:git tag -a vX.Y.Z -m "Release vX.Y.Z"。
  • 只在明确授权后推送指定分支与 tag(如 git push origin master vX.Y.Z);不用 --tags(历史 tag 冲突会非零退出,即使分支与新 tag 已成功)。
  • 验证:git ls-remote --tags origin vX.Y.Z、gh run list --repo VOD-Studio/yggdrasil、gh run view、gh release view。
  • GitHub re-run 用的是原触发提交的 workflow,不会吸收之后的 workflow 修复,需要新触发才能验证新 workflow。
  • 「已推 tag」不等于「已部署成功」。