From d8dee0721339f69a2afc4c95a01f6340edf5ddd3 Mon Sep 17 00:00:00 2001 From: zuevav Date: Wed, 16 Sep 2026 00:48:56 +0300 Subject: [PATCH] =?UTF-8?q?feat(iso):=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=20B?= =?UTF-8?q?ridge&Join=20=D0=BD=D0=B0=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=20Debian=2013=20netinst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deploy/iso/build-iso.sh: пересборка официального netinst (xorriso, загрузочные записи BIOS и UEFI сохраняются), пункт по умолчанию «Установить Bridge&Join», текстовый установщик - preseed.cfg: русская локаль, Москва, DHCP, SSH и пакеты для bj; спрашиваются только пароли, диск и подтверждение стирания - bj-firstboot: при первой загрузке на экране сервера спрашивает ключ продукта и запускает bj-installer; адрес первичной настройки и код остаются на экране входа Co-Authored-By: Claude Opus 5 (1M context) --- deploy/iso/bj-firstboot | 42 +++++++++++++++++++ deploy/iso/bj-firstboot.service | 21 ++++++++++ deploy/iso/build-iso.sh | 73 +++++++++++++++++++++++++++++++++ deploy/iso/preseed.cfg | 71 ++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100755 deploy/iso/bj-firstboot create mode 100644 deploy/iso/bj-firstboot.service create mode 100755 deploy/iso/build-iso.sh create mode 100644 deploy/iso/preseed.cfg diff --git a/deploy/iso/bj-firstboot b/deploy/iso/bj-firstboot new file mode 100755 index 0000000..1ca4872 --- /dev/null +++ b/deploy/iso/bj-firstboot @@ -0,0 +1,42 @@ +#!/bin/bash +# Первая загрузка сервера, установленного с образа Bridge&Join: на экране сервера спрашивает ключ +# продукта и запускает bj-installer. После успешной установки служба выключается; адрес первичной +# настройки и одноразовый код остаются на экране входа (/etc/issue.d/bj-setup.issue). +set -u +MARK=/var/lib/bj/.bj/installed-from-iso +SERVER=https://lic.zetit.ru +CHANNEL=stable +[ -s /etc/bj/channel ] && CHANNEL=$(tr -d ' \n' < /etc/bj/channel) + +finish() { + mkdir -p "$(dirname "$MARK")" && date -Iseconds > "$MARK" + systemctl disable bj-firstboot.service >/dev/null 2>&1 +} + +clear +printf '\n Bridge&Join: установка на сервер\n ────────────────────────────────────────────────\n\n' +printf ' Debian установлен. Осталось установить bj.\n' +printf ' Нужен ключ продукта (BJ-XXXX-XXXX-XXXX): он есть в портале клиента %s/portal/\n\n' "$SERVER" + +for i in $(seq 1 60); do + curl -fsS -m 5 -o /dev/null "$SERVER/healthz" && break + [ "$i" = 1 ] && printf ' Жду сеть и связь с %s…\n' "$SERVER" + sleep 2 +done + +while true; do + read -r -p " Ключ продукта (пусто — установить позже): " CODE + CODE=$(printf '%s' "$CODE" | tr -d ' ' | tr '[:lower:]' '[:upper:]') + if [ -z "$CODE" ]; then + printf '\n Установка bj отложена. Позже выполните: sudo bj-installer install --code КЛЮЧ-ПРОДУКТА\n\n' + finish + sleep 3 + exit 0 + fi + if /usr/local/sbin/bj-installer install --code "$CODE" --server "$SERVER" --channel "$CHANNEL"; then + finish + read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ + exit 0 + fi + printf '\n Установка не завершилась. Проверьте ключ продукта и сеть и попробуйте ещё раз.\n\n' +done diff --git a/deploy/iso/bj-firstboot.service b/deploy/iso/bj-firstboot.service new file mode 100644 index 0000000..24d7c08 --- /dev/null +++ b/deploy/iso/bj-firstboot.service @@ -0,0 +1,21 @@ +[Unit] +Description=Bridge&Join: установка bj при первой загрузке (ключ продукта на экране сервера) +After=network-online.target systemd-user-sessions.service +Wants=network-online.target +Before=getty@tty1.service +ConditionPathExists=!/var/lib/bj/.bj/installed-from-iso + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/bj-firstboot +StandardInput=tty +StandardOutput=tty +StandardError=tty +TTYPath=/dev/tty1 +TTYReset=yes +TTYVHangup=yes +TimeoutSec=0 +RemainAfterExit=no + +[Install] +WantedBy=multi-user.target diff --git a/deploy/iso/build-iso.sh b/deploy/iso/build-iso.sh new file mode 100755 index 0000000..b820f21 --- /dev/null +++ b/deploy/iso/build-iso.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# Сборка образа ISO Bridge&Join на основе официального Debian 13 netinst. +# +# deploy/iso/build-iso.sh <версия> [канал] [выходной.iso] +# +# В образ добавляются: файл ответов установщику (preseed.cfg), bj-installer и служба первой загрузки. +# Загрузочное меню BIOS (isolinux) и UEFI (grub) по умолчанию запускает установку с этими ответами. +# Загрузочные записи исходного образа сохраняются (xorriso -boot_image any replay). +# Нужен xorriso. Проверка исходного образа — по SHA256SUMS с cdimage.debian.org. +set -eu +SRC=${1:?исходный debian-13.x-amd64-netinst.iso} +INSTALLER=${2:?файл bj-installer} +VERSION=${3:?версия образа, например 2026.10.1} +CHANNEL=${4:-stable} +OUT=${5:-bj-debian13-$VERSION.iso} +HERE=$(cd "$(dirname "$0")" && pwd) +command -v xorriso >/dev/null || { echo "нужен xorriso: apt-get install xorriso"; exit 1; } +WORK=$(mktemp -d) +trap 'rm -rf "$WORK"' EXIT + +mkdir -p "$WORK/bj" "$WORK/preseed" "$WORK/isolinux" "$WORK/grub" +cp "$HERE/preseed.cfg" "$WORK/preseed/bj.cfg" +install -m 0755 "$INSTALLER" "$WORK/bj/bj-installer" +install -m 0755 "$HERE/bj-firstboot" "$WORK/bj/bj-firstboot" +cp "$HERE/bj-firstboot.service" "$WORK/bj/bj-firstboot.service" +echo "$CHANNEL" > "$WORK/bj/channel" +echo "$VERSION" > "$WORK/bj/version" + +BOOT="auto=true priority=high preseed/file=/cdrom/preseed/bj.cfg language=ru country=RU locale=ru_RU.UTF-8 keyboard-configuration/xkb-keymap=ru" + +# BIOS: пункт по умолчанию в isolinux +xorriso -osirrox on -indev "$SRC" -extract /isolinux/txt.cfg "$WORK/isolinux/txt.orig" >/dev/null 2>&1 +KERNEL=$(awk '/^\s*kernel/{print $2; exit}' "$WORK/isolinux/txt.orig") +INITRD=$(grep -o 'initrd=[^ ]*' "$WORK/isolinux/txt.orig" | head -1 | cut -d= -f2) +{ + echo "default bj" + echo "label bj" + echo " menu label ^Установить Bridge&Join $VERSION (Debian 13)" + echo " menu default" + echo " kernel $KERNEL" + echo " append vga=788 initrd=$INITRD $BOOT --- quiet" + sed '/menu default/d;/^default /d' "$WORK/isolinux/txt.orig" +} > "$WORK/isolinux/txt.cfg" +xorriso -osirrox on -indev "$SRC" -extract /isolinux/isolinux.cfg "$WORK/isolinux/isolinux.cfg" >/dev/null 2>&1 +sed -i 's/^timeout .*/timeout 100/; s/^prompt .*/prompt 0/' "$WORK/isolinux/isolinux.cfg" +grep -q '^timeout' "$WORK/isolinux/isolinux.cfg" || echo "timeout 100" >> "$WORK/isolinux/isolinux.cfg" + +# UEFI: первый пункт в grub +xorriso -osirrox on -indev "$SRC" -extract /boot/grub/grub.cfg "$WORK/grub/grub.orig" >/dev/null 2>&1 +# текстовый установщик (без gtk), как в BIOS: установка идёт без графической среды +LINUX=$(awk '/^\s*linux\s/ && $2 !~ /gtk/ {print $2; exit}' "$WORK/grub/grub.orig") +INITRDG=$(awk '/^\s*initrd\s/ && $2 !~ /gtk/ {print $2; exit}' "$WORK/grub/grub.orig") +{ + echo "set default=0" + echo "set timeout=10" + echo "menuentry --hotkey=i 'Установить Bridge&Join $VERSION (Debian 13)' {" + echo " set background_color=black" + echo " linux $LINUX vga=788 $BOOT --- quiet" + echo " initrd $INITRDG" + echo "}" + sed '/^set default/d;/^set timeout/d' "$WORK/grub/grub.orig" +} > "$WORK/grub/grub.cfg" + +rm -f "$OUT" +xorriso -indev "$SRC" -outdev "$OUT" -boot_image any replay \ + -volid "BJ_DEBIAN13" \ + -map "$WORK/preseed" /preseed \ + -map "$WORK/bj" /bj \ + -map "$WORK/isolinux/txt.cfg" /isolinux/txt.cfg \ + -map "$WORK/isolinux/isolinux.cfg" /isolinux/isolinux.cfg \ + -map "$WORK/grub/grub.cfg" /boot/grub/grub.cfg \ + -end >/dev/null 2>"$WORK/xorriso.log" || { cat "$WORK/xorriso.log"; exit 1; } +echo "Образ собран: $OUT ($(du -h "$OUT" | cut -f1)), канал обновлений $CHANNEL" diff --git a/deploy/iso/preseed.cfg b/deploy/iso/preseed.cfg new file mode 100644 index 0000000..0edd616 --- /dev/null +++ b/deploy/iso/preseed.cfg @@ -0,0 +1,71 @@ +#_preseed_V1 +# Ответы установщику Debian 13 для образа Bridge&Join (deploy/iso/build-iso.sh). +# Спрашиваются только пароли, диск (если их несколько) и подтверждение стирания; остальное задано здесь. +# После установки служба bj-firstboot на экране сервера спросит ключ продукта и установит bj. + +# Язык, клавиатура, время +d-i debian-installer/language string ru +d-i debian-installer/country string RU +d-i debian-installer/locale string ru_RU.UTF-8 +d-i localechooser/supported-locales multiselect ru_RU.UTF-8, en_US.UTF-8 +d-i keyboard-configuration/xkb-keymap select ru +d-i keyboard-configuration/toggle select Alt+Shift +d-i clock-setup/utc boolean true +d-i time/zone string Europe/Moscow +d-i clock-setup/ntp boolean true + +# Сеть: DHCP на первом подключённом интерфейсе +d-i netcfg/choose_interface select auto +d-i netcfg/get_hostname string bj-server +d-i netcfg/get_domain string +d-i netcfg/hostname string bj-server +d-i hw-detect/load_firmware boolean true + +# Зеркало пакетов +d-i mirror/country string manual +d-i mirror/http/hostname string deb.debian.org +d-i mirror/http/directory string /debian +d-i mirror/http/proxy string +d-i apt-setup/cdrom/set-first boolean false +d-i apt-setup/non-free-firmware boolean true +d-i apt-setup/services-select multiselect security, updates + +# Учётные записи: пароль root и администратор ОС задаются при установке +d-i passwd/root-login boolean true +d-i passwd/make-user boolean true +d-i passwd/user-fullname string Администратор +d-i passwd/username string bjadmin + +# Разметка: весь выбранный диск, одна файловая система; диск и стирание подтверждаются при установке +d-i partman-auto/method string regular +d-i partman-auto/choose_recipe select atomic +d-i partman-auto-lvm/guided_size string max +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/default_filesystem string ext4 +d-i partman-md/confirm boolean true +d-i partman-lvm/device_remove_lvm boolean true +d-i partman-md/device_remove_md boolean true + +# Пакеты: без графики; SSH и всё, что нужно bj, ставится сразу +tasksel tasksel/first multiselect standard, ssh-server +d-i pkgsel/include string ca-certificates curl postgresql postgresql-client default-jre-headless pcscd python3 sudo +d-i pkgsel/upgrade select safe-upgrade +popularity-contest popularity-contest/participate boolean false + +# Загрузчик +d-i grub-installer/only_debian boolean true +d-i grub-installer/with_other_os boolean false +d-i grub-installer/bootdev string default + +# Установщик bj и служба первой загрузки (файлы лежат в /bj на образе) +d-i preseed/late_command string \ + install -m 0755 /cdrom/bj/bj-installer /target/usr/local/sbin/bj-installer; \ + install -m 0755 /cdrom/bj/bj-firstboot /target/usr/local/sbin/bj-firstboot; \ + install -m 0644 /cdrom/bj/bj-firstboot.service /target/etc/systemd/system/bj-firstboot.service; \ + mkdir -p /target/etc/bj; \ + if [ -f /cdrom/bj/channel ]; then install -m 0644 /cdrom/bj/channel /target/etc/bj/channel; fi; \ + in-target systemctl enable bj-firstboot.service + +d-i finish-install/reboot_in_progress note +d-i cdrom-detect/eject boolean true