TypeCodes

github workflow构建哪吒探针FreeBSD安装包

之前写了关于如何在serv00/ct8机器上一键安装哪吒探针的内容,这里主要分享下如何构建这种运行在serv00/ct8这种FreeBSD操作系统上的哪吒探针面板二进制安装包。

当然,也可以直接了当的在github上查看https://github.com/vfhky/nezha-build的源代码,也可以直接下载代码构建出来的可用于serv00/ct8这种FreeBSD主机的哪吒面板安装包

https://github.com/vfhky/nezha-build

一、背景

由于哪吒官方没有提供FreeBSD的dashboard面板安装包,所以如果想在serv00/ct8上使用就得先自己构建一个。

可以看到serv00_ct8_nezha项目最初的几个版本(也是哪吒探针V0版本期间),是在安装期间直接拉取官方源代码构建出来的:即在serv00/ct8机器安装探针面板时,会先用命令go build -ldflags="-s -w --extldflags '-static -fpic' -X github.com/naiba/nezha/service/singleton.Version=${version_num}"构建得到安装包然后再安装。

这样带来的问题就是每次安装或者升级dashboard面板时都会消耗较长时间,所以在24年10月做了优化

  1. 创建一个新的github工程nezha-build使用 workflow 来构建哪吒面板FreeBSD安装包;
  2. 原有github工程serv00_ct8_nezha解耦后就只需从 nezha-build 下载FreeBSD包安装即可。

二、开启CGO

哪吒探针dashboard面板是go语言开发的,但是使用了go-sqlite3驱动,所以在交叉编译的时候必须得设置CGO_ENABLED=1,否则就会得到go-sqlite3 requires cgo to work的错误:

https://github.com/vfhky/nezha-build

三、交叉编译的困局

在开启CGO的前提下,最初nezha-build工程尝试在github workflow中使用 Ubuntu 环境,然后使用交叉编译工具链(如 Clang、musl-tools)来构建 FreeBSD amd64 二进制文件。但实际操作中,却遇到了各种棘手的难题:主要是缺少FreeBSD C头文件。

3.1 使用clang编译

先贴一下workflow核心代码:

      - name: Build
        uses: goreleaser/goreleaser-action@v6
        env:
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
          CGO_ENABLED: 1
          CC: /usr/bin/clang
        with:
          distribution: goreleaser
          version: "~> v2"
          workdir: nezha
          args: build --single-target --clean --skip=validate

然后运行workflow报错:

 build failed: failed to build for freebsd_amd64_v1: exit status 1: # runtime/cgo
 In file included from _cgo_export.c:3:
 /usr/include/stdlib.h:25:10: fatal error: 'bits/libc-header-start.h' file not found
 target: freebsd_amd64_v1
Error: The process '/__t/goreleaser-action/2.6.1/x64/goreleaser' failed with exit code 1

原因:在 Go runtime 尝试编译其 C 代码部分时,会默认使用当前 Ubuntu 系统中的 glibc 头文件,导致编译器尝试包含 bits/libc-header-start.h,从而引发错误。

3.2 使用musl-tools编译

先贴一下workflow核心代码:

      - name: Install dependencies
        run: |
          apt-get install -y clang lld musl-tools
      .......................

      - name: Build
        uses: goreleaser/goreleaser-action@v6
        env:
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
          CGO_ENABLED: 1
          CC: /usr/bin/musl-gcc # Use musl-gcc symlink
          LDFLAGS: "-static" # Crucial: Static linking with musl

然后运行workflow报错:

 build failed: failed to build for freebsd_amd64_v1: exit status 1: # runtime/cgo
 gcc_freebsd_amd64.c:7:10: fatal error: sys/signalvar.h: No such file or directory
     7 | #include <sys/signalvar.h>
       |          ^~~~~~~~~~~~~~~~~
 compilation terminated.
 target: freebsd_amd64_v1
Error: The process '/__t/goreleaser-action/2.6.1/x64/goreleaser' failed with exit code 1

原因:同样的,sys/signalvar.h 是 FreeBSD 特有的系统头文件,它在 Ubuntu 系统中并不存在。尽管我尝试使用 musl-gcc 作为交叉编译器,但是 Go runtime 自身的 C 代码仍然会尝试使用 Ubuntu 系统中的头文件,导致编译器无法找到 sys/signalvar.h。

3.3 困局

通过多次构建,我发现即使使用了clang 、musl-tools 和其它交叉编译工具链,仍然无法在 Ubuntu 环境下成功构建 FreeBSD amd64 二进制文件。

四、解决方案:vmactions/freebsd-vm

上述问题归根结底是由于构建环境不一致导致的。我在 Ubuntu 环境中尝试构建 FreeBSD 程序,虽然使用了交叉编译工具,但是 Go runtime 仍然会受到 Ubuntu 系统库的影响。因此,我需要一个真正的 FreeBSD 环境来进行构建。

vmactions/freebsd-vm 正是为此而生,它可以在 GitHub Actions 工作流程中启动一个真实的 FreeBSD 虚拟机,提供一个与目标环境完全一致的构建环境,从而彻底解决交叉编译带来的各种问题。

vmactions/freebsd-vm的大致原理:依赖于 QEMU 进行虚拟化,并通过 SSH 进行远程控制,以实现自动化任务。

1、在Ubuntu中运行 QEMU,然后创建 FreeBSD 虚拟机;
2、使用预构建的 FreeBSD 磁盘镜像。从源代码中的freebsd-vm/conf/14.1.conf可以看到诸如
OVA_LINK="https://github.com/vmactions/freebsd-builder/releases/download/v${BUILDER_VERSION}/freebsd-${VM_RELEASE}.qcow2.zst"
3、使用SSH公私钥连接 FreeBSD 虚拟机,上传哪吒探针dashboard面板源码并构建

五、总结

可以看到在相较于开启CGO后交叉编译构建哪吒探针面板FreeBSD安装包的复杂,使用vmactions/freebsd-vm提供的真实FreeBSD构建环境可以很简单的实现。

最后,大家可以在 https://github.com/vfhky/nezha-build 查看实现的源代码。也可以直接下载构建好的哪吒探针dashboard面板(FreeBSD版本),目前设置每天8点、16点、24点拉取官方最新代码进行构建,以便serv00和ct8主机一键安装哪吒探针V1版本工程能下载和安装到最新的探针面板。

打赏支持

Comments »