deploy.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #!/bin/bash
  2. # 项目部署脚本 - 统一管理所有部署和维护操作
  3. set -e
  4. echo "============================================="
  5. echo " 端州区项目部署脚本 "
  6. echo "============================================="
  7. # 配置变量
  8. REMOTE_HOST="192.168.20.183"
  9. REMOTE_USER="root"
  10. REMOTE_PASS="123456"
  11. REMOTE_DIR="/root/dzxj_dtu"
  12. LOCAL_BACKEND_DIR="backend"
  13. LOCAL_FRONTEND_DIR="frontend"
  14. PORT=5001
  15. # 颜色定义
  16. RED='\033[0;31m'
  17. GREEN='\033[0;32m'
  18. YELLOW='\033[1;33m'
  19. NC='\033[0m' # No Color
  20. echo_info() {
  21. echo -e "${GREEN}[信息]${NC} $1"
  22. }
  23. echo_warn() {
  24. echo -e "${YELLOW}[警告]${NC} $1"
  25. }
  26. echo_error() {
  27. echo -e "${RED}[错误]${NC} $1"
  28. }
  29. echo_success() {
  30. echo -e "${GREEN}[成功]${NC} $1"
  31. }
  32. # 功能:检查SSH连接
  33. check_ssh() {
  34. echo_info "检查SSH连接..."
  35. if ping -c 1 -W 2 $REMOTE_HOST > /dev/null 2>&1; then
  36. echo_success "远程服务器可访问"
  37. return 0
  38. else
  39. echo_error "无法访问远程服务器 $REMOTE_HOST"
  40. return 1
  41. fi
  42. }
  43. # 功能:准备本地文件
  44. prepare_files() {
  45. echo_info "准备部署文件..."
  46. # 检查必要目录是否存在
  47. if [ ! -d "$LOCAL_BACKEND_DIR" ]; then
  48. echo_error "后端目录不存在: $LOCAL_BACKEND_DIR"
  49. return 1
  50. fi
  51. if [ ! -d "$LOCAL_FRONTEND_DIR" ]; then
  52. echo_error "前端目录不存在: $LOCAL_FRONTEND_DIR"
  53. return 1
  54. fi
  55. # 创建临时目录用于打包
  56. TEMP_DIR=$(mktemp -d)
  57. echo_info "创建临时目录: $TEMP_DIR"
  58. # 创建完整的项目结构
  59. mkdir -p "$TEMP_DIR/backend"
  60. mkdir -p "$TEMP_DIR/frontend"
  61. # 复制后端文件(保留完整目录结构)
  62. cp -r "$LOCAL_BACKEND_DIR"/* "$TEMP_DIR/backend/"
  63. echo_success "后端文件已复制到临时目录"
  64. # 复制前端构建文件(保留完整目录结构)
  65. if [ -d "$LOCAL_FRONTEND_DIR/dist" ]; then
  66. cp -r "$LOCAL_FRONTEND_DIR/dist" "$TEMP_DIR/frontend/"
  67. echo_success "前端构建文件已复制到临时目录"
  68. else
  69. echo_warn "前端dist目录不存在,跳过前端文件复制"
  70. fi
  71. # 复制安装脚本和配置文件
  72. if [ -f "install_arm_ubuntu.sh" ]; then
  73. cp "install_arm_ubuntu.sh" "$TEMP_DIR/"
  74. chmod +x "$TEMP_DIR/install_arm_ubuntu.sh"
  75. echo_success "安装脚本已复制到临时目录"
  76. fi
  77. echo_success "文件准备完成"
  78. echo "$TEMP_DIR"
  79. }
  80. # 功能:上传文件到远程服务器
  81. upload_files() {
  82. local temp_dir=$1
  83. echo_info "上传文件到远程服务器..."
  84. # 使用expect实现自动登录和文件传输
  85. cat > /tmp/upload.exp << 'EOF'
  86. #!/usr/bin/expect -f
  87. set timeout 600
  88. spawn scp -r [lindex $argv 0]/* [lindex $argv 1]@[lindex $argv 2]:[lindex $argv 3]/
  89. expect {
  90. "*yes/no*" {
  91. send "yes\r"
  92. exp_continue
  93. }
  94. "*password:*" {
  95. send "[lindex $argv 4]\r"
  96. }
  97. }
  98. expect eof
  99. EOF
  100. chmod +x /tmp/upload.exp
  101. /tmp/upload.exp "$temp_dir" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_DIR" "$REMOTE_PASS"
  102. if [ $? -eq 0 ]; then
  103. echo_success "文件上传成功"
  104. return 0
  105. else
  106. echo_error "文件上传失败"
  107. return 1
  108. fi
  109. }
  110. # 功能:在远程服务器上安装依赖
  111. install_dependencies() {
  112. echo_info "在远程服务器上安装依赖..."
  113. cat > /tmp/install_deps.exp << 'EOF'
  114. #!/usr/bin/expect -f
  115. set timeout 600
  116. set remote_dir [lindex $argv 0]
  117. spawn ssh [lindex $argv 1]@[lindex $argv 2]
  118. expect {
  119. "*yes/no*" {
  120. send "yes\r"
  121. exp_continue
  122. }
  123. "*password:*" {
  124. send "[lindex $argv 3]\r"
  125. }
  126. }
  127. expect "*#*"
  128. # 首先安装系统依赖
  129. set install_cmd "apt-get update && apt-get install -y --no-install-recommends python3 python3-venv python3-pip python3-dev gcc libffi-dev make git curl net-tools iproute2 nginx mosquitto mosquitto-clients"
  130. send "$install_cmd\r"
  131. expect "*#*"
  132. # 检查是否存在requirements.txt文件
  133. send "if [ -f \"$remote_dir/backend/requirements.txt\" ]; then echo \"Found requirements.txt\"; else echo \"No requirements.txt found\"; fi\r"
  134. expect "*#*"
  135. # 创建Python虚拟环境
  136. send "python3 -m venv $remote_dir/venv\r"
  137. expect "*#*"
  138. # 安装Python依赖
  139. send "source $remote_dir/venv/bin/activate && pip install --upgrade pip && pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && pip install --no-cache-dir -r $remote_dir/backend/requirements.txt\r"
  140. expect "*#*"
  141. send "exit\r"
  142. expect eof
  143. EOF
  144. chmod +x /tmp/install_deps.exp
  145. /tmp/install_deps.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  146. if [ $? -eq 0 ]; then
  147. echo_success "依赖安装成功"
  148. return 0
  149. else
  150. echo_error "依赖安装失败"
  151. return 1
  152. fi
  153. }
  154. # 功能:释放占用的端口
  155. release_port() {
  156. local port=$1
  157. echo_info "释放端口 $port..."
  158. cat > /tmp/release_port.exp << EOF
  159. #!/usr/bin/expect -f
  160. set timeout 120
  161. spawn ssh $REMOTE_USER@$REMOTE_HOST
  162. expect {
  163. "*yes/no*" {
  164. send "yes\r"
  165. exp_continue
  166. }
  167. "*password:*" {
  168. send "$REMOTE_PASS\r"
  169. }
  170. }
  171. expect "*#*"
  172. send "echo '正在查找占用端口的进程...'\r"
  173. expect "*#*"
  174. # 使用多种方法查找并终止占用端口的进程
  175. send "netstat -tulpn 2>/dev/null | grep :$port || echo '未找到进程 (netstat)'\r"
  176. expect "*#*"
  177. send "lsof -i :$port 2>/dev/null || echo '未找到进程 (lsof)'\r"
  178. expect "*#*"
  179. send "fuser -k $port/tcp 2>/dev/null || echo '未找到进程 (fuser)'\r"
  180. expect "*#*"
  181. send "sleep 2\r"
  182. expect "*#*"
  183. # 检查端口是否被释放
  184. send "netstat -tulpn 2>/dev/null | grep :$port || echo '端口已释放'\r"
  185. expect "*#*"
  186. send "exit\r"
  187. expect eof
  188. EOF
  189. chmod +x /tmp/release_port.exp
  190. /tmp/release_port.exp
  191. echo_success "端口释放操作完成"
  192. }
  193. # 功能:配置nginx
  194. configure_nginx() {
  195. echo_info "配置nginx部署前端..."
  196. cat > /tmp/configure_nginx.exp << 'EOF'
  197. #!/usr/bin/expect -f
  198. set timeout 120
  199. set remote_dir [lindex $argv 0]
  200. set port [lindex $argv 4]
  201. spawn ssh [lindex $argv 1]@[lindex $argv 2]
  202. expect {
  203. "*yes/no*" {
  204. send "yes\r"
  205. exp_continue
  206. }
  207. "*password:*" {
  208. send "[lindex $argv 3]\r"
  209. }
  210. }
  211. expect "*#*"
  212. # 创建nginx配置文件
  213. set nginx_conf "dzxj_dtu.conf"
  214. send "cat > /etc/nginx/sites-available/$nginx_conf << 'NGINX_EOF'\r"
  215. expect "*#*"
  216. send "server {\r"
  217. send " listen 80;\r"
  218. send " server_name localhost;\r"
  219. send "\r"
  220. send " # 前端静态文件目录\r"
  221. send " root $remote_dir/frontend/dist;\r"
  222. send " index index.html;\r"
  223. send "\r"
  224. send " location / {\r"
  225. send " try_files \$uri \$uri/ /index.html;\r"
  226. send " }\r"
  227. send "\r"
  228. send " # 代理后端API请求\r"
  229. send " location /api {\r"
  230. send " proxy_pass http://localhost:$port/api;\r"
  231. send " proxy_set_header Host \$host;\r"
  232. send " proxy_set_header X-Real-IP \$remote_addr;\r"
  233. send " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\r"
  234. send " proxy_set_header X-Forwarded-Proto \$scheme;\r"
  235. send " }\r"
  236. send "\r"
  237. send " # WebSocket连接代理\r"
  238. send " location /socket.io {\r"
  239. send " proxy_pass http://localhost:$port/socket.io;\r"
  240. send " proxy_http_version 1.1;\r"
  241. send " proxy_set_header Upgrade \$http_upgrade;\r"
  242. send " proxy_set_header Connection 'upgrade';\r"
  243. send " proxy_set_header Host \$host;\r"
  244. send " proxy_cache_bypass \$http_upgrade;\r"
  245. send " }\r"
  246. send "}\r"
  247. send "NGINX_EOF\r"
  248. expect "*#*"
  249. # 启用nginx配置
  250. send "if [ -f /etc/nginx/sites-enabled/default ]; then rm /etc/nginx/sites-enabled/default; fi\r"
  251. expect "*#*"
  252. send "ln -sf /etc/nginx/sites-available/$nginx_conf /etc/nginx/sites-enabled/\r"
  253. expect "*#*"
  254. # 测试nginx配置并重启
  255. send "nginx -t\r"
  256. expect "*#*"
  257. send "systemctl restart nginx\r"
  258. expect "*#*"
  259. send "exit\r"
  260. expect eof
  261. EOF
  262. chmod +x /tmp/configure_nginx.exp
  263. /tmp/configure_nginx.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT"
  264. echo_success "nginx配置完成"
  265. }
  266. # 功能:在远程服务器上启动服务
  267. start_service() {
  268. echo_info "启动后端服务..."
  269. cat > /tmp/start_service.exp << 'EOF'
  270. #!/usr/bin/expect -f
  271. set timeout 120
  272. set remote_dir [lindex $argv 0]
  273. spawn ssh [lindex $argv 1]@[lindex $argv 2]
  274. expect {
  275. "*yes/no*" {
  276. send "yes\r"
  277. exp_continue
  278. }
  279. "*password:*" {
  280. send "[lindex $argv 3]\r"
  281. }
  282. }
  283. expect "*#*"
  284. # 确保使用虚拟环境启动服务
  285. send "cd $remote_dir/backend && source ../venv/bin/activate && nohup python3 app.py > /tmp/app_service.log 2>&1 &\r"
  286. expect "*#*"
  287. send "sleep 3\r"
  288. expect "*#*"
  289. # 检查服务是否启动
  290. send "ps aux | grep 'python3 app.py' | grep -v grep || echo '服务未启动'\r"
  291. expect "*#*"
  292. # 检查端口监听
  293. send "netstat -tulpn 2>/dev/null | grep :[lindex $argv 4] || echo '端口未监听'\r"
  294. expect "*#*"
  295. # 显示日志开头
  296. send "echo '\n服务日志:'\r"
  297. expect "*#*"
  298. send "head -n 20 /tmp/app_service.log\r"
  299. expect "*#*"
  300. send "exit\r"
  301. expect eof
  302. EOF
  303. chmod +x /tmp/start_service.exp
  304. /tmp/start_service.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT"
  305. echo_success "服务启动操作完成"
  306. }
  307. # 功能:检查服务状态
  308. check_service() {
  309. echo_info "检查服务状态..."
  310. cat > /tmp/check_service.exp << EOF
  311. #!/usr/bin/expect -f
  312. set timeout 120
  313. spawn ssh $REMOTE_USER@$REMOTE_HOST
  314. expect {
  315. "*yes/no*" {
  316. send "yes\r"
  317. exp_continue
  318. }
  319. "*password:*" {
  320. send "$REMOTE_PASS\r"
  321. }
  322. }
  323. expect "*#*"
  324. send "echo '服务进程状态:'\r"
  325. expect "*#*"
  326. send "ps aux | grep 'python3 app.py' | grep -v grep\r"
  327. expect "*#*"
  328. send "echo '\n端口监听状态:'\r"
  329. expect "*#*"
  330. send "netstat -tulpn 2>/dev/null | grep :$PORT\r"
  331. expect "*#*"
  332. send "echo '\n网络接口信息:'\r"
  333. expect "*#*"
  334. send "ip addr show\r"
  335. expect "*#*"
  336. send "echo '\n测试API可用性:'\r"
  337. expect "*#*"
  338. send "curl -s http://localhost:$PORT/api/health || echo 'API不可访问'\r"
  339. expect "*#*"
  340. send "exit\r"
  341. expect eof
  342. EOF
  343. chmod +x /tmp/check_service.exp
  344. /tmp/check_service.exp
  345. echo_success "服务状态检查完成"
  346. }
  347. # 功能:停止远程服务
  348. stop_service() {
  349. echo_info "停止后端服务..."
  350. cat > /tmp/stop_service.exp << 'EOF'
  351. #!/usr/bin/expect -f
  352. set timeout 120
  353. spawn ssh [lindex $argv 0]@[lindex $argv 1]
  354. expect {
  355. "*yes/no*" {
  356. send "yes\r"
  357. exp_continue
  358. }
  359. "*password:*" {
  360. send "[lindex $argv 2]\r"
  361. }
  362. }
  363. expect "*#*"
  364. send "echo '停止服务进程...'\r"
  365. expect "*#*"
  366. send "pkill -f 'python3 app.py' || echo '未找到服务进程'\r"
  367. expect "*#*"
  368. send "sleep 2\r"
  369. expect "*#*"
  370. # 确认进程已停止
  371. send "ps aux | grep 'python3 app.py' | grep -v grep || echo '服务已停止'\r"
  372. expect "*#*"
  373. send "exit\r"
  374. expect eof
  375. EOF
  376. chmod +x /tmp/stop_service.exp
  377. /tmp/stop_service.exp "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  378. echo_success "服务停止操作完成"
  379. }
  380. # 显示帮助信息
  381. show_help() {
  382. echo "使用方法: $0 [选项]"
  383. echo ""
  384. echo "选项:"
  385. echo " --deploy 执行完整部署流程(检查、准备、上传、安装、启动、nginx配置)"
  386. echo " --start 仅启动服务"
  387. echo " --stop 仅停止服务"
  388. echo " --restart 重启服务"
  389. echo " --status 检查服务状态"
  390. echo " --release-port 释放占用的端口"
  391. echo " --install-deps 安装依赖"
  392. echo " --configure-nginx 配置nginx"
  393. echo " --check-ssh 检查SSH连接"
  394. echo " --help 显示此帮助信息"
  395. echo ""
  396. echo "示例:"
  397. echo " $0 --deploy # 执行完整部署"
  398. echo " $0 --restart # 重启服务"
  399. echo " $0 --status # 检查服务状态"
  400. }
  401. # 主函数
  402. main() {
  403. if [ $# -eq 0 ]; then
  404. show_help
  405. exit 1
  406. fi
  407. case "$1" in
  408. --deploy)
  409. echo_info "开始完整部署流程..."
  410. check_ssh && \
  411. TEMP_DIR=$(prepare_files) && \
  412. upload_files "$TEMP_DIR" && \
  413. install_dependencies && \
  414. release_port $PORT && \
  415. configure_nginx && \
  416. start_service && \
  417. check_service
  418. ;;
  419. --start)
  420. start_service
  421. ;;
  422. --stop)
  423. stop_service
  424. ;;
  425. --restart)
  426. stop_service && \
  427. release_port $PORT && \
  428. start_service && \
  429. check_service
  430. ;;
  431. --status)
  432. check_service
  433. ;;
  434. --release-port)
  435. release_port $PORT
  436. ;;
  437. --install-deps)
  438. install_dependencies
  439. ;;
  440. --configure-nginx)
  441. configure_nginx
  442. ;;
  443. --check-ssh)
  444. check_ssh
  445. ;;
  446. --help)
  447. show_help
  448. exit 0
  449. ;;
  450. *)
  451. echo_error "未知选项: $1"
  452. show_help
  453. exit 1
  454. ;;
  455. esac
  456. # 清理临时文件
  457. if [ -d "$TEMP_DIR" ]; then
  458. rm -rf "$TEMP_DIR"
  459. fi
  460. rm -f /tmp/*.exp
  461. echo_success "操作完成!"
  462. }
  463. # 执行主函数
  464. main "$@"