ci: build musl only for arm64 and reuse toolchain cache [CI]
This commit is contained in:
1 parent
490b008a57
commit
a6f9759238
22 files changed
+62
-73
No files matched your search
+10
-10
@@ -1,6 +1,6 @@
|
||||
# 部署
|
||||
|
||||
节点(Agent)使用 NativeAOT。Linux 的开发版和正式版共用 `ci/build-linux-agent.sh`:musl amd64/arm64 静态链接 MsQuic、OpenSSL 和 .NET 加密 shim;glibc amd64/arm64 附带 MsQuic、NUMA、zstd 和 zlib 共享库,主机仍需提供 OpenSSL 3 和对应 libc。Agent OCI 镜像以 Alpine 为基底,直接使用同版本的 musl 原生包。OpenWrt 更新包也使用这份二进制,安装与签名清单沿用设备端现有协议。
|
||||
节点(Agent)使用 NativeAOT。Linux 的开发版和正式版共用 `ci/build-linux-agent.sh`:musl arm64 静态链接 MsQuic、OpenSSL 和 .NET 加密 shim;glibc amd64/arm64 附带 MsQuic、NUMA、zstd 和 zlib 共享库,主机仍需提供 OpenSSL 3 和对应 libc。Agent OCI 镜像复用同版本的原生包:amd64 使用 glibc 与 Debian 基底,arm64 使用静态 musl 与 Alpine 基底。OpenWrt 更新包也使用这份二进制,安装与签名清单沿用设备端现有协议。
|
||||
|
||||
## 1. 构建与打包
|
||||
|
||||
@@ -42,13 +42,13 @@ scripts/package.sh <agent> <rid> → backend/artifacts
|
||||
| rid | 目标 | 构建方式 |
|
||||
| --- | --- | --- |
|
||||
| `linux-x64`、`linux-arm64` | Debian/Ubuntu glibc 服务器 | Linux amd64 runner 通过 AotAnywhere 交叉编译 |
|
||||
| `linux-musl-x64`、`linux-musl-arm64` | Alpine、amd64 OpenWrt、aarch64 OpenWrt 路由器 | Linux amd64 runner 通过 AotAnywhere 交叉编译 |
|
||||
| `linux-musl-arm64` | ARM64 Alpine、aarch64 OpenWrt 路由器 | Linux amd64 runner 通过 AotAnywhere 交叉编译 |
|
||||
| `osx-x64`、`osx-arm64` | Intel Mac、Apple Silicon | Windows CI 主机通过 AotAnywhere 交叉编译;发布包未做 Developer ID 签名或 Apple 公证 |
|
||||
| `win-x64`、`win-arm64` | Windows x64、ARM64 | Windows CI 主机上的 Visual Studio C++ 工具链 |
|
||||
|
||||
macOS 的 Apple Silicon 产物带临时 ad-hoc 签名,Intel 产物未签名。通过浏览器下载时,macOS Gatekeeper 可能阻止启动;面向普通用户分发前需要 Developer ID 签名和 Apple 公证。MIPS 不在当前目标列表中(见 `project-layout.md`)。
|
||||
|
||||
仓库内的 `scripts/publish.sh` 面向本机目标平台;Woodpecker 的开发版和 tag 流水线在 Linux runner 上构建 Agent 与 `fleet-enroll` 的四个 Linux RID;Windows runner 负责 macOS 和 Windows。Backend OCI 镜像在 Linux runner 上构建。
|
||||
仓库内的 `scripts/publish.sh` 面向本机目标平台;Woodpecker 的开发版和 tag 流水线在 Linux runner 上构建 Agent 与 `fleet-enroll` 的三个 Linux RID;Windows runner 负责 macOS 和 Windows。Backend OCI 镜像在 Linux runner 上构建。
|
||||
|
||||
## Backend 容器
|
||||
|
||||
@@ -84,25 +84,25 @@ Backend 的 NativeAOT 发布默认启用 `SqliteStaticLink`,支持 Linux glibc
|
||||
|
||||
## 节点二进制发布
|
||||
|
||||
Woodpecker 在 `vMAJOR.MINOR.PATCH` tag 上,由 Windows runner 使用 AotAnywhere 并行构建 Agent 的 Linux glibc、Linux musl、macOS 和 Windows 产物。Agent 包还包含一次性注册工具 `fleet-enroll`。Linux 归档带有安装脚本和 systemd/OpenWrt 单元;Windows 产物为 `.zip`,Linux/macOS 产物为 `.tar.gz`。glibc sidecar 选用 Debian 12 兼容构建,musl sidecar 来自 Alpine v3.22。Linux musl 的 Agent 二进制还会打包为 OCI 镜像,基底为 `mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine`,支持 `linux/amd64` 和 `linux/arm64`;镜像直接带有归档中的 MsQuic、NUMA 和 LTTng 共享库,并通过 `LD_LIBRARY_PATH` 加载。Linux 原生库包按 RID 缓存在 CI runner 的 `.nuget/moshiro-quic-runtime`,索引最多缓存 24 小时,已下载的版本包会复用。所有平台产物和 OCI 镜像发布成功后,CI 会创建对应的 Gitea Release,并附上压缩包和 SHA-256 校验文件。macOS 产物目前未签名/公证。安装说明见 [Agent](../../backend/agent/README.md) 文档。
|
||||
Woodpecker 在 `vMAJOR.MINOR.PATCH` tag 上构建 Agent 的 Linux、macOS 和 Windows 产物。Linux amd64/arm64 使用 glibc,OpenWrt ARM64 使用静态 musl;Agent 包还包含一次性注册工具 `fleet-enroll`。Linux 归档带有安装脚本和 systemd/OpenWrt 单元;Windows 产物为 `.zip`,Linux/macOS 产物为 `.tar.gz`。glibc sidecar 选用 Debian 12 兼容构建,musl sidecar 来自 Alpine v3.22。Agent OCI 镜像使用 amd64 glibc/Debian 和 arm64 musl/Alpine,直接携带相应归档中的共享库,并通过 `LD_LIBRARY_PATH` 加载。Linux 原生库包按 RID 缓存在 CI runner 的 `.nuget/moshiro-quic-runtime`,索引最多缓存 24 小时,已下载的版本包会复用。所有平台产物和 OCI 镜像发布成功后,CI 会创建对应的 Gitea Release,并附上压缩包和 SHA-256 校验文件。macOS 产物目前未签名/公证。安装说明见 [Agent](../../backend/agent/README.md) 文档。
|
||||
|
||||
## CI 工作流
|
||||
|
||||
### Linux runner 的运行环境
|
||||
|
||||
Linux workflow 使用 `ci=domain-linux-native`、`platform=linux/amd64` 标签和 Woodpecker `local` backend;步骤里的 `image: bash` 是执行程序,构建工具来自 runner 环境。测试、前端和 Backend 编译使用 .NET 10、Node/npm、Python、clang 和 Zig;Agent 的 Linux 原生包通过 Buildah 的 NativeAOT builder 编译,OCI 镜像从已发布的 musl 包组装。
|
||||
Linux workflow 使用 `ci=domain-linux-native`、`platform=linux/amd64` 标签和 Woodpecker `local` backend;步骤里的 `image: bash` 是执行程序,构建工具来自 runner 环境。测试、前端和 Backend 编译使用 .NET 10、Node/npm、Python、clang 和 Zig;Agent 的 Linux 原生包通过 Buildah 的 NativeAOT builder 编译,OCI 镜像从已发布的 glibc amd64、musl arm64 包组装。
|
||||
|
||||
WSL 的 agent 通过 rootless Podman 运行,systemd 模板见 `ci/woodpecker-agent-podman.service`。工具全部在 `packaging/container/Woodpecker.Agent.Containerfile` 中安装,包括 .NET 10 SDK、Node/npm、Buildah、netavark/aardvark-dns、Git、Python、clang、Woodpecker agent/clone 插件和测试用 MsQuic 库;AotAnywhere SDK、Zig 与四个 Linux RID 的 NativeAOT 包由 `NativeAot.Builder.Containerfile` 预热。容器 PID 上限是 8192,避免多个并行 AotAnywhere/Zig 链接时撞到默认 2048 的限制。容器只把 `/home/justme` 作为可写工作区和缓存,不挂载宿主工具目录。连接信息与 7897 代理配置放在宿主 `/home/justme/woodpecker/agent-podman.env`,不要提交密钥。容器允许 `unshare`、提供 `SYS_ADMIN` 和 `/dev/fuse`,以便 Buildah 挂载镜像层;不要通过 `chroot /host` 启动 agent,因为 Linux 会拒绝 chroot 进程创建新的用户命名空间。
|
||||
WSL 的 agent 通过 rootless Podman 运行,systemd 模板见 `ci/woodpecker-agent-podman.service`。工具全部在 `packaging/container/Woodpecker.Agent.Containerfile` 中安装,包括 .NET 10 SDK、Node/npm、Buildah、netavark/aardvark-dns、Git、Python、clang、Woodpecker agent/clone 插件和测试用 MsQuic 库;AotAnywhere SDK、Zig 与三个 Linux RID 的 NativeAOT 包由 `NativeAot.Builder.Containerfile` 预热。容器 PID 上限是 8192,避免多个并行 AotAnywhere/Zig 链接时撞到默认 2048 的限制。容器只把 `/home/justme` 作为可写工作区和缓存,不挂载宿主工具目录。连接信息与 7897 代理配置放在宿主 `/home/justme/woodpecker/agent-podman.env`,不要提交密钥。容器允许 `unshare`、提供 `SYS_ADMIN` 和 `/dev/fuse`,以便 Buildah 挂载镜像层;不要通过 `chroot /host` 启动 agent,因为 Linux 会拒绝 chroot 进程创建新的用户命名空间。
|
||||
|
||||
以 WSL 的 `justme` 用户运行 `bash ci/build-runner-image.sh` 构建工具镜像,验证后安装 systemd 模板并重启 agent。该脚本使用 Podman 的持久镜像层缓存和 `--pull=missing`,服务启动使用 `--pull=never`;流水线和服务重启都不会执行工具安装。NativeAOT builder 只在 SDK/工具版本或 Containerfile 改变时更新,不受每次开发构建的版本号影响。它按镜像 ID 导出到 `woodpecker/cache/runner-image`,Linux Agent 的共享 Buildah store 从本地归档导入一次,之后直接复用镜像。只有所需归档不存在或工具配置改变时,构建脚本才回退到 Containerfile 构建。应用的 NuGet restore 缓存独立持久化在 `woodpecker/cache/nuget/packages`,启动时从镜像复制已有工具包作为初始缓存。
|
||||
|
||||
Agent 构建按 `build-musl-amd64`、`build-musl-arm64`、`build-glibc-amd64`、`build-glibc-arm64` 拆分。`ci/stage-node-image.py` 只把 Agent、`fleet-enroll` 的依赖工程和父目录构建配置放进还原层,文件时间固定;C# 源码进入后续编译层。四个 Linux RID 共用一个 Buildah store、工具链镜像和 `moshiro-nuget` 缓存挂载,首次从工具镜像的包目录初始化。restore 独占写入,后续编译和发布只读;镜像层命中时跳过 restore,依赖变化时仍复用已下载包。
|
||||
Agent 构建按 `build-musl-arm64`、`build-glibc-amd64`、`build-glibc-arm64` 拆分。`ci/stage-node-image.py` 只把 Agent、`fleet-enroll` 的依赖工程和父目录构建配置放进还原层,文件时间固定;C# 源码进入后续编译层。三个 Linux RID 共用一个 Buildah store、工具链镜像和 `moshiro-nuget` 缓存挂载,首次从工具镜像的包目录初始化。restore 独占写入,后续编译和发布只读;镜像层命中时跳过 restore,依赖变化时仍复用已下载包。
|
||||
|
||||
`Agent.Native.proj` 在一个 MSBuild 图内编译两份程序和公共依赖。随后两个独立 stage 用 `publish --no-build --no-restore` 完成 NativeAOT,Buildah `--jobs 2` 并行执行;中间目录随 stage 隔离。最终 scratch stage 只保留两份可执行文件,`ci/extract-node-binaries.sh` 在同一个 `buildah unshare` 会话内挂载、复制和卸载。`ci/package-linux-agent.sh` 生成原生安装归档,`ci/release-node-images.sh` 复用已发布归档生成 OCI 镜像。
|
||||
|
||||
任务结束时清理本次上下文、导出目录和临时包,失败退出也清理临时容器。构建持有共享 store 锁和当前 RID 的锁;清理需要独占 store 锁;`ci/cleanup-build-cache.sh` 清理超过 7 天的中间镜像与旧版本应用镜像,保留具名工具镜像和当前构建镜像,删除时不强制移除仍被引用的层。已退役的 Probe、独立 Agent 架构及索引 store,在存储元数据连续 7 天未更新且可取得独占锁时整目录清理;近期使用、锁定或没有可识别元数据的目录保留。NuGet 缓存挂载保留,不使用会同时删除挂载缓存的 `buildah prune`。`ci/build-runner-image.sh` 在持锁期间保留当前工具链和最近的上一份 OCI 导出归档。
|
||||
|
||||
所有镜像构建、索引及签名清单发布脚本通过 `ci/buildah-env.sh` 显式配置 Buildah 的 `graphroot` 和 `runroot`。Agent 原生构建的四个 RID 共用 `buildah-home/linux-agent`,Backend 和 OCI 发布使用各自的 store,运行状态留在当前 runner 的临时目录;容器内 UID 0 不再使各步骤落到同一个 `/var/lib/containers/storage`。`RUN` 默认使用 `chroot` isolation,避免额外的 OCI runtime/cgroup 嵌套;这与上面禁止的 agent 启动方式是不同阶段。
|
||||
所有镜像构建、索引及签名清单发布脚本通过 `ci/buildah-env.sh` 显式配置 Buildah 的 `graphroot` 和 `runroot`。Agent 原生构建的三个 RID 共用 `buildah-home/linux-agent`,Backend 和 OCI 发布使用各自的 store,运行状态留在当前 runner 的临时目录;容器内 UID 0 不再使各步骤落到同一个 `/var/lib/containers/storage`。`RUN` 默认使用 `chroot` isolation,避免额外的 OCI runtime/cgroup 嵌套;这与上面禁止的 agent 启动方式是不同阶段。
|
||||
|
||||
WSL 的 systemd 服务不会单独阻止发行版空闲退出。Windows 登录用户运行 `powershell -ExecutionPolicy Bypass -File ci/start-wsl-runner.ps1`,注册并启动隐藏的登录任务,持续运行 Debian 的前台 `sleep infinity`,让 CI server/agent 保持在线。任务使用当前用户的普通权限;需要暂停 WSL 时先停止任务 `MoShiro WSL runner (Debian)`。agent 单元等待 `user@1000.service` 并设置用户 D-Bus 地址,让 rootless Podman 使用已就绪的用户会话。
|
||||
|
||||
@@ -138,7 +138,7 @@ Pull request 和 `main` 的 push 会跑三个 workflow:
|
||||
| Backend | `registry.oeo.one/moshiro-dev/moshiro-backend:latest` | `registry.oeo.one/moshiro-dev/moshiro-backend:<版本>`(如 `0.4.1-dev.12-044ce0c`) |
|
||||
| Agent | `registry.oeo.one/moshiro-dev/moshiro-agent:latest` | `registry.oeo.one/moshiro-dev/moshiro-agent:<版本>` |
|
||||
|
||||
Agent 也发布架构固定标签 `:<版本>-amd64` 与 `:<版本>-arm64`。原生构建在 amd64 的 `sdk:10.0-noble-aot` 衍生 builder 中使用 AotAnywhere 编译四个 Linux RID,ARM64 无需 QEMU;builder 预热项目固定版本的 SDK、Zig 和运行时包,NuGet 使用共享的持久缓存挂载,restore 独占写入、编译与发布只读。运行基底为 `runtime-deps:10.0-alpine`。开发镜像不创建 Gitea Release,也不修改正式版 `moshiro/` 仓库中的标签。普通 main push 不会构建镜像。节点和 Backend 判断自己是不是开发构建,看构建信息里的 tag 含 `-dev.`(旧的 `dev-<sha>`、`main-<sha>` 也认)。
|
||||
Agent 也发布架构固定标签 `:<版本>-amd64` 与 `:<版本>-arm64`。原生构建在 amd64 的 `sdk:10.0-noble-aot` 衍生 builder 中使用 AotAnywhere 编译三个 Linux RID,ARM64 无需 QEMU;builder 预热项目固定版本的 SDK、Zig 和运行时包,NuGet 使用共享的持久缓存挂载,restore 独占写入、编译与发布只读。amd64 镜像基底为 `runtime-deps:10.0`,arm64 为 `runtime-deps:10.0-alpine`。开发镜像不创建 Gitea Release,也不修改正式版 `moshiro/` 仓库中的标签。普通 main push 不会构建镜像。节点和 Backend 判断自己是不是开发构建,看构建信息里的 tag 含 `-dev.`(旧的 `dev-<sha>`、`main-<sha>` 也认)。
|
||||
|
||||
### 正式版发布
|
||||
|
||||
@@ -192,7 +192,7 @@ Linux 产物比 Windows 大,是因为 .NET 的加密、压缩、网络本机
|
||||
|
||||
#### 原生一键安装与自动更新
|
||||
|
||||
管理端「添加 拨号方」提供 OpenWrt · 原生二进制 命令,以 root 执行。支持 ARM64/aarch64 和 x86_64,不需要容器或 .NET;自动安装依赖、验签下载、固定属主并注册、配置 procd。身份在 `/etc/moshiro/`,更新策略在 `/etc/moshiro-native.conf`(`CHANNEL=dev|release`、`POLICY=auto|manual`、`INTERVAL=30`)。动态 musl 正式包仍需 `libopenssl3`,实际设备兼容性需实机验证。
|
||||
管理端「添加 拨号方」提供 OpenWrt · 原生二进制 命令,以 root 执行。支持 ARM64/aarch64,不需要容器或 .NET;自动安装依赖、验签下载、固定属主并注册、配置 procd。身份在 `/etc/moshiro/`,更新策略在 `/etc/moshiro-native.conf`(`CHANNEL=dev|release`、`POLICY=auto|manual`、`INTERVAL=30`)。原生包使用静态 musl 可执行文件,实际设备兼容性需实机验证。
|
||||
|
||||
带 `[CI]` 的 main push 发布 dev,稳定 tag 发布 release,沿用 `gitea_token` 和 `release_signing_key`;Gitea generic package `moshiro-openwrt` 需允许匿名下载。制品发布后,在线节点收到通知就唤醒更新器,另有 30 秒轮询兜底,不等待 10 分钟。更新器验签、防重放、原子切换完整版本,健康检查失败回滚;这些步骤由独立的更新器完成,不在 拨号方 进程内执行。
|
||||
|
||||
|
||||
Reference in new issue
Block a user