#!/bin/bash # 生产环境数据库初始化脚本 # 用于全新的生产环境部署 set -e # 默认配置 CONFIG_FILE="etc/photographyapi-api.yaml" BACKUP_DIR="data/backups" LOG_FILE="init.log" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 日志函数 log() { echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } error() { echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE" } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE" } # 显示横幅 show_banner() { cat << 'EOF' ____ __ __ __ / __ \/ /_ ____ / /_____ ____ __________ _____/ /_ / /_/ / __ \/ __ \/ __/ __ \/ __ \/ ___/ __ \/ ___/ __ \ / ____/ / / / /_/ / /_/ /_/ / /_/ / / / /_/ / /__/ / / / /_/ /_/ /_/\____/\__/\____/\__, /_/ \__,_/\___/_/ /_/ /____/ Production Database Initialization Script ========================================= EOF } # 检查环境 check_environment() { log "检查生产环境..." # 检查是否为 root 用户(生产环境建议) if [[ $EUID -eq 0 ]]; then warning "正在以 root 用户运行" fi # 检查Go环境 if ! command -v go &> /dev/null; then error "Go 未安装" exit 1 fi local go_version=$(go version | cut -d' ' -f3) log "Go 版本: $go_version" # 检查配置文件 if [[ ! -f "$CONFIG_FILE" ]]; then error "配置文件不存在: $CONFIG_FILE" exit 1 fi success "环境检查通过" } # 创建目录结构 create_directories() { log "创建目录结构..." local dirs=( "data" "data/backups" "uploads" "uploads/photos" "uploads/avatars" "uploads/thumbnails" "logs" "bin" ) for dir in "${dirs[@]}"; do if [[ ! -d "$dir" ]]; then mkdir -p "$dir" log "创建目录: $dir" else log "目录已存在: $dir" fi done # 设置权限 chmod 755 data uploads logs bin chmod 700 data/backups # 备份目录更严格的权限 success "目录结构创建完成" } # 检查数据库状态 check_database_status() { log "检查数据库状态..." if [[ -f "data/photography.db" ]]; then warning "数据库文件已存在: data/photography.db" local db_size=$(du -h "data/photography.db" | cut -f1) log "数据库大小: $db_size" echo -n "数据库已存在,是否继续初始化?这将覆盖现有数据 (y/N): " read -r confirm if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then log "用户取消初始化" exit 0 fi # 备份现有数据库 local backup_name="photography_pre_init_$(date +%Y%m%d_%H%M%S).db" cp "data/photography.db" "data/backups/$backup_name" log "现有数据库已备份为: $backup_name" else log "数据库文件不存在,将创建新数据库" fi } # 初始化数据库 initialize_database() { log "初始化数据库..." # 删除现有数据库(如果存在) if [[ -f "data/photography.db" ]]; then rm -f "data/photography.db" log "删除现有数据库文件" fi # 运行迁移 log "执行数据库迁移..." if go run cmd/migrate/main.go -f "$CONFIG_FILE" -c up; then success "数据库迁移完成" else error "数据库迁移失败" exit 1 fi # 验证数据库 if [[ -f "data/photography.db" ]]; then success "数据库创建成功" local db_size=$(du -h "data/photography.db" | cut -f1) log "数据库大小: $db_size" else error "数据库创建失败" exit 1 fi } # 验证数据库结构 verify_database() { log "验证数据库结构..." # 检查迁移状态 log "检查迁移状态:" go run cmd/migrate/main.go -f "$CONFIG_FILE" -c status # 检查表是否存在 local tables=("user" "category" "photo" "schema_migrations") for table in "${tables[@]}"; do if sqlite3 "data/photography.db" ".tables" | grep -q "$table"; then success "表 $table 存在" else error "表 $table 不存在" exit 1 fi done # 检查默认数据 local user_count=$(sqlite3 "data/photography.db" "SELECT COUNT(*) FROM user;") local category_count=$(sqlite3 "data/photography.db" "SELECT COUNT(*) FROM category;") log "默认用户数量: $user_count" log "默认分类数量: $category_count" if [[ "$user_count" -gt 0 && "$category_count" -gt 0 ]]; then success "默认数据初始化成功" else warning "默认数据可能未正确初始化" fi } # 创建初始备份 create_initial_backup() { log "创建初始备份..." local backup_name="photography_initial_$(date +%Y%m%d_%H%M%S).db" local backup_path="data/backups/$backup_name" cp "data/photography.db" "$backup_path" success "初始备份创建成功: $backup_name" # 记录初始备份 echo "$backup_path" > "data/.initial_backup" } # 生成配置摘要 generate_config_summary() { log "生成配置摘要..." cat > "DEPLOYMENT_INFO.md" << EOF # Photography Backend Deployment Information ## 部署时间 - 初始化时间: $(date '+%Y-%m-%d %H:%M:%S %Z') - 操作系统: $(uname -s) $(uname -r) - 主机名: $(hostname) ## 数据库信息 - 数据库类型: SQLite - 数据库文件: data/photography.db - 初始备份: $(cat data/.initial_backup 2>/dev/null || echo "未找到") ## 目录结构 \`\`\` $(tree -d -L 2 2>/dev/null || find . -type d -maxdepth 2 | head -20) \`\`\` ## 迁移状态 \`\`\` $(go run cmd/migrate/main.go -f "$CONFIG_FILE" -c status 2>/dev/null || echo "无法获取迁移状态") \`\`\` ## 下一步操作 1. 启动应用服务: \`make quick\` 2. 检查服务状态: \`make status\` 3. 查看迁移状态: \`make migrate-status\` 4. 创建备份: \`make db-backup\` ## 管理命令 - 查看帮助: \`make help\` - 迁移数据库: \`./scripts/production-migrate.sh migrate\` - 回滚迁移: \`./scripts/production-migrate.sh rollback 1\` - 系统检查: \`./scripts/production-migrate.sh check\` ## 注意事项 - 定期备份数据库 - 监控日志文件 - 更新时先测试迁移 - 保持配置文件安全 EOF success "配置摘要已生成: DEPLOYMENT_INFO.md" } # 设置服务文件(可选) setup_systemd_service() { if [[ ! -f "/etc/systemd/system" ]]; then log "Systemd 不可用,跳过服务配置" return 0 fi log "配置 Systemd 服务..." local service_file="/etc/systemd/system/photography-api.service" local current_dir=$(pwd) local user=$(whoami) cat > "$service_file" << EOF [Unit] Description=Photography API Service After=network.target [Service] Type=simple User=$user WorkingDirectory=$current_dir ExecStart=$current_dir/bin/photography-api -f $current_dir/$CONFIG_FILE Restart=always RestartSec=10 # 环境变量 Environment=GO111MODULE=on Environment=GOPROXY=https://goproxy.cn,direct # 日志 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF systemctl daemon-reload success "Systemd 服务配置完成" log "使用以下命令管理服务:" log " sudo systemctl start photography-api" log " sudo systemctl enable photography-api" log " sudo systemctl status photography-api" } # 最终检查 final_check() { log "执行最终检查..." # 检查应用是否可以构建 if make build; then success "应用构建成功" else error "应用构建失败" exit 1 fi # 检查配置是否正确 if go run cmd/api/main.go -f "$CONFIG_FILE" -test.timeout=1s 2>/dev/null; then success "配置文件验证通过" else warning "配置文件可能有问题,请检查" fi success "最终检查完成" } # 显示完成信息 show_completion() { success "数据库初始化完成!" cat << EOF 🎉 初始化成功! 接下来的步骤: 1. 启动应用: make quick 2. 访问应用: http://localhost:8080 3. 查看状态: make status 4. 查看帮助: make help 管理脚本: - 迁移管理: ./scripts/production-migrate.sh - 查看部署信息: cat DEPLOYMENT_INFO.md 默认管理员账户: - 用户名: admin - 密码: admin123 - 邮箱: admin@example.com ⚠️ 重要提醒: - 请立即修改默认管理员密码 - 定期备份数据库 - 监控应用日志 - 保持系统更新 📋 详细信息请查看: DEPLOYMENT_INFO.md EOF } # 主函数 main() { show_banner log "开始生产环境数据库初始化..." check_environment create_directories check_database_status initialize_database verify_database create_initial_backup generate_config_summary final_check # 询问是否配置 Systemd 服务 echo -n "是否配置 Systemd 服务? (y/N): " read -r setup_service if [[ "$setup_service" == "y" || "$setup_service" == "Y" ]]; then setup_systemd_service fi show_completion log "初始化脚本执行完成" } # 运行主函数 main "$@"