486 lines
17 KiB
Bash
Executable File
486 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# ZBrain VM Bootstrap
|
|
# ====================
|
|
# Подготавливает чистую Ubuntu 22.04 VM к работе как ZBrain хост.
|
|
# Устанавливает: Postgres 16 + pgvector, Node 22 LTS, Bun, Docker, gbrain.
|
|
#
|
|
# Использование:
|
|
# sudo bash scripts/bootstrap-vm.sh
|
|
#
|
|
# Предполагается: запуск от root на свежей Ubuntu 22.04 LTS.
|
|
# Скрипт идемпотентный - можно перезапускать.
|
|
|
|
set -euo pipefail
|
|
|
|
# ============================================================
|
|
# Конфигурация - правь под себя ПЕРЕД запуском
|
|
# ============================================================
|
|
ZBRAIN_USER="${ZBRAIN_USER:-zbrain}"
|
|
ZBRAIN_HOME="/opt/zbrain"
|
|
ZBRAIN_CONFIG_DIR="/etc/zbrain"
|
|
ZBRAIN_DATA_DIR="/var/lib/zbrain"
|
|
ZBRAIN_LOG_DIR="/var/log/zbrain"
|
|
|
|
# FNA-прокси для исходящих запросов к OpenAI/Anthropic
|
|
FNA_PROXY="${FNA_PROXY:-http://client_001:PASSWORD@fna.zetit.ru:3128}"
|
|
|
|
POSTGRES_VERSION="16"
|
|
NODE_VERSION="22"
|
|
GBRAIN_VERSION="${GBRAIN_VERSION:-master}" # потом закрепим тег после первого деплоя
|
|
GBRAIN_REPO="${GBRAIN_REPO:-https://git.zetit.ru/zuevav/gbrain-mirror.git}"
|
|
|
|
# RAM в гигабайтах (для тюнинга Postgres)
|
|
TOTAL_RAM_GB="${TOTAL_RAM_GB:-8}"
|
|
|
|
# ============================================================
|
|
# Утилиты
|
|
# ============================================================
|
|
log() {
|
|
echo -e "\033[1;34m[$(date +'%H:%M:%S')] $*\033[0m"
|
|
}
|
|
|
|
err() {
|
|
echo -e "\033[1;31m[ERROR] $*\033[0m" >&2
|
|
}
|
|
|
|
require_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
err "Этот скрипт должен запускаться от root (sudo)."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_ubuntu() {
|
|
if ! grep -q "Ubuntu 22.04" /etc/os-release 2>/dev/null; then
|
|
err "Скрипт рассчитан на Ubuntu 22.04 LTS."
|
|
err "Текущая система:"
|
|
cat /etc/os-release | grep PRETTY_NAME >&2 || true
|
|
read -p "Продолжить на свой страх и риск? [y/N] " -n 1 -r
|
|
echo
|
|
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 1: Базовые пакеты и обновления
|
|
# ============================================================
|
|
step_base_packages() {
|
|
log "Шаг 1: Базовые пакеты"
|
|
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y -qq \
|
|
curl wget gnupg lsb-release ca-certificates \
|
|
build-essential git \
|
|
ufw fail2ban \
|
|
htop iotop net-tools \
|
|
unzip jq \
|
|
software-properties-common \
|
|
apt-transport-https \
|
|
chrony # точное время для аудит-логов
|
|
|
|
log "Шаг 1: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 2: Создание пользователя zbrain
|
|
# ============================================================
|
|
step_create_user() {
|
|
log "Шаг 2: Пользователь $ZBRAIN_USER"
|
|
|
|
if ! id "$ZBRAIN_USER" &>/dev/null; then
|
|
useradd --system --create-home --shell /bin/bash "$ZBRAIN_USER"
|
|
log "Создан пользователь $ZBRAIN_USER"
|
|
fi
|
|
|
|
mkdir -p "$ZBRAIN_HOME" "$ZBRAIN_CONFIG_DIR" "$ZBRAIN_DATA_DIR" "$ZBRAIN_LOG_DIR"
|
|
chown -R "$ZBRAIN_USER:$ZBRAIN_USER" "$ZBRAIN_HOME" "$ZBRAIN_DATA_DIR" "$ZBRAIN_LOG_DIR"
|
|
chmod 750 "$ZBRAIN_CONFIG_DIR" # секреты - 750
|
|
|
|
log "Шаг 2: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 3: Системные параметры (sysctl, swap, файрвол)
|
|
# ============================================================
|
|
step_system_tuning() {
|
|
log "Шаг 3: Системные параметры"
|
|
|
|
# Swap для защиты от OOM
|
|
if [[ ! -f /swapfile ]]; then
|
|
fallocate -l 4G /swapfile
|
|
chmod 600 /swapfile
|
|
mkswap /swapfile
|
|
swapon /swapfile
|
|
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
|
log "Создан swap 4G"
|
|
fi
|
|
|
|
# sysctl для Postgres + сети
|
|
cat > /etc/sysctl.d/99-zbrain.conf <<EOF
|
|
# ZBrain system tuning
|
|
vm.swappiness = 10
|
|
vm.overcommit_memory = 2
|
|
vm.overcommit_ratio = 80
|
|
vm.dirty_background_ratio = 5
|
|
vm.dirty_ratio = 10
|
|
|
|
# Сетевые буферы
|
|
net.core.rmem_max = 16777216
|
|
net.core.wmem_max = 16777216
|
|
net.ipv4.tcp_rmem = 4096 87380 16777216
|
|
net.ipv4.tcp_wmem = 4096 65536 16777216
|
|
|
|
# Защита
|
|
net.ipv4.tcp_syncookies = 1
|
|
net.ipv4.conf.all.rp_filter = 1
|
|
EOF
|
|
sysctl -p /etc/sysctl.d/99-zbrain.conf >/dev/null
|
|
|
|
# UFW firewall
|
|
ufw --force reset >/dev/null
|
|
ufw default deny incoming
|
|
ufw default allow outgoing
|
|
ufw allow 22/tcp comment 'SSH'
|
|
ufw allow 80/tcp comment 'HTTP (redirect to HTTPS)'
|
|
ufw allow 443/tcp comment 'HTTPS'
|
|
# Postgres - ТОЛЬКО localhost, никаких ufw allow 5432!
|
|
ufw --force enable
|
|
|
|
log "Шаг 3: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 4: PostgreSQL 16 + pgvector
|
|
# ============================================================
|
|
step_postgres() {
|
|
log "Шаг 4: PostgreSQL $POSTGRES_VERSION + pgvector"
|
|
|
|
# Репозиторий PGDG
|
|
if [[ ! -f /etc/apt/sources.list.d/pgdg.list ]]; then
|
|
sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
|
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
|
apt-get update -qq
|
|
fi
|
|
|
|
apt-get install -y -qq \
|
|
postgresql-$POSTGRES_VERSION \
|
|
postgresql-contrib-$POSTGRES_VERSION \
|
|
postgresql-$POSTGRES_VERSION-pgvector \
|
|
postgresql-client-$POSTGRES_VERSION
|
|
|
|
# Тюнинг postgresql.conf под объём RAM
|
|
local pg_conf="/etc/postgresql/$POSTGRES_VERSION/main/postgresql.conf"
|
|
local shared_buffers=$((TOTAL_RAM_GB * 1024 / 4)) # 25% от RAM в MB
|
|
local effective_cache=$((TOTAL_RAM_GB * 1024 / 2)) # 50% от RAM в MB
|
|
|
|
cat > /etc/postgresql/$POSTGRES_VERSION/main/conf.d/zbrain.conf <<EOF
|
|
# ZBrain Postgres tuning
|
|
# Сгенерировано bootstrap-vm.sh для VM ${TOTAL_RAM_GB}GB RAM
|
|
|
|
# Память
|
|
shared_buffers = ${shared_buffers}MB
|
|
effective_cache_size = ${effective_cache}MB
|
|
maintenance_work_mem = 512MB
|
|
work_mem = 32MB
|
|
|
|
# Соединения
|
|
max_connections = 100
|
|
listen_addresses = 'localhost'
|
|
|
|
# WAL
|
|
wal_buffers = 16MB
|
|
checkpoint_completion_target = 0.9
|
|
min_wal_size = 1GB
|
|
max_wal_size = 4GB
|
|
|
|
# Параллелизм (для HNSW index build + сложных запросов)
|
|
max_parallel_workers_per_gather = 2
|
|
max_parallel_maintenance_workers = 2
|
|
|
|
# SSD
|
|
random_page_cost = 1.1
|
|
effective_io_concurrency = 200
|
|
|
|
# Логи
|
|
log_min_duration_statement = 1000
|
|
log_checkpoints = on
|
|
log_connections = on
|
|
log_disconnections = on
|
|
log_lock_waits = on
|
|
log_temp_files = 0
|
|
log_line_prefix = '%t [%p] %u@%d '
|
|
EOF
|
|
|
|
# pg_hba.conf - только localhost
|
|
cat > /etc/postgresql/$POSTGRES_VERSION/main/pg_hba.conf <<EOF
|
|
# ZBrain pg_hba.conf
|
|
local all postgres peer
|
|
local all all scram-sha-256
|
|
host all all 127.0.0.1/32 scram-sha-256
|
|
host all all ::1/128 scram-sha-256
|
|
EOF
|
|
|
|
systemctl enable postgresql
|
|
systemctl restart postgresql
|
|
|
|
# Создание главной БД brainhub и расширений
|
|
sudo -u postgres psql -c "CREATE DATABASE brainhub;" 2>/dev/null || log "БД brainhub уже существует"
|
|
sudo -u postgres psql -d brainhub -c "CREATE EXTENSION IF NOT EXISTS vector;"
|
|
sudo -u postgres psql -d brainhub -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
|
sudo -u postgres psql -d brainhub -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
|
|
|
|
log "Шаг 4: ✓ Postgres работает, BD brainhub готова"
|
|
log " ВАЖНО: создай пароли для пользователей postgres и brainhub:"
|
|
log " sudo -u postgres psql"
|
|
log " ALTER USER postgres PASSWORD '...';"
|
|
log " CREATE USER brainhub WITH PASSWORD '...';"
|
|
log " GRANT ALL PRIVILEGES ON DATABASE brainhub TO brainhub;"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 5: Node.js 22 LTS + Bun
|
|
# ============================================================
|
|
step_node_bun() {
|
|
log "Шаг 5: Node.js $NODE_VERSION LTS + Bun"
|
|
|
|
# Node через NodeSource
|
|
if ! command -v node &>/dev/null || [[ "$(node -v)" != v${NODE_VERSION}* ]]; then
|
|
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
|
apt-get install -y -qq nodejs
|
|
fi
|
|
|
|
# Bun (для gbrain)
|
|
if ! sudo -u "$ZBRAIN_USER" bash -c 'command -v bun' &>/dev/null; then
|
|
sudo -u "$ZBRAIN_USER" bash -c 'curl -fsSL https://bun.sh/install | bash'
|
|
# Добавим в PATH
|
|
sudo -u "$ZBRAIN_USER" bash -c 'echo "export PATH=\$HOME/.bun/bin:\$PATH" >> ~/.bashrc'
|
|
fi
|
|
|
|
log " Node: $(node -v)"
|
|
log " npm: $(npm -v)"
|
|
log "Шаг 5: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 6: Docker + Compose
|
|
# ============================================================
|
|
step_docker() {
|
|
log "Шаг 6: Docker"
|
|
|
|
if ! command -v docker &>/dev/null; then
|
|
# Официальный репо Docker (не snap!)
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
|
|
apt-get update -qq
|
|
apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
fi
|
|
|
|
# zbrain в группу docker
|
|
usermod -aG docker "$ZBRAIN_USER"
|
|
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
|
|
log " Docker: $(docker --version)"
|
|
log " Compose: $(docker compose version)"
|
|
log "Шаг 6: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 7: gbrain (клонирование из mirror, установка зависимостей)
|
|
# ============================================================
|
|
step_gbrain() {
|
|
log "Шаг 7: gbrain (из $GBRAIN_REPO)"
|
|
|
|
local gbrain_dir="$ZBRAIN_DATA_DIR/gbrain"
|
|
|
|
if [[ ! -d "$gbrain_dir" ]]; then
|
|
sudo -u "$ZBRAIN_USER" git clone "$GBRAIN_REPO" "$gbrain_dir"
|
|
else
|
|
log " gbrain уже склонирован в $gbrain_dir"
|
|
sudo -u "$ZBRAIN_USER" bash -c "cd '$gbrain_dir' && git fetch"
|
|
fi
|
|
|
|
sudo -u "$ZBRAIN_USER" bash -c "cd '$gbrain_dir' && git checkout '$GBRAIN_VERSION'"
|
|
|
|
# Установка зависимостей через bun (используем FNA-прокси)
|
|
log " Устанавливаю зависимости gbrain (через FNA proxy)..."
|
|
sudo -u "$ZBRAIN_USER" bash -c "
|
|
export HTTPS_PROXY='$FNA_PROXY'
|
|
export HTTP_PROXY='$FNA_PROXY'
|
|
export PATH=\$HOME/.bun/bin:\$PATH
|
|
cd '$gbrain_dir' && bun install
|
|
"
|
|
|
|
log "Шаг 7: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 8: Конфиг-файлы и шаблоны
|
|
# ============================================================
|
|
step_config_templates() {
|
|
log "Шаг 8: Шаблоны конфигов"
|
|
|
|
# .env шаблон
|
|
cat > "$ZBRAIN_CONFIG_DIR/env.example" <<'EOF'
|
|
# ZBrain Environment Configuration
|
|
# Скопируй в .env и заполни значения
|
|
|
|
# === База данных ===
|
|
DATABASE_URL=postgresql://brainhub:CHANGE_ME@localhost:5432/brainhub
|
|
POSTGRES_ADMIN_URL=postgresql://postgres:CHANGE_ME@localhost:5432/postgres
|
|
|
|
# === FNA Proxy (для исходящих к OpenAI/Anthropic) ===
|
|
HTTPS_PROXY=http://client_001:PASSWORD@fna.zetit.ru:3128
|
|
HTTP_PROXY=http://client_001:PASSWORD@fna.zetit.ru:3128
|
|
NO_PROXY=localhost,127.0.0.1,.zetit.ru,.zetit.local
|
|
|
|
# === API ключи ===
|
|
OPENAI_API_KEY=sk-...
|
|
ANTHROPIC_API_KEY=sk-ant-...
|
|
|
|
# === ZBrain ===
|
|
ZBRAIN_BASE_URL=https://brain.zetit.ru
|
|
ZBRAIN_INTERNAL_URL=http://brain.zetit.local
|
|
SESSION_SECRET=GENERATE_RANDOM_64_CHARS
|
|
JWT_SECRET=GENERATE_RANDOM_64_CHARS
|
|
TOKEN_ENCRYPTION_KEY=GENERATE_RANDOM_32_BYTES_HEX
|
|
|
|
# === OAuth ===
|
|
YANDEX_OAUTH_CLIENT_ID=
|
|
YANDEX_OAUTH_CLIENT_SECRET=
|
|
GITHUB_OAUTH_CLIENT_ID=
|
|
GITHUB_OAUTH_CLIENT_SECRET=
|
|
|
|
# === Порты ===
|
|
BRAINHUB_INTERNAL_PORT=3000
|
|
BRAINHUB_PUBLIC_PORT=3010
|
|
GBRAIN_PORT_RANGE_START=3001
|
|
GBRAIN_PORT_RANGE_END=3099
|
|
|
|
# === Логирование ===
|
|
LOG_LEVEL=info
|
|
LOG_FILE=/var/log/zbrain/brainhub.log
|
|
EOF
|
|
|
|
chmod 640 "$ZBRAIN_CONFIG_DIR/env.example"
|
|
chown root:"$ZBRAIN_USER" "$ZBRAIN_CONFIG_DIR/env.example"
|
|
|
|
log " Шаблон env: $ZBRAIN_CONFIG_DIR/env.example"
|
|
log " Не забудь: cp $ZBRAIN_CONFIG_DIR/env.example $ZBRAIN_CONFIG_DIR/.env && chmod 600 $ZBRAIN_CONFIG_DIR/.env"
|
|
log "Шаг 8: ✓"
|
|
}
|
|
|
|
# ============================================================
|
|
# Шаг 9: Самопроверка
|
|
# ============================================================
|
|
step_verify() {
|
|
log "Шаг 9: Самопроверка"
|
|
|
|
local errors=0
|
|
|
|
check() {
|
|
local name="$1"
|
|
local cmd="$2"
|
|
if eval "$cmd" &>/dev/null; then
|
|
log " ✓ $name"
|
|
else
|
|
err " ✗ $name (команда: $cmd)"
|
|
errors=$((errors+1))
|
|
fi
|
|
}
|
|
|
|
check "PostgreSQL запущен" "systemctl is-active postgresql"
|
|
check "Postgres доступен" "sudo -u postgres psql -c 'SELECT version()'"
|
|
check "pgvector установлен" "sudo -u postgres psql -d brainhub -c 'SELECT * FROM pg_extension WHERE extname = '\''vector'\''' | grep -q vector"
|
|
check "Node.js установлен" "node --version"
|
|
check "Docker запущен" "systemctl is-active docker"
|
|
check "Bun установлен" "sudo -u $ZBRAIN_USER bash -c 'PATH=\$HOME/.bun/bin:\$PATH bun --version'"
|
|
check "gbrain склонирован" "test -d $ZBRAIN_DATA_DIR/gbrain"
|
|
check "UFW активен" "ufw status | grep -q 'Status: active'"
|
|
check "Swap включён" "swapon --show | grep -q swapfile"
|
|
|
|
if [[ $errors -gt 0 ]]; then
|
|
err "Обнаружено $errors ошибок. Проверь логи выше."
|
|
exit 1
|
|
fi
|
|
|
|
log "Шаг 9: ✓ Всё работает"
|
|
}
|
|
|
|
# ============================================================
|
|
# Итоговый отчёт
|
|
# ============================================================
|
|
final_report() {
|
|
cat <<EOF
|
|
|
|
╔════════════════════════════════════════════════════════════╗
|
|
║ ZBrain VM Bootstrap готов ║
|
|
╚════════════════════════════════════════════════════════════╝
|
|
|
|
Следующие шаги:
|
|
|
|
1. Создай пароли для Postgres:
|
|
sudo -u postgres psql
|
|
ALTER USER postgres PASSWORD 'strong-password';
|
|
CREATE USER brainhub WITH PASSWORD 'another-strong-password';
|
|
GRANT ALL PRIVILEGES ON DATABASE brainhub TO brainhub;
|
|
\\q
|
|
|
|
2. Скопируй и заполни .env:
|
|
sudo cp $ZBRAIN_CONFIG_DIR/env.example $ZBRAIN_CONFIG_DIR/.env
|
|
sudo chmod 600 $ZBRAIN_CONFIG_DIR/.env
|
|
sudo chown $ZBRAIN_USER:$ZBRAIN_USER $ZBRAIN_CONFIG_DIR/.env
|
|
sudo nano $ZBRAIN_CONFIG_DIR/.env
|
|
|
|
3. Создай первый брейн:
|
|
sudo bash $ZBRAIN_HOME/scripts/create-brain.sh zetit "ZETIT MSP" 3001
|
|
|
|
4. (опционально) Склонируй ZBrain код:
|
|
sudo -u $ZBRAIN_USER git clone git@git.zetit.ru:zuevav/ZBrain.git $ZBRAIN_HOME/app
|
|
|
|
5. Запусти первый gbrain instance:
|
|
см. docs/DEPLOYMENT.md
|
|
|
|
Параметры этой VM:
|
|
RAM: ${TOTAL_RAM_GB} GB
|
|
Postgres shared_buffers: $((TOTAL_RAM_GB * 1024 / 4)) MB
|
|
ZBrain home: $ZBRAIN_HOME
|
|
ZBrain data: $ZBRAIN_DATA_DIR
|
|
ZBrain config: $ZBRAIN_CONFIG_DIR
|
|
ZBrain logs: $ZBRAIN_LOG_DIR
|
|
|
|
EOF
|
|
}
|
|
|
|
# ============================================================
|
|
# Main
|
|
# ============================================================
|
|
main() {
|
|
require_root
|
|
check_ubuntu
|
|
|
|
log "Старт ZBrain VM bootstrap"
|
|
log "Целевая RAM: ${TOTAL_RAM_GB} GB"
|
|
log "FNA proxy: ${FNA_PROXY%%:*}://***"
|
|
echo
|
|
|
|
step_base_packages
|
|
step_create_user
|
|
step_system_tuning
|
|
step_postgres
|
|
step_node_bun
|
|
step_docker
|
|
step_gbrain
|
|
step_config_templates
|
|
step_verify
|
|
|
|
final_report
|
|
}
|
|
|
|
main "$@"
|