Исправить production builder для старых CPU без AVX2 и обновить документацию сборки

This commit is contained in:
2026-05-05 23:14:09 +05:00
parent 9368846405
commit 50f6c70722
4 changed files with 233 additions and 83 deletions
+135 -44
View File
@@ -1,39 +1,104 @@
# HY2XS production builder
## Назначение
Этот каталог содержит production builder для HY2XS.
[`build.sh`](build.sh) собирает переносимый установочный пакет HY2XS для production-развёртывания.
Builder собирает один переносимый install-archive:
Итоговый архив создаётся в [`dist`](../../dist) и предназначен для установки на чистый Debian 13 amd64 без сборки на целевом сервере.
```text
dist/hy2xs-install-<version>.tar.gz
```
## Поддерживаемая среда сборки
Этот архив переносится на production server, распаковывается и устанавливается через [`install.sh`](../../package/install.sh).
Builder поддерживает только:
На production server не должно быть сборки из исходников: без `go build`, без `bun install`, без `pnpm install`, без frontend build и без TypeScript transpilation.
## Что где лежит
Основные части проекта:
- [`tools/build/build.sh`](build.sh) — главный entrypoint сборки.
- [`tools/build/lib/deps.sh`](lib/deps.sh) — проверка Debian/amd64, установка build dependencies, установка Go/Bun/Node.js/pnpm.
- [`tools/build/lib/package.sh`](lib/package.sh) — сборка orchestrator, сборка HY2XS admin, создание stage directory и tar.gz архива.
- [`tools/build/lib/verify.sh`](lib/verify.sh) — проверка структуры репозитория и итогового архива.
- [`tools/build/hysteria-lock.env`](hysteria-lock.env) — pinned версия, URL и SHA256 upstream Hysteria2 binary.
- [`orchestrator`](../../orchestrator) — TypeScript/Bun install-only orchestrator.
- [`apps`](../../apps) — HY2XS admin fork: backend на Go и frontend.
- [`package`](../../package) — skeleton будущего install package: `install.sh`, templates, systemd units, default config.
- [`dist`](../../dist) — итоговые архивы. Создаётся builder'ом, в git обычно не хранится.
- [`.toolchain`](../../.toolchain) — локальный toolchain builder'а. Создаётся автоматически, в git не хранится.
## Требования к build machine
Production build поддерживается только на:
- Debian 13;
- amd64 / x86_64;
- bash;
- доступ к интернету для установки build-зависимостей и toolchain.
- root или пользователь с `sudo`;
- доступ в интернет.
Windows/macOS не являются production build host. На Windows можно править исходники, но финальную сборку нужно выполнять на Debian 13 amd64.
Нужен outbound HTTPS/DNS до:
- Debian apt repositories;
- `go.dev`;
- `github.com`;
- `nodejs.org`;
- npm registry.
Windows и macOS можно использовать для редактирования исходников, но финальную production-сборку надо делать на Debian 13 amd64.
## Что builder делает сам
При запуске builder:
1. Проверяет ОС и архитектуру build host.
1. Проверяет, что host — Debian 13 amd64.
2. Проверяет структуру репозитория.
3. Доставляет отсутствующие системные build-зависимости через `apt-get`.
4. Проверяет и при необходимости скачивает локальный toolchain:
3. Устанавливает недостающие системные build dependencies через `apt-get`.
4. Проверяет или скачивает локальные версии:
- Go `1.21.13`;
- Bun `1.1.45`;
- Node.js `20.19.0`;
- pnpm `9.15.9`.
5. Собирает install-only orchestrator под Linux amd64.
6. Собирает bundled HY2XS admin под Linux amd64.
7. Формирует metadata и checksums.
8. Создаёт архив install package.
9. Проверяет состав итогового архива.
5. Собирает install-only orchestrator в standalone binary.
6. Собирает frontend HY2XS admin.
7. Собирает backend HY2XS admin в Linux amd64 binary.
8. Копирует package skeleton.
9. Записывает metadata и checksums.
10. Создаёт `dist/hy2xs-install-<version>.tar.gz`.
11. Проверяет, что архив содержит обязательные файлы.
## Важное про Bun и старые CPU
Bun имеет два Linux x64 artifact'а:
- `bun-linux-x64` — обычный build;
- `bun-linux-x64-baseline` — build для CPU без AVX2.
Если CPU не поддерживает AVX2, обычный Bun может падать с `Illegal instruction`.
Builder автоматически проверяет [`/proc/cpuinfo`](../../fix17.txt).
По умолчанию:
```bash
BUN_FLAVOR=auto
```
Логика:
- если CPU поддерживает AVX2, используется `bun-linux-x64`;
- если CPU не поддерживает AVX2, используется `bun-linux-x64-baseline`.
Можно принудительно задать flavor:
```bash
BUN_FLAVOR=x64 ./tools/build/build.sh
```
или:
```bash
BUN_FLAVOR=x64-baseline ./tools/build/build.sh
```
## Запуск
@@ -43,47 +108,73 @@ Windows/macOS не являются production build host. На Windows можн
./tools/build/build.sh
```
С явной версией пакета:
С явной версией и build id:
```bash
PACKAGE_VERSION=0.1.0 ./tools/build/build.sh
PACKAGE_VERSION=0.1.6 \
BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ) \
./tools/build/build.sh
```
С явным build id:
## Проверка результата
Проверка архива:
```bash
PACKAGE_VERSION=0.1.0 BUILD_ID=prod-20260425-001 ./tools/build/build.sh
ls -lh dist/hy2xs-install-0.1.6.tar.gz
sha256sum dist/hy2xs-install-0.1.6.tar.gz | tee dist/hy2xs-install-0.1.6.tar.gz.sha256
```
## Локальный toolchain
Builder ставит управляемый toolchain в [`.toolchain`](../../.toolchain) и не требует ручной установки Go/Bun/Node/pnpm в систему.
Если нужная версия уже установлена глобально, builder может использовать её. Если версия не совпадает, будет скачана локальная версия.
## Важные ограничения
- Builder не ставит HY2XS на сервер.
- Builder не выполняет target install.
- Builder не собирает ничего на target machine.
- Builder не вендорит бинарь Hysteria2 в пакет: Hysteria2 скачивается install layer'ом с official upstream.
- Итоговый пакет не должен содержать build scripts, `.toolchain` или временные каталоги.
## Результат
После успешной сборки появится архив:
Проверка обязательных файлов:
```bash
dist/hy2xs-install-<version>.tar.gz
tar -tzf dist/hy2xs-install-0.1.6.tar.gz | grep -E '^(hy2xs-install/install.sh|hy2xs-install/orchestrator/hy2xs-orchestrator|hy2xs-install/ui/hy2xs-admin/hy2xs-admin|hy2xs-install/metadata/checksums.txt)$'
```
Его нужно перенести на target Debian 13 amd64, распаковать и запустить [`install.sh`](../../package/install.sh) от root.
Проверка metadata:
```bash
tar -xOzf dist/hy2xs-install-0.1.6.tar.gz hy2xs-install/metadata/package.env
```
## Полезные переменные
- `PACKAGE_VERSION=0.1.6`
- `BUILD_ID=prod-$(date -u +%Y%m%dT%H%M%SZ)`
- `BUN_FLAVOR=auto|x64|x64-baseline`
- `TOOLCHAIN_DIR=/custom/path/.toolchain`
- `VERIFY_TOOLCHAIN_CHECKSUMS=true`
## Диагностика
Если сборка падает:
Проверить AVX2:
1. Проверьте, что host — Debian 13 amd64.
2. Проверьте доступ к `go.dev`, `github.com`, `nodejs.org`, npm registry и apt repositories.
3. Удалите [`.toolchain`](../../.toolchain) и повторите запуск, если toolchain скачался повреждённым.
4. Проверьте lock-файлы [`bun.lock`](../../orchestrator/bun.lock), [`pnpm-lock.yaml`](../../apps/frontend/pnpm-lock.yaml), [`go.sum`](../../apps/go.sum).
```bash
grep -m1 '^flags' /proc/cpuinfo | grep -qw avx2 && echo 'CPU has AVX2' || echo 'CPU has NO AVX2; Bun baseline is required'
```
Проверить Bun:
```bash
.toolchain/bun/bin/bun --version
echo "bun_exit=$?"
```
Если есть `Illegal instruction`, удалите старый Bun и пересоберите:
```bash
rm -rf .toolchain/bun .toolchain/bun-tmp
rm -f .toolchain/downloads/bun-linux-x64-*.zip
rm -f .toolchain/downloads/bun-linux-x64-baseline-*.zip
PACKAGE_VERSION=0.1.6 ./tools/build/build.sh
```
Проверить shell syntax:
```bash
bash -n tools/build/build.sh
bash -n tools/build/lib/common.sh
bash -n tools/build/lib/deps.sh
bash -n tools/build/lib/package.sh
bash -n tools/build/lib/verify.sh
```
+91 -18
View File
@@ -10,6 +10,7 @@ VERIFY_TOOLCHAIN_CHECKSUMS="${VERIFY_TOOLCHAIN_CHECKSUMS:-false}"
GO_ARCHIVE_SHA256="${GO_ARCHIVE_SHA256:-}"
NODE_ARCHIVE_SHA256="${NODE_ARCHIVE_SHA256:-}"
BUN_ARCHIVE_SHA256="${BUN_ARCHIVE_SHA256:-}"
BUN_FLAVOR="${BUN_FLAVOR:-auto}"
verify_archive_sha256() {
local archive="$1"
@@ -119,30 +120,102 @@ ensure_go() {
[ "$(go_version "$GO_BIN")" = "$GO_REQUIRED" ] || fail "Go version mismatch: required $GO_REQUIRED, got $($GO_BIN version)"
}
cpu_has_avx2() {
grep -m1 '^flags' /proc/cpuinfo 2>/dev/null | grep -qw avx2
}
select_bun_artifact() {
case "$BUN_FLAVOR" in
auto)
if cpu_has_avx2; then
BUN_ARTIFACT="bun-linux-x64"
else
BUN_ARTIFACT="bun-linux-x64-baseline"
fi
;;
x64|bun-linux-x64)
BUN_ARTIFACT="bun-linux-x64"
;;
baseline|x64-baseline|bun-linux-x64-baseline)
BUN_ARTIFACT="bun-linux-x64-baseline"
;;
*)
fail "unsupported BUN_FLAVOR: $BUN_FLAVOR (use auto, x64, or x64-baseline)"
;;
esac
BUN_COMPILE_TARGET="$BUN_ARTIFACT"
export BUN_ARTIFACT BUN_COMPILE_TARGET
}
bun_version() {
local bun="$1"
"$bun" --version 2>/dev/null || true
}
ensure_bun() {
select_bun_artifact
local managed="$TOOLCHAIN_DIR/bun/bin/bun"
if [ -x "$managed" ] && [ "$($managed --version)" = "$BUN_REQUIRED" ]; then
BUN_BIN="$managed"
elif command -v bun >/dev/null 2>&1 && [ "$(bun --version)" = "$BUN_REQUIRED" ]; then
BUN_BIN="$(command -v bun)"
else
log_info "Installing Bun $BUN_REQUIRED into $TOOLCHAIN_DIR/bun"
mkdir -p "$TOOLCHAIN_DIR/downloads" "$TOOLCHAIN_DIR/bun"
local archive="$TOOLCHAIN_DIR/downloads/bun-linux-x64-${BUN_REQUIRED}.zip"
download_file "https://github.com/oven-sh/bun/releases/download/bun-v${BUN_REQUIRED}/bun-linux-x64.zip" "$archive"
verify_archive_sha256 "$archive" "$BUN_ARCHIVE_SHA256" "BUN_ARCHIVE"
rm -rf "$TOOLCHAIN_DIR/bun-tmp" "$TOOLCHAIN_DIR/bun"
mkdir -p "$TOOLCHAIN_DIR/bun-tmp"
unzip -q "$archive" -d "$TOOLCHAIN_DIR/bun-tmp"
mkdir -p "$TOOLCHAIN_DIR/bun/bin"
install -m 0755 "$TOOLCHAIN_DIR/bun-tmp/bun-linux-x64/bun" "$managed"
rm -rf "$TOOLCHAIN_DIR/bun-tmp"
BUN_BIN="$managed"
local selected_bun=""
local actual=""
if [ -x "$managed" ]; then
actual="$(bun_version "$managed")"
if [ "$actual" = "$BUN_REQUIRED" ]; then
selected_bun="$managed"
else
log_info "Ignoring managed Bun at $managed: required $BUN_REQUIRED, got ${actual:-failed to execute}"
fi
fi
if [ -z "$selected_bun" ] && command -v bun >/dev/null 2>&1; then
local system_bun
system_bun="$(command -v bun)"
if [ "$system_bun" != "$managed" ]; then
actual="$(bun_version "$system_bun")"
if [ "$actual" = "$BUN_REQUIRED" ]; then
selected_bun="$system_bun"
else
log_info "Ignoring system Bun at $system_bun: required $BUN_REQUIRED, got ${actual:-failed to execute}"
fi
fi
fi
if [ -z "$selected_bun" ]; then
log_info "Installing Bun $BUN_REQUIRED ($BUN_ARTIFACT) into $TOOLCHAIN_DIR/bun"
mkdir -p "$TOOLCHAIN_DIR/downloads" "$TOOLCHAIN_DIR/bun"
local archive="$TOOLCHAIN_DIR/downloads/${BUN_ARTIFACT}-${BUN_REQUIRED}.zip"
download_file "https://github.com/oven-sh/bun/releases/download/bun-v${BUN_REQUIRED}/${BUN_ARTIFACT}.zip" "$archive"
verify_archive_sha256 "$archive" "$BUN_ARCHIVE_SHA256" "BUN_ARCHIVE"
rm -rf "$TOOLCHAIN_DIR/bun-tmp" "$TOOLCHAIN_DIR/bun"
mkdir -p "$TOOLCHAIN_DIR/bun-tmp"
unzip -q "$archive" -d "$TOOLCHAIN_DIR/bun-tmp"
mkdir -p "$TOOLCHAIN_DIR/bun/bin"
install -m 0755 "$TOOLCHAIN_DIR/bun-tmp/${BUN_ARTIFACT}/bun" "$managed"
rm -rf "$TOOLCHAIN_DIR/bun-tmp"
selected_bun="$managed"
fi
BUN_BIN="$selected_bun"
export BUN_BIN
export PATH="$(dirname "$BUN_BIN"):$PATH"
[ "$($BUN_BIN --version)" = "$BUN_REQUIRED" ] || fail "Bun version mismatch: required $BUN_REQUIRED, got $($BUN_BIN --version)"
actual="$(bun_version "$BUN_BIN")"
if [ "$actual" != "$BUN_REQUIRED" ]; then
fail "Bun version mismatch: required $BUN_REQUIRED, got ${actual:-failed to execute}. Selected artifact: ${BUN_ARTIFACT}. On old CPUs without AVX2 use BUN_FLAVOR=x64-baseline."
fi
log_info "Using Bun $actual; artifact=$BUN_ARTIFACT; compile_target=$BUN_COMPILE_TARGET"
}
node_version() {
+7 -1
View File
@@ -26,11 +26,16 @@ prepare_stage() {
}
build_orchestrator() {
local bun_compile_target="${BUN_COMPILE_TARGET:-bun-linux-x64}"
log_info "Building orchestrator with Bun compile target: $bun_compile_target"
(
cd orchestrator
"$BUN_BIN" install --frozen-lockfile
"$BUN_BIN" build src/cli.ts --compile --target=bun-linux-x64 --outfile ../"$STAGE_DIR"/orchestrator/hy2xs-orchestrator
"$BUN_BIN" build src/cli.ts --compile --target="$bun_compile_target" --outfile ../"$STAGE_DIR"/orchestrator/hy2xs-orchestrator
)
chmod 0755 "$STAGE_DIR/orchestrator/hy2xs-orchestrator"
}
@@ -90,6 +95,7 @@ write_metadata() {
printf 'orchestrator_stack=Bun+TypeScript\n'
printf 'go_version=%s\n' "$($GO_BIN version)"
printf 'bun_version=%s\n' "$($BUN_BIN --version)"
printf 'bun_compile_target=%s\n' "${BUN_COMPILE_TARGET:-unknown}"
printf 'node_version=%s\n' "$($NODE_BIN --version)"
printf 'pnpm_version=%s\n' "$($PNPM_BIN --version)"
printf 'hysteria_source=official-upstream\n'