#!/bin/bash # ============================================ # LinkShare Blog - 现代化一键部署脚本 # ============================================ # 用途: 自动化部署流程,支持初始化检查 # 用法: ./scripts/deploy.sh [options] # 示例: ./scripts/deploy.sh # ./scripts/deploy.sh --dev # ./scripts/deploy.sh --init-check set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" cd "$PROJECT_ROOT" # 颜色定义 GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' log_info() { echo -e "${GREEN}[✓]${NC} $1"; } log_step() { echo -e "${BLUE}[→]${NC} $1"; } log_warn() { echo -e "${YELLOW}[!]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } print_banner() { echo "==========================================" echo " LinkShare Blog 一键部署" echo "==========================================" echo "" } show_usage() { echo "用法: $0 [选项]" echo "" echo "选项:" echo " --dev, --development 开发环境部署" echo " --prod, --production 生产环境部署 (默认)" echo " --skip-build 跳过镜像构建" echo " --skip-migrate 跳过数据库迁移" echo " --skip-seed 跳过数据库种子" echo " --init-check 部署后检查初始化状态" echo " --admin-token TOKEN 管理员 token(用于初始化检查)" echo " --no-deps 不启动依赖服务" echo " --backup 部署前自动备份数据库" echo " -h, --help 显示此帮助" echo "" echo "示例:" echo " $0 # 完整生产部署" echo " $0 --dev # 开发环境部署" echo " $0 --skip-build --init-check # 跳过构建并检查初始化" echo "" exit 1 } # 参数解析 ENV="production" SKIP_BUILD=false SKIP_MIGRATE=false SKIP_SEED=false INIT_CHECK=false ADMIN_TOKEN="" INCLUDE_DEPS=true BACKUP_BEFORE=false while [[ $# -gt 0 ]]; do case $1 in --dev|--development) ENV="development" shift ;; --prod|--production) ENV="production" shift ;; --skip-build) SKIP_BUILD=true shift ;; --skip-migrate) SKIP_MIGRATE=true shift ;; --skip-seed) SKIP_SEED=true shift ;; --init-check) INIT_CHECK=true shift ;; --admin-token) ADMIN_TOKEN="$2" shift 2 ;; --no-deps) INCLUDE_DEPS=false shift ;; --backup) BACKUP_BEFORE=true shift ;; -h|--help) show_usage ;; *) log_error "未知选项: $1" show_usage ;; esac done # 工具函数 wait_for_service() { local url=$1 local name=$2 local max_attempts=30 local attempt=1 log_step "等待 $name 就绪..." while [ $attempt -le $max_attempts ]; do if curl -sf "$url" >/dev/null 2>&1; then log_info "$name 已就绪" return 0 fi echo -n "." sleep 2 ((attempt++)) done echo "" log_error "$name 未能在预期时间内就绪" return 1 } check_deployment_success() { log_step "验证部署结果..." # 基本健康检查 if ! curl -sf http://localhost:3001/health >/dev/null; then log_error "API 健康检查失败" return 1 fi log_info "API 健康检查通过" # 检查初始化状态(如果要求) if [ "$INIT_CHECK" = true ] && [ -n "$ADMIN_TOKEN" ]; then local init_response=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ http://localhost:3001/init/status) if [ "$init_response" = "200" ]; then log_info "初始化状态检查通过" else log_warn "初始化状态检查失败 (HTTP $init_response)" fi fi return 0 } # 主部署流程 main() { print_banner log_info "目标环境: $ENV" echo "" # 1. 环境验证 log_step "1/5 验证环境配置..." if [ ! -f ".env" ]; then log_warn ".env 文件不存在,从模板创建..." if [ -f ".env.example" ]; then cp .env.example .env log_warn "请编辑 .env 文件设置必要的配置!" else log_error "未找到 .env.example 模板" exit 1 fi fi if [ -f "scripts/verify-env.sh" ]; then log_info "运行环境验证..." if ! bash scripts/verify-env.sh; then log_error "环境验证失败,请修复上述问题" exit 1 fi fi echo "" # 2. 备份数据库(可选) if [ "$BACKUP_BEFORE" = true ]; then log_step "2/5 备份数据库..." if [ -f "scripts/backup.sh" ]; then bash scripts/backup.sh "pre-deploy-$(date +%Y%m%d_%H%M%S)" || { log_warn "备份失败,但继续部署..." } fi echo "" fi # 3. 构建镜像 if [ "$SKIP_BUILD" = false ]; then log_step "3/5 构建 Docker 镜像..." if ! docker-compose build api; then log_error "镜像构建失败" exit 1 fi log_info "镜像构建成功" echo "" fi # 4. 启动服务 log_step "4/5 启动服务..." if [ "$INCLUDE_DEPS" = false ]; then docker-compose up -d api || { log_error "API 服务启动失败" exit 1 } else docker-compose up -d || { log_error "服务启动失败" exit 1 } fi log_info "服务已启动" echo "" # 5. 等待服务就绪 if ! wait_for_service "http://localhost:3001/health" "API"; then log_error "API 服务未就绪" docker-compose logs api --tail=50 exit 1 fi echo "" # 6. 数据库迁移和 seed if [ "$SKIP_MIGRATE" = false ]; then log_step "6/5 运行数据库迁移..." if docker-compose exec -T api bunx prisma migrate deploy 2>/dev/null; then log_info "数据库迁移完成" else log_warn "迁移失败或无需迁移" fi echo "" fi if [ "$SKIP_SEED" = false ] && [ "$SKIP_MIGRATE" = false ]; then log_step "7/5 运行数据库种子..." if docker-compose exec -T api bunx prisma db seed 2>/dev/null; then log_info "数据库种子完成" else log_warn "种子执行失败或数据已存在" fi echo "" fi # 7. 验证部署 if ! check_deployment_success; then log_error "部署验证失败" echo "" log_error "========== 部署失败 ==========" log_error "请检查以下内容:" log_error " 1. 查看日志: docker-compose logs -f api" log_error " 2. 检查配置: cat .env" log_error " 3. 验证依赖: docker-compose ps" log_error " 4. 手动健康检查: curl http://localhost:3001/health" exit 1 fi # 8. 显示部署信息 echo "" log_step "部署完成!" echo "" echo "==========================================" echo "服务状态:" echo "==========================================" docker-compose ps echo "" echo "==========================================" echo "访问地址:" echo "==========================================" echo "API: http://localhost:3001" echo "健康检查: http://localhost:3001/health" echo "Swagger: http://localhost:3001/api-docs (开发环境)" if [ "$INIT_CHECK" = true ]; then echo "初始化状态: http://localhost:3001/init/status (需要管理员 Token)" fi echo "" echo "==========================================" echo "常用命令:" echo "==========================================" echo "查看日志: docker-compose logs -f api" echo "重启服务: docker-compose restart" echo "停止服务: docker-compose down" echo "备份数据库: ./scripts/backup.sh" echo "健康检查: ./scripts/healthcheck.sh" if [ "$INIT_CHECK" = true ]; then echo "初始化检查: ./scripts/healthcheck.sh --admin-token " fi echo "" if [ -f ".env" ]; then log_warn "请确保 .env 文件中的敏感配置已正确设置!" fi } main