#!/bin/bash # 项目部署脚本 - 统一管理所有部署和维护操作 set -e echo "=============================================" echo " 端州区项目部署脚本 " echo "=============================================" # 配置变量 REMOTE_HOST="192.168.20.183" REMOTE_USER="root" REMOTE_PASS="123456" REMOTE_DIR="/root/dzxj_dtu" LOCAL_BACKEND_DIR="backend" LOCAL_FRONTEND_DIR="frontend" PORT=5001 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo_info() { echo -e "${GREEN}[信息]${NC} $1" } echo_warn() { echo -e "${YELLOW}[警告]${NC} $1" } echo_error() { echo -e "${RED}[错误]${NC} $1" } echo_success() { echo -e "${GREEN}[成功]${NC} $1" } # 功能:检查SSH连接 check_ssh() { echo_info "检查SSH连接..." if ping -c 1 -W 2 $REMOTE_HOST > /dev/null 2>&1; then echo_success "远程服务器可访问" return 0 else echo_error "无法访问远程服务器 $REMOTE_HOST" return 1 fi } # 功能:准备本地文件 prepare_files() { echo_info "准备部署文件..." # 检查必要目录是否存在 if [ ! -d "$LOCAL_BACKEND_DIR" ]; then echo_error "后端目录不存在: $LOCAL_BACKEND_DIR" return 1 fi if [ ! -d "$LOCAL_FRONTEND_DIR" ]; then echo_error "前端目录不存在: $LOCAL_FRONTEND_DIR" return 1 fi # 创建临时目录用于打包 TEMP_DIR=$(mktemp -d) echo_info "创建临时目录: $TEMP_DIR" # 创建完整的项目结构 mkdir -p "$TEMP_DIR/backend" mkdir -p "$TEMP_DIR/frontend" # 复制后端文件(保留完整目录结构) cp -r "$LOCAL_BACKEND_DIR"/* "$TEMP_DIR/backend/" echo_success "后端文件已复制到临时目录" # 复制前端构建文件(保留完整目录结构) if [ -d "$LOCAL_FRONTEND_DIR/dist" ]; then cp -r "$LOCAL_FRONTEND_DIR/dist" "$TEMP_DIR/frontend/" echo_success "前端构建文件已复制到临时目录" else echo_warn "前端dist目录不存在,跳过前端文件复制" fi # 复制安装脚本和配置文件 if [ -f "install_arm_ubuntu.sh" ]; then cp "install_arm_ubuntu.sh" "$TEMP_DIR/" chmod +x "$TEMP_DIR/install_arm_ubuntu.sh" echo_success "安装脚本已复制到临时目录" fi echo_success "文件准备完成" echo "$TEMP_DIR" } # 功能:上传文件到远程服务器 upload_files() { local temp_dir=$1 echo_info "上传文件到远程服务器..." # 使用expect实现自动登录和文件传输 cat > /tmp/upload.exp << 'EOF' #!/usr/bin/expect -f set timeout 600 spawn scp -r [lindex $argv 0]/* [lindex $argv 1]@[lindex $argv 2]:[lindex $argv 3]/ expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "[lindex $argv 4]\r" } } expect eof EOF chmod +x /tmp/upload.exp /tmp/upload.exp "$temp_dir" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_DIR" "$REMOTE_PASS" if [ $? -eq 0 ]; then echo_success "文件上传成功" return 0 else echo_error "文件上传失败" return 1 fi } # 功能:在远程服务器上安装依赖 install_dependencies() { echo_info "在远程服务器上安装依赖..." cat > /tmp/install_deps.exp << 'EOF' #!/usr/bin/expect -f set timeout 600 set remote_dir [lindex $argv 0] spawn ssh [lindex $argv 1]@[lindex $argv 2] expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "[lindex $argv 3]\r" } } expect "*#*" # 首先安装系统依赖 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" send "$install_cmd\r" expect "*#*" # 检查是否存在requirements.txt文件 send "if [ -f \"$remote_dir/backend/requirements.txt\" ]; then echo \"Found requirements.txt\"; else echo \"No requirements.txt found\"; fi\r" expect "*#*" # 创建Python虚拟环境 send "python3 -m venv $remote_dir/venv\r" expect "*#*" # 安装Python依赖 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" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/install_deps.exp /tmp/install_deps.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" if [ $? -eq 0 ]; then echo_success "依赖安装成功" return 0 else echo_error "依赖安装失败" return 1 fi } # 功能:释放占用的端口 release_port() { local port=$1 echo_info "释放端口 $port..." cat > /tmp/release_port.exp << EOF #!/usr/bin/expect -f set timeout 120 spawn ssh $REMOTE_USER@$REMOTE_HOST expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "$REMOTE_PASS\r" } } expect "*#*" send "echo '正在查找占用端口的进程...'\r" expect "*#*" # 使用多种方法查找并终止占用端口的进程 send "netstat -tulpn 2>/dev/null | grep :$port || echo '未找到进程 (netstat)'\r" expect "*#*" send "lsof -i :$port 2>/dev/null || echo '未找到进程 (lsof)'\r" expect "*#*" send "fuser -k $port/tcp 2>/dev/null || echo '未找到进程 (fuser)'\r" expect "*#*" send "sleep 2\r" expect "*#*" # 检查端口是否被释放 send "netstat -tulpn 2>/dev/null | grep :$port || echo '端口已释放'\r" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/release_port.exp /tmp/release_port.exp echo_success "端口释放操作完成" } # 功能:配置nginx configure_nginx() { echo_info "配置nginx部署前端..." cat > /tmp/configure_nginx.exp << 'EOF' #!/usr/bin/expect -f set timeout 120 set remote_dir [lindex $argv 0] set port [lindex $argv 4] spawn ssh [lindex $argv 1]@[lindex $argv 2] expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "[lindex $argv 3]\r" } } expect "*#*" # 创建nginx配置文件 set nginx_conf "dzxj_dtu.conf" send "cat > /etc/nginx/sites-available/$nginx_conf << 'NGINX_EOF'\r" expect "*#*" send "server {\r" send " listen 80;\r" send " server_name localhost;\r" send "\r" send " # 前端静态文件目录\r" send " root $remote_dir/frontend/dist;\r" send " index index.html;\r" send "\r" send " location / {\r" send " try_files \$uri \$uri/ /index.html;\r" send " }\r" send "\r" send " # 代理后端API请求\r" send " location /api {\r" send " proxy_pass http://localhost:$port/api;\r" send " proxy_set_header Host \$host;\r" send " proxy_set_header X-Real-IP \$remote_addr;\r" send " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\r" send " proxy_set_header X-Forwarded-Proto \$scheme;\r" send " }\r" send "\r" send " # WebSocket连接代理\r" send " location /socket.io {\r" send " proxy_pass http://localhost:$port/socket.io;\r" send " proxy_http_version 1.1;\r" send " proxy_set_header Upgrade \$http_upgrade;\r" send " proxy_set_header Connection 'upgrade';\r" send " proxy_set_header Host \$host;\r" send " proxy_cache_bypass \$http_upgrade;\r" send " }\r" send "}\r" send "NGINX_EOF\r" expect "*#*" # 启用nginx配置 send "if [ -f /etc/nginx/sites-enabled/default ]; then rm /etc/nginx/sites-enabled/default; fi\r" expect "*#*" send "ln -sf /etc/nginx/sites-available/$nginx_conf /etc/nginx/sites-enabled/\r" expect "*#*" # 测试nginx配置并重启 send "nginx -t\r" expect "*#*" send "systemctl restart nginx\r" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/configure_nginx.exp /tmp/configure_nginx.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT" echo_success "nginx配置完成" } # 功能:在远程服务器上启动服务 start_service() { echo_info "启动后端服务..." cat > /tmp/start_service.exp << 'EOF' #!/usr/bin/expect -f set timeout 120 set remote_dir [lindex $argv 0] spawn ssh [lindex $argv 1]@[lindex $argv 2] expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "[lindex $argv 3]\r" } } expect "*#*" # 确保使用虚拟环境启动服务 send "cd $remote_dir/backend && source ../venv/bin/activate && nohup python3 app.py > /tmp/app_service.log 2>&1 &\r" expect "*#*" send "sleep 3\r" expect "*#*" # 检查服务是否启动 send "ps aux | grep 'python3 app.py' | grep -v grep || echo '服务未启动'\r" expect "*#*" # 检查端口监听 send "netstat -tulpn 2>/dev/null | grep :[lindex $argv 4] || echo '端口未监听'\r" expect "*#*" # 显示日志开头 send "echo '\n服务日志:'\r" expect "*#*" send "head -n 20 /tmp/app_service.log\r" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/start_service.exp /tmp/start_service.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT" echo_success "服务启动操作完成" } # 功能:检查服务状态 check_service() { echo_info "检查服务状态..." cat > /tmp/check_service.exp << EOF #!/usr/bin/expect -f set timeout 120 spawn ssh $REMOTE_USER@$REMOTE_HOST expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "$REMOTE_PASS\r" } } expect "*#*" send "echo '服务进程状态:'\r" expect "*#*" send "ps aux | grep 'python3 app.py' | grep -v grep\r" expect "*#*" send "echo '\n端口监听状态:'\r" expect "*#*" send "netstat -tulpn 2>/dev/null | grep :$PORT\r" expect "*#*" send "echo '\n网络接口信息:'\r" expect "*#*" send "ip addr show\r" expect "*#*" send "echo '\n测试API可用性:'\r" expect "*#*" send "curl -s http://localhost:$PORT/api/health || echo 'API不可访问'\r" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/check_service.exp /tmp/check_service.exp echo_success "服务状态检查完成" } # 功能:停止远程服务 stop_service() { echo_info "停止后端服务..." cat > /tmp/stop_service.exp << 'EOF' #!/usr/bin/expect -f set timeout 120 spawn ssh [lindex $argv 0]@[lindex $argv 1] expect { "*yes/no*" { send "yes\r" exp_continue } "*password:*" { send "[lindex $argv 2]\r" } } expect "*#*" send "echo '停止服务进程...'\r" expect "*#*" send "pkill -f 'python3 app.py' || echo '未找到服务进程'\r" expect "*#*" send "sleep 2\r" expect "*#*" # 确认进程已停止 send "ps aux | grep 'python3 app.py' | grep -v grep || echo '服务已停止'\r" expect "*#*" send "exit\r" expect eof EOF chmod +x /tmp/stop_service.exp /tmp/stop_service.exp "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" echo_success "服务停止操作完成" } # 显示帮助信息 show_help() { echo "使用方法: $0 [选项]" echo "" echo "选项:" echo " --deploy 执行完整部署流程(检查、准备、上传、安装、启动、nginx配置)" echo " --start 仅启动服务" echo " --stop 仅停止服务" echo " --restart 重启服务" echo " --status 检查服务状态" echo " --release-port 释放占用的端口" echo " --install-deps 安装依赖" echo " --configure-nginx 配置nginx" echo " --check-ssh 检查SSH连接" echo " --help 显示此帮助信息" echo "" echo "示例:" echo " $0 --deploy # 执行完整部署" echo " $0 --restart # 重启服务" echo " $0 --status # 检查服务状态" } # 主函数 main() { if [ $# -eq 0 ]; then show_help exit 1 fi case "$1" in --deploy) echo_info "开始完整部署流程..." check_ssh && \ TEMP_DIR=$(prepare_files) && \ upload_files "$TEMP_DIR" && \ install_dependencies && \ release_port $PORT && \ configure_nginx && \ start_service && \ check_service ;; --start) start_service ;; --stop) stop_service ;; --restart) stop_service && \ release_port $PORT && \ start_service && \ check_service ;; --status) check_service ;; --release-port) release_port $PORT ;; --install-deps) install_dependencies ;; --configure-nginx) configure_nginx ;; --check-ssh) check_ssh ;; --help) show_help exit 0 ;; *) echo_error "未知选项: $1" show_help exit 1 ;; esac # 清理临时文件 if [ -d "$TEMP_DIR" ]; then rm -rf "$TEMP_DIR" fi rm -f /tmp/*.exp echo_success "操作完成!" } # 执行主函数 main "$@"