feat: bundle multi-arch nginx for native fnOS stage 2
This commit is contained in:
@@ -11,22 +11,35 @@
|
||||
|
||||
构建过程不再引用 `F:\Fonu-main\havline`。
|
||||
|
||||
阶段一范围:
|
||||
阶段二范围:
|
||||
|
||||
- Go 主程序原生运行
|
||||
- 统一网关 `/app/havline`
|
||||
- Unix Socket `app.sock`
|
||||
- `cmd/main` 启动、停止和状态检查
|
||||
- amd64 与 arm64 双架构二进制
|
||||
- Nginx amd64 与 arm64 双架构二进制
|
||||
- Nginx 依赖库与 `mime.types`
|
||||
- HTTP 18080 与 HTTPS 9443
|
||||
|
||||
当前不包含:
|
||||
|
||||
- Nginx 二进制
|
||||
- frpc
|
||||
- cloudflared
|
||||
|
||||
这些依赖将在后续阶段加入。
|
||||
|
||||
## 构建前置条件
|
||||
|
||||
构建脚本需要本地存在用于提取 Nginx 的 Havline 镜像:
|
||||
|
||||
```text
|
||||
jayhub.top/mrlee/havline:1.9.0 amd64
|
||||
havline:1.9.0 arm64
|
||||
```
|
||||
|
||||
如果本地没有对应架构镜像,先加载 amd64 与 arm64 镜像归档。
|
||||
|
||||
## 构建
|
||||
|
||||
```powershell
|
||||
@@ -43,5 +56,17 @@ dist/havline-native-1.9.0.fpk
|
||||
构建脚本会:
|
||||
|
||||
1. 使用 `VITE_BASE_PATH=/app/havline/` 构建前端;
|
||||
2. 交叉编译 amd64 与 arm64 Go 二进制;
|
||||
3. 调用 `fnpack build` 打包。
|
||||
2. 从本地镜像提取 amd64 与 arm64 Nginx 及依赖库;
|
||||
3. 交叉编译 amd64 与 arm64 Go 二进制;
|
||||
4. 调用 `fnpack build` 打包。
|
||||
|
||||
## 真机注意
|
||||
|
||||
当前 Nginx 来自 Debian 12,依赖目标系统 glibc。飞牛设备建议满足:
|
||||
|
||||
```text
|
||||
glibc >= 2.36
|
||||
```
|
||||
|
||||
如果目标设备 glibc 版本较低,需要改为静态编译 Nginx 或打包完整
|
||||
loader 与 libc。
|
||||
|
||||
@@ -26,6 +26,12 @@ http {
|
||||
include ` + absNginxPath(cfg.NginxMimeTypes) + `;
|
||||
default_type application/octet-stream;
|
||||
|
||||
client_body_temp_path ` + absNginxPath(filepath.Join(cfg.NginxDir(), "temp", "client_body_temp")) + `;
|
||||
proxy_temp_path ` + absNginxPath(filepath.Join(cfg.NginxDir(), "temp", "proxy_temp")) + `;
|
||||
fastcgi_temp_path ` + absNginxPath(filepath.Join(cfg.NginxDir(), "temp", "fastcgi_temp")) + `;
|
||||
uwsgi_temp_path ` + absNginxPath(filepath.Join(cfg.NginxDir(), "temp", "uwsgi_temp")) + `;
|
||||
scgi_temp_path ` + absNginxPath(filepath.Join(cfg.NginxDir(), "temp", "scgi_temp")) + `;
|
||||
|
||||
log_format havline_access '$time_iso8601 $host $server_port $request_method $request_uri $status $request_time $remote_addr $upstream_addr $request_length $bytes_sent';
|
||||
access_log ` + absNginxPath(filepath.Join(cfg.LogsDir(), "access.log")) + ` havline_access;
|
||||
|
||||
|
||||
@@ -21,6 +21,55 @@ function Copy-Tree {
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-DockerCli {
|
||||
if ($env:DOCKER_BIN) { return $env:DOCKER_BIN }
|
||||
$command = Get-Command docker -ErrorAction SilentlyContinue
|
||||
if ($command) { return $command.Source }
|
||||
$default = "C:\Program Files\Docker\Docker\resources\bin\docker.exe"
|
||||
if (Test-Path -LiteralPath $default) { return $default }
|
||||
throw "找不到 docker 命令"
|
||||
}
|
||||
|
||||
function Export-Nginx {
|
||||
param(
|
||||
[string]$DockerBin,
|
||||
[string]$Platform,
|
||||
[string]$Arch,
|
||||
[string]$Image,
|
||||
[string]$OutputDir
|
||||
)
|
||||
|
||||
$archInfo = (& $DockerBin image inspect $Image --format '{{.Architecture}}' 2>$null)
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "找不到 Nginx 来源镜像:$Image"
|
||||
}
|
||||
if ($archInfo.Trim() -ne $Arch) {
|
||||
throw "镜像架构不匹配:$Image 是 $($archInfo.Trim()),需要 $Arch"
|
||||
}
|
||||
|
||||
$archDir = Join-Path $OutputDir $Arch
|
||||
New-Item -ItemType Directory -Force $archDir | Out-Null
|
||||
$script = @'
|
||||
set -e
|
||||
mkdir -p /out/lib
|
||||
cp /usr/sbin/nginx /out/nginx
|
||||
cp /etc/nginx/mime.types /out/mime.types
|
||||
ldd /usr/sbin/nginx | awk '/=> \// {print $3} /^\// {print $1}' | sort -u | while read lib; do
|
||||
case "$(basename "$lib")" in
|
||||
libc.so.6|ld-linux-*.so.*) continue ;;
|
||||
esac
|
||||
cp "$lib" /out/lib/
|
||||
done
|
||||
'@
|
||||
|
||||
& $DockerBin run --rm --platform $Platform -v "${archDir}:/out" --entrypoint sh $Image -c $script
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "提取 $Arch Nginx 失败,退出码:$LASTEXITCODE"
|
||||
}
|
||||
|
||||
Copy-Item -LiteralPath (Join-Path $archDir "mime.types") -Destination (Join-Path $OutputDir "mime.types") -Force
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $project)) {
|
||||
throw "找不到 Native 应用工程:$project"
|
||||
}
|
||||
@@ -67,6 +116,11 @@ if ($LASTEXITCODE -ge 8) {
|
||||
Copy-Tree -Source (Join-Path $mainRepo "migrations") -Destination (Join-Path $stage "app\migrations")
|
||||
Copy-Tree -Source (Join-Path $mainRepo "web\assets\image") -Destination (Join-Path $stage "app\web\assets\image")
|
||||
|
||||
$serverDir = Join-Path $stage "app\server"
|
||||
$dockerBin = Resolve-DockerCli
|
||||
Export-Nginx -DockerBin $dockerBin -Platform "linux/amd64" -Arch "amd64" -Image "jayhub.top/mrlee/havline:$version" -OutputDir $serverDir
|
||||
Export-Nginx -DockerBin $dockerBin -Platform "linux/arm64" -Arch "arm64" -Image "havline:$version" -OutputDir $serverDir
|
||||
|
||||
$env:CGO_ENABLED = "0"
|
||||
$env:GOOS = "linux"
|
||||
|
||||
|
||||
@@ -17,6 +17,18 @@ if [ ! -f "$BIN" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$BIN"
|
||||
NGINX_BIN="$TRIM_APPDEST/server/$ARCH_DIR/nginx"
|
||||
if [ ! -f "$NGINX_BIN" ]; then
|
||||
echo "找不到 Nginx 二进制:$NGINX_BIN" > "$TRIM_TEMP_LOGFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MIME_TYPES="$TRIM_APPDEST/server/mime.types"
|
||||
if [ ! -f "$MIME_TYPES" ]; then
|
||||
echo "找不到 Nginx mime.types:$MIME_TYPES" > "$TRIM_TEMP_LOGFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$BIN" "$NGINX_BIN"
|
||||
echo "Havline 数据目录已准备:$TRIM_PKGVAR"
|
||||
exit 0
|
||||
|
||||
@@ -58,8 +58,12 @@ start_app() {
|
||||
export HAVLINE_GATEWAY_SOCKET="$SOCKET_PATH"
|
||||
export HAVLINE_GATEWAY_PREFIX="/app/havline"
|
||||
export HAVLINE_UPDATER_SOCKET=""
|
||||
export HAVLINE_NGINX_BIN="$TRIM_APPDEST/server/$arch/nginx"
|
||||
export HAVLINE_NGINX_MIME_TYPES="$TRIM_APPDEST/server/mime.types"
|
||||
export HAVLINE_NGINX_PID="$TRIM_PKGVAR/nginx/nginx.pid"
|
||||
export HAVLINE_NGINX_HTTP_PORT="${wizard_nginx_http_port:-18080}"
|
||||
export HAVLINE_NGINX_HTTPS_PORT="${wizard_nginx_https_port:-9443}"
|
||||
export LD_LIBRARY_PATH="$TRIM_APPDEST/server/$arch/lib:${LD_LIBRARY_PATH:-}"
|
||||
export TZ="${wizard_timezone:-Asia/Shanghai}"
|
||||
|
||||
if [ -n "${wizard_initial_admin_password:-}" ]; then
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
appname = havline
|
||||
version = 1.9.0
|
||||
display_name = Havline
|
||||
desc = NAS 公网访问管理:原生应用阶段一
|
||||
desc = NAS 公网访问管理:原生应用阶段二
|
||||
platform = all
|
||||
source = thirdparty
|
||||
maintainer = Havline
|
||||
@@ -11,4 +11,4 @@ desktop_uidir = ui
|
||||
desktop_applaunchname = havline.main
|
||||
ctl_stop = true
|
||||
os_min_version = 1.1.3100
|
||||
changelog = 原生应用阶段一:Go 主程序、统一网关和启停脚本
|
||||
changelog = 原生应用阶段二:Nginx amd64/arm64 双架构打包
|
||||
|
||||
Reference in New Issue
Block a user