Add .deb package builder script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
205
packaging/build-deb.sh
Normal file
205
packaging/build-deb.sh
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env bash
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# LLM Trainer — .deb package builder
|
||||
# Run this on the Ubuntu machine after cloning the repo:
|
||||
# chmod +x packaging/build-deb.sh
|
||||
# ./packaging/build-deb.sh
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
set -euo pipefail
|
||||
|
||||
PKG_NAME="llm-trainer"
|
||||
PKG_VERSION="1.0.0"
|
||||
PKG_ARCH="amd64"
|
||||
PKG_DIR="${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
OUT_DIR="${REPO_ROOT}"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " LLM Trainer .deb Builder"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# ── Check dependencies ────────────────────────────────────────
|
||||
for cmd in node npm python3 pip3 dpkg-deb nginx; do
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
echo "[ERROR] Required command not found: $cmd"
|
||||
echo " Install with: sudo apt install nodejs npm python3-pip nginx"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Build frontend ────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[1/4] Building React frontend..."
|
||||
cd "${REPO_ROOT}/frontend"
|
||||
npm install --silent
|
||||
npm run build
|
||||
echo " Frontend built → frontend/dist"
|
||||
|
||||
# ── Create package directory tree ─────────────────────────────
|
||||
echo ""
|
||||
echo "[2/4] Creating package structure..."
|
||||
BUILD="${REPO_ROOT}/${PKG_DIR}"
|
||||
rm -rf "${BUILD}"
|
||||
|
||||
install -d "${BUILD}/DEBIAN"
|
||||
install -d "${BUILD}/opt/llm-trainer/backend"
|
||||
install -d "${BUILD}/opt/llm-trainer/frontend"
|
||||
install -d "${BUILD}/opt/llm-trainer/venv"
|
||||
install -d "${BUILD}/lib/systemd/system"
|
||||
install -d "${BUILD}/etc/nginx/sites-available"
|
||||
install -d "${BUILD}/etc/nginx/sites-enabled"
|
||||
install -d "${BUILD}/etc/llm-trainer"
|
||||
install -d "${BUILD}/var/log/llm-trainer"
|
||||
|
||||
# Copy backend
|
||||
cp "${REPO_ROOT}/backend/"*.py "${BUILD}/opt/llm-trainer/backend/"
|
||||
cp "${REPO_ROOT}/backend/requirements.txt" "${BUILD}/opt/llm-trainer/backend/"
|
||||
|
||||
# Copy built frontend
|
||||
cp -r "${REPO_ROOT}/frontend/dist/." "${BUILD}/opt/llm-trainer/frontend/"
|
||||
|
||||
# ── Write control files ───────────────────────────────────────
|
||||
cat > "${BUILD}/DEBIAN/control" <<EOF
|
||||
Package: ${PKG_NAME}
|
||||
Version: ${PKG_VERSION}
|
||||
Architecture: ${PKG_ARCH}
|
||||
Maintainer: tocmo0nlord
|
||||
Depends: python3 (>= 3.10), python3-pip, python3-venv, nginx
|
||||
Description: LLM Trainer Dashboard
|
||||
Web dashboard for managing LLM training pipelines via SSH.
|
||||
Includes document ingestion, QA pair generation, curation,
|
||||
training monitor, and an interactive terminal.
|
||||
EOF
|
||||
|
||||
# ── Systemd service ───────────────────────────────────────────
|
||||
cat > "${BUILD}/lib/systemd/system/llm-trainer.service" <<EOF
|
||||
[Unit]
|
||||
Description=LLM Trainer Backend
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=llm-trainer
|
||||
Group=llm-trainer
|
||||
WorkingDirectory=/opt/llm-trainer/backend
|
||||
ExecStart=/opt/llm-trainer/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8080
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:/var/log/llm-trainer/backend.log
|
||||
StandardError=append:/var/log/llm-trainer/backend.log
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# ── Nginx config ──────────────────────────────────────────────
|
||||
cat > "${BUILD}/etc/nginx/sites-available/llm-trainer" <<'EOF'
|
||||
server {
|
||||
listen 3000;
|
||||
server_name _;
|
||||
|
||||
root /opt/llm-trainer/frontend;
|
||||
index index.html;
|
||||
|
||||
# Serve React SPA
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Proxy REST API to FastAPI backend
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
# WebSocket support (terminal, log streaming)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# ── postinst ──────────────────────────────────────────────────
|
||||
cat > "${BUILD}/DEBIAN/postinst" <<'POSTINST'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Create system user
|
||||
if ! id -u llm-trainer &>/dev/null; then
|
||||
useradd --system --no-create-home --shell /usr/sbin/nologin llm-trainer
|
||||
fi
|
||||
|
||||
# Set permissions
|
||||
chown -R llm-trainer:llm-trainer /opt/llm-trainer
|
||||
chown -R llm-trainer:llm-trainer /var/log/llm-trainer
|
||||
|
||||
# Build Python venv and install deps
|
||||
echo "Installing Python dependencies..."
|
||||
python3 -m venv /opt/llm-trainer/venv
|
||||
/opt/llm-trainer/venv/bin/pip install --quiet --upgrade pip
|
||||
/opt/llm-trainer/venv/bin/pip install --quiet -r /opt/llm-trainer/backend/requirements.txt
|
||||
chown -R llm-trainer:llm-trainer /opt/llm-trainer/venv
|
||||
|
||||
# Enable nginx site
|
||||
ln -sf /etc/nginx/sites-available/llm-trainer /etc/nginx/sites-enabled/llm-trainer
|
||||
nginx -t && systemctl reload nginx || true
|
||||
|
||||
# Enable and start backend service
|
||||
systemctl daemon-reload
|
||||
systemctl enable llm-trainer
|
||||
systemctl start llm-trainer
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " LLM Trainer installed successfully!"
|
||||
echo " Open: http://$(hostname -I | awk '{print $1}'):3000"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
POSTINST
|
||||
chmod 0755 "${BUILD}/DEBIAN/postinst"
|
||||
|
||||
# ── prerm ─────────────────────────────────────────────────────
|
||||
cat > "${BUILD}/DEBIAN/prerm" <<'PRERM'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
systemctl stop llm-trainer 2>/dev/null || true
|
||||
systemctl disable llm-trainer 2>/dev/null || true
|
||||
rm -f /etc/nginx/sites-enabled/llm-trainer
|
||||
systemctl reload nginx 2>/dev/null || true
|
||||
PRERM
|
||||
chmod 0755 "${BUILD}/DEBIAN/prerm"
|
||||
|
||||
# ── postrm ────────────────────────────────────────────────────
|
||||
cat > "${BUILD}/DEBIAN/postrm" <<'POSTRM'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
if [ "$1" = "purge" ]; then
|
||||
rm -rf /opt/llm-trainer
|
||||
rm -rf /var/log/llm-trainer
|
||||
rm -f /etc/nginx/sites-available/llm-trainer
|
||||
userdel llm-trainer 2>/dev/null || true
|
||||
fi
|
||||
POSTRM
|
||||
chmod 0755 "${BUILD}/DEBIAN/postrm"
|
||||
|
||||
# ── Build .deb ────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[3/4] Building .deb package..."
|
||||
cd "${REPO_ROOT}"
|
||||
dpkg-deb --build --root-owner-group "${PKG_DIR}"
|
||||
echo " Package built → ${PKG_DIR}.deb"
|
||||
|
||||
# ── Cleanup ───────────────────────────────────────────────────
|
||||
rm -rf "${BUILD}"
|
||||
|
||||
echo ""
|
||||
echo "[4/4] Done!"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " Install with:"
|
||||
echo " sudo dpkg -i ${PKG_DIR}.deb"
|
||||
echo " sudo apt-get install -f # fix any missing deps"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
Reference in New Issue
Block a user