315 lines
11 KiB
Bash
Executable File
315 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# ================================================================
|
||
# 蝶雅智能体平台 - 一键迁移到生产服务器
|
||
# ================================================================
|
||
set -euo pipefail
|
||
|
||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
||
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
|
||
|
||
# ================================================================
|
||
DB_USER="dy_app"
|
||
DB_PASS="dy_data_2026"
|
||
DB_NAME="dy_data"
|
||
APP_PORT=18888
|
||
|
||
# ================================================================
|
||
clear
|
||
echo -e "${CYAN}============================================${NC}"
|
||
echo -e "${CYAN} 蝶雅智能体平台 → 生产服务器一键迁移${NC}"
|
||
echo -e "${CYAN}============================================${NC}"
|
||
echo ""
|
||
|
||
read -rp "请输入新电脑 IP 地址: " REMOTE_IP
|
||
read -rp "请输入新电脑 SSH 用户名(默认 gxd): " REMOTE_USER
|
||
REMOTE_USER="${REMOTE_USER:-gxd}"
|
||
|
||
# 自动获取新电脑的家目录
|
||
REMOTE_HOME=$(ssh -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_IP}" "echo \$HOME" 2>/dev/null)
|
||
if [ -z "${REMOTE_HOME}" ]; then
|
||
err "无法获取远程家目录,请检查 SSH 连接"
|
||
fi
|
||
REMOTE_DIR="${REMOTE_HOME}/.openclaw/workspace/dy-dashboard"
|
||
|
||
echo ""
|
||
info "新电脑用户:${REMOTE_USER}"
|
||
info "家目录:${REMOTE_HOME}"
|
||
info "项目路径:${REMOTE_DIR}"
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 1. 测试 SSH 连接
|
||
# ================================================================
|
||
info "1/9 测试 SSH 连接..."
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new "${REMOTE_USER}@${REMOTE_IP}" "echo SSH_OK" 2>/dev/null | grep -q "SSH_OK"; then
|
||
ok "SSH 连接成功"
|
||
else
|
||
err "SSH 连接失败,请检查。提示:先执行 ssh-copy-id ${REMOTE_USER}@${REMOTE_IP}"
|
||
fi
|
||
|
||
# ================================================================
|
||
# 2. 配置免密码 sudo
|
||
# ================================================================
|
||
info "2/9 配置新电脑免密码 sudo..."
|
||
echo ""
|
||
echo -e "${YELLOW}→ 接下来需要输入新电脑的 sudo 密码(输入时不会显示字符),输完回车即可${NC}"
|
||
echo ""
|
||
|
||
ssh -tt "${REMOTE_USER}@${REMOTE_IP}" "
|
||
CURRENT_USER=$(whoami)
|
||
if [ -f \"/etc/sudoers.d/\${CURRENT_USER}\" ]; then
|
||
echo ' [新电脑] 免密码 sudo 已配置,跳过'
|
||
else
|
||
echo '\${CURRENT_USER} ALL=(ALL) NOPASSWD:***' | sudo tee /etc/sudoers.d/\${CURRENT_USER} > /dev/null
|
||
sudo chmod 440 /etc/sudoers.d/\${CURRENT_USER}
|
||
echo ' [新电脑] ✅ 免密码 sudo 配置完成'
|
||
fi
|
||
" || {
|
||
err "免密码 sudo 配置失败,请手动执行:\n ssh ${REMOTE_USER}@${REMOTE_IP}\n sudo tee /etc/sudoers.d/${REMOTE_USER} <<< \"${REMOTE_USER} ALL=(ALL) NOPASSWD:***\"\n sudo chmod 440 /etc/sudoers.d/${REMOTE_USER}\n然后重新运行脚本"
|
||
}
|
||
|
||
ok "免密码 sudo 配置完成"
|
||
|
||
# ================================================================
|
||
# 3. 检查本机数据库
|
||
# ================================================================
|
||
info "3/9 检查本机 MySQL..."
|
||
if command -v mysql &>/dev/null; then
|
||
if mysql -u"${DB_USER}" -p"${DB_PASS}" -e "USE ${DB_NAME}; SELECT COUNT(*) AS tables FROM information_schema.tables WHERE table_schema='${DB_NAME}';" 2>/dev/null; then
|
||
ok "本机数据库就绪"
|
||
else
|
||
warn "MySQL 能连但数据可能不全,将尝试导出..."
|
||
fi
|
||
else
|
||
warn "本机无 mysql 命令,尝试用 mysqldump 直接导出..."
|
||
fi
|
||
|
||
# ================================================================
|
||
# 4. 导出数据库
|
||
# ================================================================
|
||
SQL_DUMP="/tmp/dy_data_migration_$(date +%Y%m%d_%H%M%S).sql"
|
||
info "4/9 导出本机数据库 → ${SQL_DUMP}..."
|
||
|
||
if mysqldump \
|
||
-h 127.0.0.1 \
|
||
-u "${DB_USER}" \
|
||
-p"${DB_PASS}" \
|
||
--single-transaction \
|
||
--no-tablespaces \
|
||
--routines \
|
||
--triggers \
|
||
--default-character-set=utf8mb4 \
|
||
"${DB_NAME}" > "${SQL_DUMP}" 2>/dev/null; then
|
||
SQL_SIZE=$(du -h "${SQL_DUMP}" | cut -f1)
|
||
ok "数据库导出完成 (${SQL_SIZE})"
|
||
else
|
||
rm -f "${SQL_DUMP}"
|
||
err "数据库导出失败,请检查 MySQL 是否在运行"
|
||
fi
|
||
|
||
# ================================================================
|
||
# 5. 传输 SQL 到新电脑
|
||
# ================================================================
|
||
info "5/9 传输 SQL 到新电脑..."
|
||
scp "${SQL_DUMP}" "${REMOTE_USER}@${REMOTE_IP}:/tmp/dy_data_import.sql"
|
||
ok "SQL 文件传输完成"
|
||
|
||
# ================================================================
|
||
# 6. 新电脑安装 MySQL + 建库 + 导数据
|
||
# ================================================================
|
||
info "6/9 在新电脑上安装 MySQL + 导数据..."
|
||
|
||
ssh "${REMOTE_USER}@${REMOTE_IP}" bash -s << 'REMOTE_SETUP'
|
||
#!/usr/bin/env bash
|
||
DB_USER="dy_app"
|
||
DB_PASS="dy_data_2026"
|
||
DB_NAME="dy_data"
|
||
|
||
echo " [新电脑] 检查 MySQL..."
|
||
if ! command -v mysql &>/dev/null; then
|
||
echo " [新电脑] 安装 MySQL..."
|
||
sudo apt update -qq
|
||
sudo DEBIAN_FRONTEND=noninteractive apt install -y -qq mysql-server
|
||
echo " [新电脑] MySQL 安装完成"
|
||
else
|
||
echo " [新电脑] MySQL 已安装:$(mysql --version)"
|
||
fi
|
||
|
||
echo " [新电脑] 启动 MySQL..."
|
||
sudo systemctl enable mysql 2>/dev/null || true
|
||
sudo systemctl start mysql 2>/dev/null || true
|
||
for i in $(seq 1 30); do
|
||
if sudo mysql -e "SELECT 1" &>/dev/null; then break; fi
|
||
sleep 1
|
||
done
|
||
|
||
echo " [新电脑] 创建数据库和用户..."
|
||
sudo mysql -e "
|
||
CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
|
||
ALTER USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||
FLUSH PRIVILEGES;
|
||
"
|
||
|
||
echo " [新电脑] 导入数据(请耐心等待)..."
|
||
mysql -u"${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" < /tmp/dy_data_import.sql
|
||
|
||
TABLE_COUNT=$(mysql -u"${DB_USER}" -p"${DB_PASS}" -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${DB_NAME}';" 2>/dev/null)
|
||
echo " [新电脑] 数据导入完成,共 ${TABLE_COUNT} 张表"
|
||
|
||
rm -f /tmp/dy_data_import.sql
|
||
REMOTE_SETUP
|
||
|
||
ok "新电脑数据库部署完成"
|
||
|
||
# ================================================================
|
||
# 7. 新电脑部署数据平台
|
||
# ================================================================
|
||
info "7/9 在新电脑上部署数据平台..."
|
||
|
||
# 构建远程脚本,传入正确的目录
|
||
ssh "${REMOTE_USER}@${REMOTE_IP}" bash -s "${REMOTE_DIR}" << 'REMOTE_DEPLOY'
|
||
#!/usr/bin/env bash
|
||
REMOTE_DIR="$1"
|
||
|
||
echo " [新电脑] 检查目录:${REMOTE_DIR}"
|
||
if [ ! -d "${REMOTE_DIR}" ]; then
|
||
echo " [新电脑] 错误:项目目录不存在!"
|
||
echo " [新电脑] 期望路径:${REMOTE_DIR}"
|
||
exit 1
|
||
fi
|
||
|
||
cd "${REMOTE_DIR}"
|
||
echo " [新电脑] 项目目录已找到"
|
||
|
||
# Python3
|
||
if ! command -v python3 &>/dev/null; then
|
||
echo " [新电脑] 安装 Python3..."
|
||
sudo apt install -y -qq python3 python3-pip python3-venv
|
||
fi
|
||
|
||
# 虚拟环境
|
||
if [ ! -d "${REMOTE_DIR}/venv" ]; then
|
||
echo " [新电脑] 创建 Python 虚拟环境..."
|
||
python3 -m venv "${REMOTE_DIR}/venv"
|
||
fi
|
||
|
||
# 依赖
|
||
echo " [新电脑] 安装 Python 依赖..."
|
||
source "${REMOTE_DIR}/venv/bin/activate"
|
||
pip install --quiet --upgrade pip
|
||
pip install --quiet \
|
||
flask==3.1.3 \
|
||
pymysql==1.2.0 \
|
||
gunicorn==26.0.0 \
|
||
gevent==26.5.0 \
|
||
openpyxl==3.1.5 \
|
||
DBUtils==3.1.2 \
|
||
flask-cors==6.0.2 \
|
||
Flask-Login==0.6.3 \
|
||
Flask-Compress==1.24
|
||
deactivate
|
||
|
||
mkdir -p "${REMOTE_DIR}/logs"
|
||
|
||
# 停旧服务
|
||
echo " [新电脑] 停止旧服务..."
|
||
kill "$(lsof -t -i:18888)" 2>/dev/null || true
|
||
sleep 1
|
||
|
||
# 启动
|
||
echo " [新电脑] 启动 Gunicorn(端口 18888)..."
|
||
nohup "${REMOTE_DIR}/venv/bin/gunicorn" \
|
||
-w 4 \
|
||
-b 0.0.0.0:18888 \
|
||
--timeout 120 \
|
||
--access-logfile "${REMOTE_DIR}/logs/access.log" \
|
||
--error-logfile "${REMOTE_DIR}/logs/error.log" \
|
||
app:app > /dev/null 2>&1 &
|
||
|
||
sleep 3
|
||
|
||
if curl -s "http://127.0.0.1:18888/" > /dev/null 2>&1; then
|
||
echo " [新电脑] ✅ 数据平台服务启动成功!"
|
||
else
|
||
echo " [新电脑] ⚠️ 服务可能尚未启动,稍后请手动检查:curl http://127.0.0.1:18888"
|
||
fi
|
||
REMOTE_DEPLOY
|
||
|
||
ok "新电脑数据平台部署完成"
|
||
|
||
# ================================================================
|
||
# 8. 新电脑配置定时任务
|
||
# ================================================================
|
||
info "8/9 在新电脑上配置定时任务..."
|
||
|
||
ssh "${REMOTE_USER}@${REMOTE_IP}" bash -s "${REMOTE_DIR}" << 'REMOTE_CRON'
|
||
#!/usr/bin/env bash
|
||
REMOTE_DIR="$1"
|
||
echo " [新电脑] 配置定时任务..."
|
||
|
||
BACKUP_JOB="30 8 * * * cd ${REMOTE_DIR} && bash backup.sh >> ${REMOTE_DIR}/logs/backup.log 2>&1"
|
||
|
||
EXISTING_CRON="$(crontab -l 2>/dev/null || true)"
|
||
NEW_CRON="${EXISTING_CRON}"
|
||
|
||
if ! echo "${NEW_CRON}" | grep -q "backup.sh"; then
|
||
NEW_CRON="${NEW_CRON}"$'\n'"${BACKUP_JOB}"
|
||
echo " [新电脑] 已添加每日备份定时任务"
|
||
fi
|
||
|
||
echo "${NEW_CRON}" | crontab -
|
||
echo " [新电脑] 定时任务配置完成"
|
||
REMOTE_CRON
|
||
|
||
ok "新电脑定时任务配置完成"
|
||
|
||
# ================================================================
|
||
# 9. 重启小龙虾
|
||
# ================================================================
|
||
info "9/9 重启新电脑小龙虾..."
|
||
|
||
ssh "${REMOTE_USER}@${REMOTE_IP}" << 'REMOTE_OPENCLAW'
|
||
set -euo pipefail
|
||
echo " [新电脑] 重启小龙虾..."
|
||
if command -v openclaw &>/dev/null; then
|
||
openclaw restart 2>/dev/null || echo " [新电脑] openclaw restart 可能需要手动确认"
|
||
echo " [新电脑] 小龙虾已重启"
|
||
else
|
||
echo " [新电脑] 未安装 openclaw 命令,跳过"
|
||
fi
|
||
REMOTE_OPENCLAW
|
||
|
||
ok "迁移流程全部完成!"
|
||
|
||
# ================================================================
|
||
rm -f "${SQL_DUMP}"
|
||
|
||
# ================================================================
|
||
clear
|
||
echo -e "${GREEN}============================================${NC}"
|
||
echo -e "${GREEN} 迁移完成!${NC}"
|
||
echo -e "${GREEN}============================================${NC}"
|
||
echo ""
|
||
echo -e " 数据平台: ${CYAN}http://${REMOTE_IP}:${APP_PORT}${NC}"
|
||
echo -e " 项目路径: ${REMOTE_DIR}"
|
||
echo ""
|
||
echo -e " ${YELLOW}定时任务:${NC}"
|
||
echo " 自动更新: 每天 7:00 / 12:00 / 18:00"
|
||
echo " 每日备份: 每天 8:30"
|
||
echo ""
|
||
echo -e " ${YELLOW}验证:${NC} 浏览器打开 http://${REMOTE_IP}:${APP_PORT}"
|
||
echo ""
|
||
echo -e " ${YELLOW}后期升级:${NC}"
|
||
echo " 旧电脑改完代码后一键打包升级:"
|
||
echo " cd ${PROJECT_DIR}"
|
||
echo " tar czf /tmp/upgrade.tar.gz . --exclude=venv --exclude=.git --exclude=__pycache__ --exclude=logs --exclude=backups"
|
||
echo " scp /tmp/upgrade.tar.gz ${REMOTE_USER}@${REMOTE_IP}:/tmp/"
|
||
echo " ssh ${REMOTE_USER}@${REMOTE_IP} 'cd ${REMOTE_DIR} && tar xzf /tmp/upgrade.tar.gz && kill \$(lsof -t -i:18888) 2>/dev/null; sleep 1; nohup venv/bin/gunicorn -w 4 -b 0.0.0.0:18888 --timeout 120 app:app >/dev/null 2>&1 &'"
|
||
echo ""
|
||
echo -e " ${GREEN}旧电脑(开发)不受影响。${NC}"
|