346 lines
10 KiB
Bash
Executable File
346 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -e
|
||
|
||
# ===== 斗鱼批量登录 Docker 部署脚本 =====
|
||
|
||
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
cd "$ROOT_DIR"
|
||
|
||
if [ -f "$ROOT_DIR/.env" ]; then
|
||
set -a
|
||
# shellcheck disable=SC1091
|
||
source "$ROOT_DIR/.env"
|
||
set +a
|
||
fi
|
||
|
||
# 使用新的项目标识;可通过环境变量覆盖。
|
||
COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-live-hub-py}"
|
||
export COMPOSE_PROJECT_NAME
|
||
|
||
# 迁移期间优先复用旧项目卷,避免目录改名导致创建空数据库。
|
||
MYSQL_VOLUME_NAME="${MYSQL_VOLUME_NAME:-}"
|
||
MYSQL_VOLUME_EXTERNAL="${MYSQL_VOLUME_EXTERNAL:-false}"
|
||
if [ -z "$MYSQL_VOLUME_NAME" ] && command -v docker >/dev/null 2>&1 \
|
||
&& docker volume inspect douyu_login_py_mysql-data >/dev/null 2>&1; then
|
||
MYSQL_VOLUME_NAME="douyu_login_py_mysql-data"
|
||
MYSQL_VOLUME_EXTERNAL="true"
|
||
fi
|
||
export MYSQL_VOLUME_NAME
|
||
export MYSQL_VOLUME_EXTERNAL
|
||
|
||
APP_PORT="${APP_PORT:-8000}"
|
||
|
||
# ── 工具函数 ──────────────────────────────────────────────
|
||
|
||
detect_compose() {
|
||
if docker compose version &> /dev/null; then
|
||
echo "docker compose"
|
||
elif command -v docker-compose &> /dev/null; then
|
||
echo "docker-compose"
|
||
else
|
||
echo ""
|
||
fi
|
||
}
|
||
|
||
stop_legacy_containers() {
|
||
local name project
|
||
for name in douyu-login-db douyu-login; do
|
||
if ! docker inspect "$name" >/dev/null 2>&1; then
|
||
continue
|
||
fi
|
||
project="$(docker inspect "$name" --format '{{index .Config.Labels "com.docker.compose.project"}}' 2>/dev/null || true)"
|
||
if [ -n "$project" ] && [ "$project" != "$COMPOSE_PROJECT_NAME" ]; then
|
||
echo "停止旧 Compose 项目容器: $name (项目 $project)"
|
||
docker stop "$name" >/dev/null
|
||
fi
|
||
done
|
||
}
|
||
|
||
# ── 子命令 ──────────────────────────────────────────────
|
||
|
||
cmd_deploy() {
|
||
echo ""
|
||
echo "=============================="
|
||
echo " 斗鱼批量登录 - Docker 部署"
|
||
echo "=============================="
|
||
|
||
if ! command -v docker &> /dev/null; then
|
||
echo "❌ 未安装 Docker,请先安装:"
|
||
echo " curl -fsSL https://get.docker.com | sh"
|
||
exit 1
|
||
fi
|
||
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未安装 docker compose,请先安装 Docker Compose"
|
||
exit 1
|
||
fi
|
||
|
||
echo " 使用: $COMPOSE"
|
||
echo ""
|
||
|
||
if [ -z "${YYB_WORKER_KEY:-}" ]; then
|
||
echo "❌ 请先在 .env 中设置 YYB_WORKER_KEY"
|
||
exit 1
|
||
fi
|
||
|
||
if ! $COMPOSE config --quiet; then
|
||
echo "❌ Docker Compose 配置无效,请检查 .env 中的必填变量"
|
||
exit 1
|
||
fi
|
||
|
||
# 创建数据和日志目录
|
||
mkdir -p data logs
|
||
|
||
# 构建并启动
|
||
echo "正在构建应用镜像(首次构建约3-5分钟)..."
|
||
stop_legacy_containers
|
||
# 生产部署不构建含大型开发依赖的 test 镜像;测试镜像仅在本地按需构建。
|
||
$COMPOSE build douyu-login
|
||
|
||
echo ""
|
||
echo "正在启动服务..."
|
||
# 重新创建应用容器,确保生产环境不会沿用旧的 reload 配置。
|
||
$COMPOSE up -d --force-recreate
|
||
|
||
echo ""
|
||
echo "等待服务启动..."
|
||
|
||
# 健康检查
|
||
for i in $(seq 1 15); do
|
||
if curl -s "http://localhost:${APP_PORT}/api/health" | grep -q "ok" 2>/dev/null; then
|
||
echo ""
|
||
echo "=============================="
|
||
echo " ✅ 部署成功!"
|
||
echo "=============================="
|
||
echo " 访问地址: http://localhost:${APP_PORT}"
|
||
echo " 默认账号见环境变量 ADMIN_USERNAME/ADMIN_PASSWORD(未设置则为 admin/admin123)"
|
||
echo ""
|
||
echo " 查看应用日志: ./deploy.sh logs"
|
||
echo " 查看容器输出: ./deploy.sh logs container"
|
||
echo " 停止服务: $COMPOSE down"
|
||
echo " 重启服务: $COMPOSE restart"
|
||
echo " 重置数据: ./deploy.sh reset"
|
||
echo "=============================="
|
||
exit 0
|
||
fi
|
||
echo " 等待中... ($i/15)"
|
||
sleep 2
|
||
done
|
||
|
||
echo ""
|
||
echo "❌ 服务启动超时,查看日志:"
|
||
$COMPOSE logs --tail 30
|
||
exit 1
|
||
}
|
||
|
||
cmd_reset() {
|
||
echo ""
|
||
echo "=============================="
|
||
echo " ⚠️ 重置所有数据"
|
||
echo "=============================="
|
||
echo ""
|
||
echo " 将删除以下内容:"
|
||
echo " • MySQL 数据卷"
|
||
echo " • 应用宝 Worker 任务数据(扫码会话、二维码和订单记录)"
|
||
echo " • 历史Cookie (data/cookies/)"
|
||
echo " • 应用日志 (logs/)"
|
||
echo " • Docker容器和镜像"
|
||
echo ""
|
||
|
||
# 交互确认
|
||
read -rp " 确认删除所有数据?输入 YES 继续: " confirm
|
||
if [ "$confirm" != "YES" ]; then
|
||
echo " 已取消"
|
||
exit 0
|
||
fi
|
||
|
||
COMPOSE=$(detect_compose)
|
||
|
||
# 停止并删除容器
|
||
if [ -n "$COMPOSE" ]; then
|
||
echo " 停止并删除容器..."
|
||
$COMPOSE down --volumes --rmi local 2>/dev/null || $COMPOSE down --volumes 2>/dev/null || true
|
||
fi
|
||
|
||
# 删除数据文件
|
||
echo " 删除旧 SQLite 数据..."
|
||
rm -rf data/web.db data/web.db-shm data/web.db-wal
|
||
|
||
echo " 删除Cookie..."
|
||
rm -rf data/cookies/
|
||
|
||
echo " 删除应用宝 Worker 任务..."
|
||
rm -rf data/yyb-worker-jobs/ data/yyb-worker-dev/
|
||
|
||
echo " 删除日志..."
|
||
rm -rf logs/*.log
|
||
|
||
# 删除其他临时文件
|
||
rm -rf data/accounts.json data/gui_state.json data/app.db 2>/dev/null || true
|
||
|
||
echo ""
|
||
echo "=============================="
|
||
echo " ✅ 数据已重置"
|
||
echo "=============================="
|
||
echo " 运行 ./deploy.sh 重新部署"
|
||
echo "=============================="
|
||
}
|
||
|
||
cmd_logs() {
|
||
local mode="${1:-app}"
|
||
if [ "$mode" = "app" ]; then
|
||
local app_log
|
||
app_log="$ROOT_DIR/logs/app-$(date '+%Y-%m-%d').log"
|
||
mkdir -p "$ROOT_DIR/logs"
|
||
echo "跟踪应用文件日志: ${app_log}(Ctrl+C 退出)"
|
||
exec tail -n "${LOG_TAIL_LINES:-200}" -F "$app_log"
|
||
fi
|
||
if [ "$mode" != "container" ]; then
|
||
echo "用法: ./deploy.sh logs [app|container]"
|
||
exit 1
|
||
fi
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未检测到 docker compose"
|
||
exit 1
|
||
fi
|
||
$COMPOSE logs --tail "${LOG_TAIL_LINES:-200}" -f
|
||
}
|
||
|
||
cmd_migrate_mysql() {
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未检测到 docker compose"
|
||
exit 1
|
||
fi
|
||
if [ ! -f data/web.db ]; then
|
||
echo "❌ 未找到 data/web.db,无法迁移 SQLite 数据"
|
||
exit 1
|
||
fi
|
||
|
||
echo "正在启动 MySQL..."
|
||
stop_legacy_containers
|
||
$COMPOSE up -d mysql
|
||
|
||
echo "等待 MySQL 就绪..."
|
||
for i in $(seq 1 30); do
|
||
if $COMPOSE exec -T mysql sh -c 'mysqladmin ping -h localhost -uroot -p"$MYSQL_ROOT_PASSWORD" --silent' >/dev/null 2>&1; then
|
||
echo "MySQL 已就绪"
|
||
break
|
||
fi
|
||
if [ "$i" = "30" ]; then
|
||
echo "❌ MySQL 启动超时,查看日志:"
|
||
$COMPOSE logs --tail 50 mysql
|
||
exit 1
|
||
fi
|
||
sleep 2
|
||
done
|
||
|
||
echo "正在构建迁移运行镜像..."
|
||
$COMPOSE build douyu-login
|
||
|
||
echo "开始迁移 SQLite 到 MySQL..."
|
||
$COMPOSE run --rm --no-deps douyu-login \
|
||
python scripts/migrate_sqlite_to_mysql.py --source /app/data/web.db
|
||
}
|
||
|
||
cmd_migrate() {
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未检测到 docker compose"
|
||
exit 1
|
||
fi
|
||
|
||
echo "正在启动 MySQL..."
|
||
stop_legacy_containers
|
||
$COMPOSE up -d mysql
|
||
|
||
echo "等待 MySQL 就绪..."
|
||
for i in $(seq 1 30); do
|
||
if $COMPOSE exec -T mysql sh -c 'mysqladmin ping -h localhost -uroot -p"$MYSQL_ROOT_PASSWORD" --silent' >/dev/null 2>&1; then
|
||
break
|
||
fi
|
||
if [ "$i" = "30" ]; then
|
||
echo "❌ MySQL 启动超时,查看日志:"
|
||
$COMPOSE logs --tail 50 mysql
|
||
exit 1
|
||
fi
|
||
sleep 2
|
||
done
|
||
|
||
echo "正在执行数据库迁移..."
|
||
echo "正在构建最新应用镜像..."
|
||
$COMPOSE build douyu-login
|
||
$COMPOSE run --rm --no-deps douyu-login \
|
||
python -c 'from web.backend.database import run_migrations; run_migrations()'
|
||
echo "✅ 数据库迁移完成"
|
||
}
|
||
|
||
cmd_stop() {
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未检测到 docker compose"
|
||
exit 1
|
||
fi
|
||
$COMPOSE down
|
||
echo "✅ 服务已停止"
|
||
}
|
||
|
||
cmd_restart() {
|
||
COMPOSE=$(detect_compose)
|
||
if [ -z "$COMPOSE" ]; then
|
||
echo "❌ 未检测到 docker compose"
|
||
exit 1
|
||
fi
|
||
stop_legacy_containers
|
||
# 重建镜像和应用容器,使新迁移文件与入口迁移逻辑都能生效。
|
||
$COMPOSE up -d --build --force-recreate douyu-login
|
||
echo "✅ 服务已重建并重启(已自动检查数据库迁移)"
|
||
}
|
||
|
||
cmd_dev() {
|
||
exec "$ROOT_DIR/dev.sh"
|
||
}
|
||
|
||
# ── 帮助 ──────────────────────────────────────────────────
|
||
|
||
cmd_help() {
|
||
echo ""
|
||
echo "=============================="
|
||
echo " 斗鱼批量登录 - 部署工具"
|
||
echo "=============================="
|
||
echo ""
|
||
echo " 用法: ./deploy.sh <命令>"
|
||
echo ""
|
||
echo " 命令:"
|
||
echo " (无参数) 构建并部署"
|
||
echo " reset 删除所有数据并重置(需确认)"
|
||
echo " migrate-mysql 先启动 MySQL 并迁移 data/web.db"
|
||
echo " migrate 仅执行数据库结构迁移"
|
||
echo " logs [app|container] 查看应用文件日志(默认)或容器输出"
|
||
echo " stop 停止服务"
|
||
echo " restart 重启服务"
|
||
echo " dev 本地调试启动(后端 reload + 前端热更新)"
|
||
echo " help 显示帮助"
|
||
echo ""
|
||
echo " 访问地址: http://localhost:${APP_PORT}"
|
||
echo " 调试地址: http://localhost:5174"
|
||
echo " 默认账号见环境变量 ADMIN_USERNAME/ADMIN_PASSWORD"
|
||
echo ""
|
||
}
|
||
|
||
# ── 入口 ──────────────────────────────────────────────────
|
||
|
||
case "${1:-}" in
|
||
reset) cmd_reset ;;
|
||
migrate-mysql) cmd_migrate_mysql ;;
|
||
migrate) cmd_migrate ;;
|
||
logs) shift; cmd_logs "${1:-app}" ;;
|
||
stop) cmd_stop ;;
|
||
restart) cmd_restart ;;
|
||
dev) cmd_dev ;;
|
||
help|-h) cmd_help ;;
|
||
*) cmd_deploy ;;
|
||
esac
|