Исправить production builder для старых CPU без AVX2 и обновить документацию сборки
This commit is contained in:
+135
-44
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user