deploy.sh 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #!/bin/bash
  2. # ============================================================
  3. # Windows Git Bash → Linux 一键部署脚本
  4. # 用法: 在 Git Bash 中运行 bash deploy.sh
  5. # ============================================================
  6. set -e
  7. # ── 服务器配置 ──
  8. HOST="39.97.59.228"
  9. USER="root"
  10. PASS="Ccri123456"
  11. PORT="22"
  12. REMOTE_DIR="/data/vent_agent/vent_deep_agent_1.4"
  13. APP_PORT="8070"
  14. # ── 本地项目根目录(脚本所在目录)──
  15. LOCAL_DIR="$(cd "$(dirname "$0")" && pwd)"
  16. echo "========================================"
  17. echo " 配风计划审查系统 - 一键部署"
  18. echo "========================================"
  19. echo " 服务器: ${USER}@${HOST}:${PORT}"
  20. echo " 远程目录: ${REMOTE_DIR}"
  21. echo " 本地目录: ${LOCAL_DIR}"
  22. echo "========================================"
  23. # ============================================================
  24. # 密码自动注入方案选择
  25. # ============================================================
  26. # 优先级: sshpass > SSH 密钥 > PuTTY(已废弃,不再推荐)
  27. # ============================================================
  28. USE_SSHPASS=false
  29. USE_SSH_KEY=false
  30. USE_PUTTY=false
  31. # ── 检查 SSH 密钥是否已配置 ──
  32. check_ssh_key() {
  33. if [ -f ~/.ssh/id_rsa ] || [ -f ~/.ssh/id_ed25519 ] || [ -f ~/.ssh/id_ecdsa ]; then
  34. # 测试是否能免密连接
  35. if ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=5 -p ${PORT} ${USER}@${HOST} "echo ok" &>/dev/null; then
  36. return 0
  37. fi
  38. fi
  39. return 1
  40. }
  41. # ── 自动配置 SSH 密钥(首次需要输入密码)──
  42. setup_ssh_key() {
  43. echo ""
  44. echo "========================================"
  45. echo " 首次部署:配置 SSH 密钥免密登录"
  46. echo " 密码已预设,只需按一次回车确认"
  47. echo "========================================"
  48. echo ""
  49. # 生成密钥(如不存在)
  50. if [ ! -f ~/.ssh/id_rsa ]; then
  51. echo "[1/2] 生成 SSH 密钥对..."
  52. ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -N "" -q
  53. echo " ✅ 密钥已生成: ~/.ssh/id_rsa"
  54. else
  55. echo "[1/2] SSH 密钥已存在,跳过生成"
  56. fi
  57. # 复制公钥到服务器(首次需要密码)
  58. echo "[2/2] 复制公钥到服务器..."
  59. echo " → 服务器: ${USER}@${HOST}:${PORT}"
  60. echo " → 密码: ${PASS}"
  61. echo " → 请输入上述密码(仅此一次,之后全自动):"
  62. echo ""
  63. # 使用 ssh-copy-id(会提示输入密码),临时关闭 set -e 以处理错误
  64. set +e
  65. ssh-copy-id -o StrictHostKeyChecking=no -p ${PORT} ${USER}@${HOST}
  66. local copy_ret=$?
  67. set -e
  68. if [ $copy_ret -eq 0 ]; then
  69. echo ""
  70. echo " ✅ SSH 密钥已部署到服务器,以后部署全自动免密!"
  71. USE_SSH_KEY=true
  72. return 0
  73. else
  74. echo ""
  75. echo " ❌ SSH 密钥配置失败(退出码: ${copy_ret}),请检查网络和密码"
  76. return 1
  77. fi
  78. }
  79. if command -v sshpass &>/dev/null; then
  80. USE_SSHPASS=true
  81. echo "[检测] sshpass 可用,全自动免交互"
  82. elif check_ssh_key; then
  83. USE_SSH_KEY=true
  84. echo "[检测] SSH 密钥已配置,免密登录"
  85. elif setup_ssh_key; then
  86. USE_SSH_KEY=true
  87. echo "[检测] SSH 密钥配置完成,后续部署全自动"
  88. else
  89. echo ""
  90. echo "========================================"
  91. echo " ⚠ 自动配置失败,请手动操作:"
  92. echo ""
  93. echo " 方案1: 安装 sshpass"
  94. echo " choco install sshpass"
  95. echo ""
  96. echo " 方案2: 手动配置 SSH 密钥"
  97. echo " ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''"
  98. echo " ssh-copy-id root@39.97.59.228"
  99. echo " (密码: ${PASS})"
  100. echo "========================================"
  101. echo ""
  102. read -p "按回车退出..."
  103. exit 1
  104. fi
  105. echo ""
  106. # ============================================================
  107. # 构建 SSH/SCP 命令
  108. # ============================================================
  109. if $USE_SSHPASS; then
  110. SSH_CMD="sshpass -p '${PASS}' ssh -o StrictHostKeyChecking=no -p ${PORT}"
  111. SSH_TAR="sshpass -p '${PASS}' ssh -o StrictHostKeyChecking=no -p ${PORT}"
  112. elif $USE_SSH_KEY; then
  113. SSH_CMD="ssh -o StrictHostKeyChecking=no -p ${PORT}"
  114. SSH_TAR="ssh -o StrictHostKeyChecking=no -p ${PORT}"
  115. SCP_CMD="scp -o StrictHostKeyChecking=no -P ${PORT}"
  116. fi
  117. # ============================================================
  118. # 步骤 1: 确保远程目录存在
  119. # ============================================================
  120. echo "[步骤 1/4] 创建远程目录..."
  121. $SSH_CMD ${USER}@${HOST} "mkdir -p ${REMOTE_DIR}"
  122. echo " ✅ 远程目录已就绪"
  123. echo ""
  124. # ============================================================
  125. # 步骤 2: 上传项目文件(tar 管道,支持 exclude + 一次认证)
  126. # ============================================================
  127. echo "[步骤 2/4] 上传项目文件(全量覆盖)..."
  128. if $USE_SSHPASS || ! $USE_PUTTY; then
  129. # ── sshpass / 普通 SSH:tar 管道上传(最优)──
  130. cd "${LOCAL_DIR}"
  131. tar czf - \
  132. --exclude='__pycache__' \
  133. --exclude='*.pyc' \
  134. --exclude='.git' \
  135. --exclude='.gitignore' \
  136. --exclude='data' \
  137. --exclude='*.db' \
  138. --exclude='*.db-shm' \
  139. --exclude='*.db-wal' \
  140. --exclude='uploads' \
  141. --exclude='output' \
  142. --exclude='logs' \
  143. --exclude='*.egg-info' \
  144. --exclude='.pytest_cache' \
  145. --exclude='.vscode' \
  146. --exclude='.idea' \
  147. --exclude='venv' \
  148. --exclude='.venv' \
  149. --exclude='node_modules' \
  150. --exclude='deploy.sh' \
  151. --exclude='deploy.bat' \
  152. . | ${SSH_TAR} ${USER}@${HOST} "cd ${REMOTE_DIR} && tar xzf -"
  153. else
  154. # ── PuTTY pscp:逐目录上传 ──
  155. ${SCP_CMD} \
  156. "${LOCAL_DIR}/main.py" \
  157. "${LOCAL_DIR}/requirements.txt" \
  158. "${LOCAL_DIR}/restart.sh" \
  159. "${LOCAL_DIR}/agents" \
  160. "${LOCAL_DIR}/api" \
  161. "${LOCAL_DIR}/tools" \
  162. "${LOCAL_DIR}/skills" \
  163. "${LOCAL_DIR}/db" \
  164. ${USER}@${HOST}:${REMOTE_DIR}/
  165. fi
  166. echo " ✅ 文件上传完成"
  167. echo ""
  168. # ============================================================
  169. # 步骤 2.5: 上传 .env(如本地存在)
  170. # ============================================================
  171. if [ -f "${LOCAL_DIR}/.env" ]; then
  172. echo "[步骤 2.5/4] 上传 .env 配置文件..."
  173. if $USE_SSHPASS || ! $USE_PUTTY; then
  174. cat "${LOCAL_DIR}/.env" | ${SSH_TAR} ${USER}@${HOST} "cat > ${REMOTE_DIR}/.env"
  175. else
  176. ${SCP_CMD} "${LOCAL_DIR}/.env" ${USER}@${HOST}:${REMOTE_DIR}/
  177. fi
  178. echo " ✅ .env 已上传"
  179. echo ""
  180. fi
  181. # ============================================================
  182. # 步骤 3: 安装/更新 Python 依赖
  183. # ============================================================
  184. echo "[步骤 3/5] 检查并安装 Python 依赖..."
  185. $SSH_CMD ${USER}@${HOST} << REMOTE_PIP
  186. set -e
  187. cd /data/vent_agent/vent_deep_agent_1.4
  188. # 激活 conda 环境(与 restart.sh 保持一致)
  189. source /data/conda/conda3/etc/profile.d/conda.sh
  190. conda activate vent_deep_agent
  191. # 检查核心依赖是否已安装
  192. if python3 -c "import paddleocr" 2>/dev/null; then
  193. echo " → 核心依赖已安装,跳过"
  194. else
  195. echo " → 首次部署,安装 Python 依赖(PaddleOCR ~200MB,需等待)..."
  196. pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
  197. echo " ✅ 依赖安装完成"
  198. fi
  199. REMOTE_PIP
  200. echo ""
  201. # ============================================================
  202. # 步骤 4: 杀旧进程(端口 8070)
  203. # ============================================================
  204. echo "[步骤 4/5] 停止旧服务(端口 ${APP_PORT})..."
  205. $SSH_CMD ${USER}@${HOST} << 'REMOTE_KILL'
  206. APP_PORT=8070
  207. PID=$(lsof -ti:${APP_PORT} 2>/dev/null || true)
  208. if [ -n "$PID" ]; then
  209. echo " → 终止进程 PID: ${PID}"
  210. kill -9 ${PID} 2>/dev/null || true
  211. sleep 1
  212. echo " ✅ 旧进程已终止"
  213. else
  214. echo " → 端口 ${APP_PORT} 无进程占用"
  215. fi
  216. # 兜底
  217. fuser -k ${APP_PORT}/tcp 2>/dev/null || true
  218. REMOTE_KILL
  219. echo ""
  220. # ============================================================
  221. # 步骤 4: 启动服务
  222. # ============================================================
  223. echo "[步骤 5/5] 启动服务..."
  224. $SSH_CMD ${USER}@${HOST} << REMOTE_START
  225. set -e
  226. cd /data/vent_agent/vent_deep_agent_1.4
  227. chmod +x restart.sh
  228. ./restart.sh
  229. REMOTE_START
  230. echo ""
  231. echo "等待服务启动..."
  232. sleep 4
  233. # ============================================================
  234. # 验证
  235. # ============================================================
  236. $SSH_CMD ${USER}@${HOST} << 'REMOTE_CHECK'
  237. APP_PORT=8070
  238. if lsof -ti:${APP_PORT} &>/dev/null; then
  239. echo ""
  240. echo "========================================"
  241. echo " ✅ 部署成功!"
  242. echo " 服务地址: http://39.97.59.228:${APP_PORT}"
  243. echo " API 文档: http://39.97.59.228:${APP_PORT}/docs"
  244. echo "========================================"
  245. else
  246. echo ""
  247. echo "========================================"
  248. echo " ⚠ 服务可能未成功启动"
  249. echo " 手动检查: ssh root@39.97.59.228"
  250. echo " 查看日志: tail -f /data/vent_agent/vent_deep_agent_1.4/vent_deep_agent.log"
  251. echo "========================================"
  252. fi
  253. REMOTE_CHECK
  254. echo ""
  255. echo "完成。"