一键部署:主程序+OCR同机(screen/GPU),Ollama外置局域网。
This commit is contained in:
+114
-40
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# 中学成绩档案系统 — Ubuntu 零 Node 一键部署(FastAPI 单进程 + systemd)
|
||||
# 中学成绩档案系统 — 一键部署
|
||||
# 架构:主程序 + OCR(GPU/screen 同机) | Ollama(其他电脑局域网)
|
||||
# 版权所有 (c) 马建军 微信: dekun03 手机: 18364911125
|
||||
#
|
||||
set -euo pipefail
|
||||
@@ -8,8 +9,12 @@ set -euo pipefail
|
||||
REPO_URL="${REPO_URL:-https://git.bz121.com/dekun/secondary-school-grade-archive.git}"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/secondary-school-grade-archive}"
|
||||
WEB_PORT="${WEB_PORT:-23566}"
|
||||
OCR_PORT="${OCR_PORT:-23567}"
|
||||
BRANCH="${BRANCH:-main}"
|
||||
PIP_MIRROR="${PIP_MIRROR:-https://pypi.tuna.tsinghua.edu.cn/simple}"
|
||||
# Ollama 在其他电脑时安装前指定,例如: OLLAMA_BASE_URL=http://192.168.8.100:11434
|
||||
OLLAMA_BASE_URL="${OLLAMA_BASE_URL:-}"
|
||||
OLLAMA_MODEL="${OLLAMA_MODEL:-qwen2.5:7b}"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
@@ -22,6 +27,8 @@ log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# shellcheck source=proxy.sh
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/proxy.sh"
|
||||
# shellcheck source=ocr-common.sh
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ocr-common.sh"
|
||||
|
||||
require_root() {
|
||||
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||
@@ -41,18 +48,41 @@ check_os() {
|
||||
}
|
||||
|
||||
check_port() {
|
||||
if command -v ss &>/dev/null && ss -tln | grep -q ":${WEB_PORT} "; then
|
||||
log_error "端口 ${WEB_PORT} 已被占用"
|
||||
exit 1
|
||||
for p in "${WEB_PORT}" "${OCR_PORT}"; do
|
||||
if command -v ss &>/dev/null && ss -tln | grep -q ":${p} "; then
|
||||
if [[ "${p}" == "${OCR_PORT}" ]] && ocr_screen_running 2>/dev/null; then
|
||||
log_warn "端口 ${OCR_PORT} 已被占用(可能已有 OCR Worker)"
|
||||
elif [[ "${p}" == "${WEB_PORT}" ]]; then
|
||||
log_error "端口 ${WEB_PORT} 已被占用"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
log_info "Web 端口 ${WEB_PORT} / OCR 端口 ${OCR_PORT} 检查完成"
|
||||
}
|
||||
|
||||
prompt_ollama_url() {
|
||||
if [[ -n "${OLLAMA_BASE_URL}" ]]; then
|
||||
log_info "Ollama 地址: ${OLLAMA_BASE_URL}"
|
||||
return
|
||||
fi
|
||||
log_info "端口 ${WEB_PORT} 可用"
|
||||
if [[ -t 0 ]]; then
|
||||
echo ""
|
||||
echo "Ollama 部署在【其他电脑】上,请填写局域网地址。"
|
||||
read -rp "Ollama 地址 [http://192.168.8.100:11434]: " input
|
||||
OLLAMA_BASE_URL="${input:-http://192.168.8.100:11434}"
|
||||
else
|
||||
OLLAMA_BASE_URL="http://127.0.0.1:11434"
|
||||
log_warn "未设置 OLLAMA_BASE_URL,默认 ${OLLAMA_BASE_URL}(可在 .env 或系统设置中修改)"
|
||||
fi
|
||||
log_info "Ollama 地址: ${OLLAMA_BASE_URL}"
|
||||
}
|
||||
|
||||
install_base_packages() {
|
||||
log_info "安装系统依赖…"
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
|
||||
git curl ca-certificates openssl \
|
||||
git curl ca-certificates openssl screen \
|
||||
python3 python3-venv python3-pip python3-dev \
|
||||
build-essential libpq-dev \
|
||||
postgresql postgresql-contrib \
|
||||
@@ -72,16 +102,27 @@ clone_or_update_repo() {
|
||||
git clone --branch "${BRANCH}" "${REPO_URL}" "${INSTALL_DIR}" || git clone "${REPO_URL}" "${INSTALL_DIR}"
|
||||
fi
|
||||
find "${INSTALL_DIR}" -name "*.sh" -exec sed -i 's/\r$//' {} +
|
||||
chmod +x "${INSTALL_DIR}/deploy/start.sh"
|
||||
chmod +x "${INSTALL_DIR}/deploy/start.sh" \
|
||||
"${INSTALL_DIR}/deploy/ocr-screen.sh" \
|
||||
"${INSTALL_DIR}/deploy/ocr-worker/"*.sh 2>/dev/null || true
|
||||
}
|
||||
|
||||
verify_frontend_dist() {
|
||||
if [[ ! -f "${INSTALL_DIR}/frontend/dist/index.html" ]]; then
|
||||
log_error "未找到 frontend/dist/index.html"
|
||||
log_error "请先在开发机执行: cd frontend && npm run build,并将 dist 推送到仓库后再部署"
|
||||
log_error "仓库应已包含预构建前端;若缺失请在开发机 npm run build 后推送"
|
||||
exit 1
|
||||
fi
|
||||
log_info "前端静态资源已就绪(无需在服务器构建)"
|
||||
log_info "前端静态资源已就绪"
|
||||
}
|
||||
|
||||
env_set_or_append() {
|
||||
local key="$1" val="$2" file="${INSTALL_DIR}/.env"
|
||||
if grep -q "^${key}=" "${file}" 2>/dev/null; then
|
||||
sed -i "s|^${key}=.*|${key}=${val}|" "${file}"
|
||||
else
|
||||
echo "${key}=${val}" >> "${file}"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_env() {
|
||||
@@ -90,17 +131,15 @@ generate_env() {
|
||||
server_ip=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
server_ip="${server_ip:-127.0.0.1}"
|
||||
|
||||
if [[ -f "${env_file}" ]]; then
|
||||
log_info "保留已有 .env"
|
||||
return
|
||||
fi
|
||||
prompt_ollama_url
|
||||
|
||||
local secret pg_pass pg_user
|
||||
secret=$(openssl rand -hex 32)
|
||||
pg_pass=$(openssl rand -hex 16)
|
||||
pg_user="gradeapp"
|
||||
if [[ ! -f "${env_file}" ]]; then
|
||||
local secret pg_pass pg_user
|
||||
secret=$(openssl rand -hex 32)
|
||||
pg_pass=$(openssl rand -hex 16)
|
||||
pg_user="gradeapp"
|
||||
|
||||
cat > "${env_file}" <<EOF
|
||||
cat > "${env_file}" <<EOF
|
||||
# generated by deploy/install.sh — $(date -Iseconds)
|
||||
WEB_PORT=${WEB_PORT}
|
||||
FRONTEND_DIST=${INSTALL_DIR}/frontend/dist
|
||||
@@ -111,14 +150,25 @@ POSTGRES_DB=student_archive
|
||||
DATABASE_URL=postgresql://${pg_user}:${pg_pass}@127.0.0.1:5432/student_archive
|
||||
UPLOAD_DIR=${INSTALL_DIR}/uploads
|
||||
CORS_ORIGINS=http://${server_ip}:${WEB_PORT},http://127.0.0.1:${WEB_PORT},http://localhost:${WEB_PORT}
|
||||
OLLAMA_BASE_URL=http://127.0.0.1:11434
|
||||
OLLAMA_MODEL=qwen2.5:7b
|
||||
# OCR 同机 GPU Worker(screen 常驻)
|
||||
OCR_SERVICE_URL=http://127.0.0.1:${OCR_PORT}
|
||||
OCR_PORT=${OCR_PORT}
|
||||
# Ollama 在其他电脑(局域网)
|
||||
OLLAMA_BASE_URL=${OLLAMA_BASE_URL}
|
||||
OLLAMA_MODEL=${OLLAMA_MODEL}
|
||||
FLUCTUATION_THRESHOLD=0.08
|
||||
ADMIN_DEFAULT_USERNAME=admin
|
||||
ADMIN_DEFAULT_PASSWORD=admin123
|
||||
EOF
|
||||
chmod 600 "${env_file}"
|
||||
log_info ".env 已生成(默认超级管理员 admin / admin123,请登录后修改)"
|
||||
chmod 600 "${env_file}"
|
||||
log_info ".env 已生成(默认 admin / admin123)"
|
||||
else
|
||||
log_info "更新 .env 中的 OCR / Ollama 配置…"
|
||||
env_set_or_append "OCR_SERVICE_URL" "http://127.0.0.1:${OCR_PORT}"
|
||||
env_set_or_append "OCR_PORT" "${OCR_PORT}"
|
||||
env_set_or_append "OLLAMA_BASE_URL" "${OLLAMA_BASE_URL}"
|
||||
env_set_or_append "OLLAMA_MODEL" "${OLLAMA_MODEL}"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_postgresql() {
|
||||
@@ -141,9 +191,11 @@ setup_postgresql() {
|
||||
}
|
||||
|
||||
setup_backend() {
|
||||
log_info "安装 Python 依赖(Paddle 包较大,约 10–30 分钟)…"
|
||||
log_info "安装主程序 Python 依赖…"
|
||||
cd "${INSTALL_DIR}/backend"
|
||||
python3 -m venv venv
|
||||
if [[ ! -d venv ]]; then
|
||||
python3 -m venv venv
|
||||
fi
|
||||
# shellcheck disable=SC1091
|
||||
source venv/bin/activate
|
||||
pip install --upgrade pip --progress-bar on -i "${PIP_MIRROR}"
|
||||
@@ -151,16 +203,28 @@ setup_backend() {
|
||||
deactivate
|
||||
}
|
||||
|
||||
setup_ocr_gpu() {
|
||||
if command -v nvidia-smi >/dev/null; then
|
||||
log_info "检测到 NVIDIA GPU,OCR 将常驻显存 (screen)"
|
||||
nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null || true
|
||||
else
|
||||
log_warn "未检测到 NVIDIA GPU,OCR 将使用 CPU(较慢)"
|
||||
fi
|
||||
install_ocr_worker
|
||||
start_ocr_screen
|
||||
wait_ocr_healthy || log_warn "OCR 仍在加载模型,稍后可执行: bash ${INSTALL_DIR}/deploy/ocr-screen.sh status"
|
||||
}
|
||||
|
||||
stop_legacy_pm2() {
|
||||
if command -v pm2 &>/dev/null; then
|
||||
pm2 delete grade-api grade-web 2>/dev/null || true
|
||||
pm2 save 2>/dev/null || true
|
||||
log_info "已停止旧版 PM2 进程(grade-api / grade-web)"
|
||||
log_info "已停止旧版 PM2 进程"
|
||||
fi
|
||||
}
|
||||
|
||||
setup_systemd() {
|
||||
log_info "配置 systemd 服务…"
|
||||
log_info "配置 systemd 服务 grade-archive(主程序)…"
|
||||
sed "s|/opt/secondary-school-grade-archive|${INSTALL_DIR}|g" \
|
||||
"${INSTALL_DIR}/deploy/grade-archive.service" > /etc/systemd/system/grade-archive.service
|
||||
systemctl daemon-reload
|
||||
@@ -168,7 +232,7 @@ setup_systemd() {
|
||||
}
|
||||
|
||||
start_service() {
|
||||
log_info "启动服务…"
|
||||
log_info "启动主程序…"
|
||||
cd "${INSTALL_DIR}"
|
||||
mkdir -p uploads backups
|
||||
systemctl restart grade-archive
|
||||
@@ -178,48 +242,58 @@ wait_healthy() {
|
||||
local i
|
||||
for i in $(seq 1 40); do
|
||||
if curl -sf "http://127.0.0.1:${WEB_PORT}/api/health" >/dev/null; then
|
||||
log_info "健康检查通过"
|
||||
log_info "主程序健康检查通过"
|
||||
return 0
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
log_warn "健康检查超时,请查看: journalctl -u grade-archive -f"
|
||||
log_warn "主程序健康检查超时: journalctl -u grade-archive -f"
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
# shellcheck disable=SC1090
|
||||
source "${INSTALL_DIR}/.env"
|
||||
local ip
|
||||
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
ip="${ip:-127.0.0.1}"
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " 中学成绩档案系统部署完成(零 Node)"
|
||||
echo " 中学成绩档案 — 一键部署完成"
|
||||
echo " 版权所有 (c) 马建军"
|
||||
echo "=========================================="
|
||||
echo " 访问: http://${ip}:${WEB_PORT}"
|
||||
echo " 目录: ${INSTALL_DIR}"
|
||||
echo " 默认管理员: admin / admin123(请立即修改)"
|
||||
echo " 访问: http://${ip}:${WEB_PORT}"
|
||||
echo " 管理员: admin / admin123(请立即修改)"
|
||||
echo ""
|
||||
echo " systemctl status grade-archive"
|
||||
echo " journalctl -u grade-archive -f"
|
||||
echo " bash ${INSTALL_DIR}/deploy/update.sh"
|
||||
echo " bash ${INSTALL_DIR}/deploy/backup.sh"
|
||||
echo " 【同机 OCR — GPU 常驻 screen】"
|
||||
echo " OCR 地址: http://127.0.0.1:${OCR_PORT}"
|
||||
echo " 状态: bash ${INSTALL_DIR}/deploy/ocr-screen.sh status"
|
||||
echo " 进入终端: screen -r ocr-worker (Ctrl+A D 退出)"
|
||||
echo " 重启 OCR: bash ${INSTALL_DIR}/deploy/ocr-screen.sh restart"
|
||||
echo ""
|
||||
echo " 【Ollama — 其他电脑】"
|
||||
echo " 地址: ${OLLAMA_BASE_URL}"
|
||||
echo " 模型: ${OLLAMA_MODEL}"
|
||||
echo " 可在「系统设置 → AI 模型」修改"
|
||||
echo ""
|
||||
echo " 主程序: systemctl status grade-archive"
|
||||
echo " 更新: sudo bash ${INSTALL_DIR}/deploy/update.sh"
|
||||
echo " 微信 dekun03 手机 18364911125"
|
||||
echo "=========================================="
|
||||
}
|
||||
|
||||
main() {
|
||||
log_info "零 Node 一键部署开始"
|
||||
log_info "一键部署开始(主程序 + OCR/GPU/screen | Ollama 外置)"
|
||||
require_root
|
||||
setup_deploy_proxy
|
||||
check_os
|
||||
check_port
|
||||
install_base_packages
|
||||
clone_or_update_repo
|
||||
verify_frontend_dist
|
||||
check_port
|
||||
install_base_packages
|
||||
generate_env
|
||||
setup_postgresql
|
||||
setup_backend
|
||||
setup_ocr_gpu
|
||||
stop_legacy_pm2
|
||||
setup_systemd
|
||||
start_service
|
||||
|
||||
Reference in New Issue
Block a user