#!/bin/bash # ============================================================ # Windows Git Bash → Linux 一键部署脚本 # 用法: 在 Git Bash 中运行 bash deploy.sh # ============================================================ set -e # ── 服务器配置 ── HOST="39.97.59.228" USER="root" PASS="Ccri123456" PORT="22" REMOTE_DIR="/data/vent_agent/vent_deep_agent_1.4" APP_PORT="8070" # ── 本地项目根目录(脚本所在目录)── LOCAL_DIR="$(cd "$(dirname "$0")" && pwd)" echo "========================================" echo " 配风计划审查系统 - 一键部署" echo "========================================" echo " 服务器: ${USER}@${HOST}:${PORT}" echo " 远程目录: ${REMOTE_DIR}" echo " 本地目录: ${LOCAL_DIR}" echo "========================================" # ============================================================ # 密码自动注入方案选择 # ============================================================ # 优先级: sshpass > SSH 密钥 > PuTTY(已废弃,不再推荐) # ============================================================ USE_SSHPASS=false USE_SSH_KEY=false USE_PUTTY=false # ── 检查 SSH 密钥是否已配置 ── check_ssh_key() { if [ -f ~/.ssh/id_rsa ] || [ -f ~/.ssh/id_ed25519 ] || [ -f ~/.ssh/id_ecdsa ]; then # 测试是否能免密连接 if ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=5 -p ${PORT} ${USER}@${HOST} "echo ok" &>/dev/null; then return 0 fi fi return 1 } # ── 自动配置 SSH 密钥(首次需要输入密码)── setup_ssh_key() { echo "" echo "========================================" echo " 首次部署:配置 SSH 密钥免密登录" echo " 密码已预设,只需按一次回车确认" echo "========================================" echo "" # 生成密钥(如不存在) if [ ! -f ~/.ssh/id_rsa ]; then echo "[1/2] 生成 SSH 密钥对..." ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -N "" -q echo " ✅ 密钥已生成: ~/.ssh/id_rsa" else echo "[1/2] SSH 密钥已存在,跳过生成" fi # 复制公钥到服务器(首次需要密码) echo "[2/2] 复制公钥到服务器..." echo " → 服务器: ${USER}@${HOST}:${PORT}" echo " → 密码: ${PASS}" echo " → 请输入上述密码(仅此一次,之后全自动):" echo "" # 使用 ssh-copy-id(会提示输入密码),临时关闭 set -e 以处理错误 set +e ssh-copy-id -o StrictHostKeyChecking=no -p ${PORT} ${USER}@${HOST} local copy_ret=$? set -e if [ $copy_ret -eq 0 ]; then echo "" echo " ✅ SSH 密钥已部署到服务器,以后部署全自动免密!" USE_SSH_KEY=true return 0 else echo "" echo " ❌ SSH 密钥配置失败(退出码: ${copy_ret}),请检查网络和密码" return 1 fi } if command -v sshpass &>/dev/null; then USE_SSHPASS=true echo "[检测] sshpass 可用,全自动免交互" elif check_ssh_key; then USE_SSH_KEY=true echo "[检测] SSH 密钥已配置,免密登录" elif setup_ssh_key; then USE_SSH_KEY=true echo "[检测] SSH 密钥配置完成,后续部署全自动" else echo "" echo "========================================" echo " ⚠ 自动配置失败,请手动操作:" echo "" echo " 方案1: 安装 sshpass" echo " choco install sshpass" echo "" echo " 方案2: 手动配置 SSH 密钥" echo " ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''" echo " ssh-copy-id root@39.97.59.228" echo " (密码: ${PASS})" echo "========================================" echo "" read -p "按回车退出..." exit 1 fi echo "" # ============================================================ # 构建 SSH/SCP 命令 # ============================================================ if $USE_SSHPASS; then SSH_CMD="sshpass -p '${PASS}' ssh -o StrictHostKeyChecking=no -p ${PORT}" SSH_TAR="sshpass -p '${PASS}' ssh -o StrictHostKeyChecking=no -p ${PORT}" elif $USE_SSH_KEY; then SSH_CMD="ssh -o StrictHostKeyChecking=no -p ${PORT}" SSH_TAR="ssh -o StrictHostKeyChecking=no -p ${PORT}" SCP_CMD="scp -o StrictHostKeyChecking=no -P ${PORT}" fi # ============================================================ # 步骤 1: 确保远程目录存在 # ============================================================ echo "[步骤 1/4] 创建远程目录..." $SSH_CMD ${USER}@${HOST} "mkdir -p ${REMOTE_DIR}" echo " ✅ 远程目录已就绪" echo "" # ============================================================ # 步骤 2: 上传项目文件(tar 管道,支持 exclude + 一次认证) # ============================================================ echo "[步骤 2/4] 上传项目文件(全量覆盖)..." if $USE_SSHPASS || ! $USE_PUTTY; then # ── sshpass / 普通 SSH:tar 管道上传(最优)── cd "${LOCAL_DIR}" tar czf - \ --exclude='__pycache__' \ --exclude='*.pyc' \ --exclude='.git' \ --exclude='.gitignore' \ --exclude='data' \ --exclude='*.db' \ --exclude='*.db-shm' \ --exclude='*.db-wal' \ --exclude='uploads' \ --exclude='output' \ --exclude='logs' \ --exclude='*.egg-info' \ --exclude='.pytest_cache' \ --exclude='.vscode' \ --exclude='.idea' \ --exclude='venv' \ --exclude='.venv' \ --exclude='node_modules' \ --exclude='deploy.sh' \ --exclude='deploy.bat' \ . | ${SSH_TAR} ${USER}@${HOST} "cd ${REMOTE_DIR} && tar xzf -" else # ── PuTTY pscp:逐目录上传 ── ${SCP_CMD} \ "${LOCAL_DIR}/main.py" \ "${LOCAL_DIR}/requirements.txt" \ "${LOCAL_DIR}/restart.sh" \ "${LOCAL_DIR}/agents" \ "${LOCAL_DIR}/api" \ "${LOCAL_DIR}/tools" \ "${LOCAL_DIR}/skills" \ "${LOCAL_DIR}/db" \ ${USER}@${HOST}:${REMOTE_DIR}/ fi echo " ✅ 文件上传完成" echo "" # ============================================================ # 步骤 2.5: 上传 .env(如本地存在) # ============================================================ if [ -f "${LOCAL_DIR}/.env" ]; then echo "[步骤 2.5/4] 上传 .env 配置文件..." if $USE_SSHPASS || ! $USE_PUTTY; then cat "${LOCAL_DIR}/.env" | ${SSH_TAR} ${USER}@${HOST} "cat > ${REMOTE_DIR}/.env" else ${SCP_CMD} "${LOCAL_DIR}/.env" ${USER}@${HOST}:${REMOTE_DIR}/ fi echo " ✅ .env 已上传" echo "" fi # ============================================================ # 步骤 3: 安装/更新 Python 依赖 # ============================================================ echo "[步骤 3/5] 检查并安装 Python 依赖..." $SSH_CMD ${USER}@${HOST} << REMOTE_PIP set -e cd /data/vent_agent/vent_deep_agent_1.4 # 激活 conda 环境(与 restart.sh 保持一致) source /data/conda/conda3/etc/profile.d/conda.sh conda activate vent_deep_agent # 检查核心依赖是否已安装 if python3 -c "import paddleocr" 2>/dev/null; then echo " → 核心依赖已安装,跳过" else echo " → 首次部署,安装 Python 依赖(PaddleOCR ~200MB,需等待)..." pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com echo " ✅ 依赖安装完成" fi REMOTE_PIP echo "" # ============================================================ # 步骤 4: 杀旧进程(端口 8070) # ============================================================ echo "[步骤 4/5] 停止旧服务(端口 ${APP_PORT})..." $SSH_CMD ${USER}@${HOST} << 'REMOTE_KILL' APP_PORT=8070 PID=$(lsof -ti:${APP_PORT} 2>/dev/null || true) if [ -n "$PID" ]; then echo " → 终止进程 PID: ${PID}" kill -9 ${PID} 2>/dev/null || true sleep 1 echo " ✅ 旧进程已终止" else echo " → 端口 ${APP_PORT} 无进程占用" fi # 兜底 fuser -k ${APP_PORT}/tcp 2>/dev/null || true REMOTE_KILL echo "" # ============================================================ # 步骤 4: 启动服务 # ============================================================ echo "[步骤 5/5] 启动服务..." $SSH_CMD ${USER}@${HOST} << REMOTE_START set -e cd /data/vent_agent/vent_deep_agent_1.4 chmod +x restart.sh ./restart.sh REMOTE_START echo "" echo "等待服务启动..." sleep 4 # ============================================================ # 验证 # ============================================================ $SSH_CMD ${USER}@${HOST} << 'REMOTE_CHECK' APP_PORT=8070 if lsof -ti:${APP_PORT} &>/dev/null; then echo "" echo "========================================" echo " ✅ 部署成功!" echo " 服务地址: http://39.97.59.228:${APP_PORT}" echo " API 文档: http://39.97.59.228:${APP_PORT}/docs" echo "========================================" else echo "" echo "========================================" echo " ⚠ 服务可能未成功启动" echo " 手动检查: ssh root@39.97.59.228" echo " 查看日志: tail -f /data/vent_agent/vent_deep_agent_1.4/vent_deep_agent.log" echo "========================================" fi REMOTE_CHECK echo "" echo "完成。"