Files
photography/docs/deployment.md
xujiang 72414d0979 feat: 完成后端-管理后台集成及部署配置
🚀 主要功能:
- 完善后端API服务层,实现完整的CRUD操作
- 开发管理后台所有核心页面 (仪表板、照片、分类、标签、用户、设置)
- 完成前后端完全集成,所有API接口正常对接
- 配置完整的CI/CD流水线,支持自动化部署

🎯 后端完善:
- 实现PhotoService, CategoryService, TagService, UserService
- 添加完整的API处理器和路由配置
- 支持Docker容器化部署
- 添加数据库迁移和健康检查

🎨 管理后台完成:
- 仪表板: 实时统计数据展示
- 照片管理: 完整的CRUD操作,支持批量处理
- 分类管理: 树形结构展示和管理
- 标签管理: 颜色标签和统计信息
- 用户管理: 角色权限控制
- 系统设置: 多标签配置界面
- 添加pre-commit代码质量检查

🔧 部署配置:
- Docker Compose完整配置
- 后端CI/CD流水线 (Docker部署)
- 管理后台CI/CD流水线 (静态文件部署)
- 前端CI/CD流水线优化
- 自动化脚本: 部署、备份、监控
- 完整的部署文档和运维指南

 集成完成:
- 所有API接口正常连接
- 认证系统完整集成
- 数据获取和状态管理
- 错误处理和用户反馈
- 响应式设计优化
2025-07-09 16:23:18 +08:00

16 KiB
Raw Blame History

摄影作品集项目部署文档

本文档详细说明了摄影作品集项目的完整部署流程,包括前端、管理后台、后端 API 和数据库的部署配置。

📋 目录

🖥️ 系统要求

硬件要求

  • CPU: 2 核心以上
  • 内存: 4GB 以上 (推荐 8GB)
  • 存储: 20GB 以上 SSD 存储
  • 网络: 稳定的互联网连接

软件要求

  • 操作系统: Ubuntu 20.04 LTS / CentOS 8 / Debian 11
  • Docker: 20.10 或更高版本
  • Docker Compose: 2.0 或更高版本
  • Git: 2.20 或更高版本
  • 域名: 用于生产环境部署

⚙️ 环境配置

1. 安装 Docker 和 Docker Compose

# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker --version
docker-compose --version

2. 克隆项目仓库

git clone <repository-url> photography
cd photography

3. 创建环境变量文件

# 复制环境变量模板
cp .env.example .env

# 编辑环境变量
nano .env

🚀 后端部署

1. 后端 Docker 配置

查看后端 Dockerfile

# backend/Dockerfile
FROM golang:1.21-alpine AS builder

# 设置工作目录
WORKDIR /app

# 安装依赖
RUN apk add --no-cache git ca-certificates tzdata

# 复制 go mod 文件
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码
COPY . .

# 构建应用
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main cmd/server/main.go

# 生产环境镜像
FROM alpine:latest

# 安装必要的包
RUN apk --no-cache add ca-certificates wget

# 创建用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 设置工作目录
WORKDIR /app

# 从构建阶段复制文件
COPY --from=builder /app/main .
COPY --from=builder /app/configs ./configs
COPY --from=builder /app/migrations ./migrations

# 创建必要的目录
RUN mkdir -p uploads logs && chown -R appuser:appgroup /app

# 切换到非 root 用户
USER appuser

# 暴露端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1

# 启动命令
CMD ["./main"]

2. 后端 Docker Compose 服务

# docker-compose.yml - 后端部分
services:
  # PostgreSQL 数据库
  postgres:
    image: postgres:15-alpine
    container_name: photography_postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${DB_NAME:-photography}
      POSTGRES_USER: ${DB_USER:-postgres}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backend/migrations:/docker-entrypoint-initdb.d
    ports:
      - "127.0.0.1:5432:5432"
    networks:
      - photography_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-photography}"]
      interval: 30s
      timeout: 10s
      retries: 5

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: photography_redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    ports:
      - "127.0.0.1:6379:6379"
    networks:
      - photography_network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 5

  # 后端 API 服务
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: photography_backend
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      # 数据库配置
      DB_HOST: postgres
      DB_PORT: 5432
      DB_NAME: ${DB_NAME:-photography}
      DB_USER: ${DB_USER:-postgres}
      DB_PASSWORD: ${DB_PASSWORD}
      
      # Redis 配置
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      
      # JWT 配置
      JWT_SECRET: ${JWT_SECRET}
      JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-24h}
      
      # 服务器配置
      PORT: 8080
      GIN_MODE: release
      
      # 文件存储配置
      STORAGE_TYPE: ${STORAGE_TYPE:-local}
      STORAGE_PATH: /app/uploads
      MAX_UPLOAD_SIZE: ${MAX_UPLOAD_SIZE:-10MB}
      
      # 日志配置
      LOG_LEVEL: ${LOG_LEVEL:-info}
      LOG_FORMAT: json
    volumes:
      - ./backend/uploads:/app/uploads
      - ./backend/logs:/app/logs
      - ./backend/configs:/app/configs
    ports:
      - "127.0.0.1:8080:8080"
    networks:
      - photography_network
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s

volumes:
  postgres_data:
    driver: local
  redis_data:
    driver: local

networks:
  photography_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

3. 启动后端服务

# 构建并启动后端服务
docker-compose up -d postgres redis
docker-compose up -d backend

# 查看日志
docker-compose logs -f backend

# 验证服务状态
curl http://localhost:8080/health

🌐 前端部署

1. 前端构建配置

# 进入前端目录
cd frontend/

# 安装依赖
bun install

# 构建生产版本
bun run build

# 验证构建结果
ls -la out/

2. 前端部署脚本

创建前端部署脚本:

#!/bin/bash
# scripts/deploy-frontend.sh

set -e

echo "🚀 开始部署前端..."

# 配置变量
FRONTEND_DIR="/home/gitea/www/photography"
BACKUP_DIR="/home/gitea/backups/photography-frontend"
BUILD_DIR="./frontend/out"

# 创建备份
echo "📦 创建当前版本备份..."
mkdir -p "$BACKUP_DIR"
if [ -d "$FRONTEND_DIR" ]; then
    tar -czf "$BACKUP_DIR/frontend-$(date +%Y%m%d-%H%M%S).tar.gz" -C "$FRONTEND_DIR" .
fi

# 创建部署目录
echo "📁 准备部署目录..."
mkdir -p "$FRONTEND_DIR"

# 部署新版本
echo "🔄 部署新版本..."
rsync -av --delete "$BUILD_DIR/" "$FRONTEND_DIR/"

# 设置权限
echo "🔐 设置文件权限..."
chown -R gitea:gitea "$FRONTEND_DIR"
chmod -R 755 "$FRONTEND_DIR"

# 清理旧备份 (保留最近5个)
echo "🧹 清理旧备份..."
cd "$BACKUP_DIR"
ls -t frontend-*.tar.gz | tail -n +6 | xargs -r rm

echo "✅ 前端部署完成!"
echo "🌐 访问地址: https://photography.iriver.top"

🛠️ 管理后台部署

1. 管理后台构建配置

# 进入管理后台目录
cd admin/

# 安装依赖
npm install

# 构建生产版本
npm run build

# 验证构建结果
ls -la dist/

2. 管理后台部署脚本

#!/bin/bash
# scripts/deploy-admin.sh

set -e

echo "🚀 开始部署管理后台..."

# 配置变量
ADMIN_DIR="/home/gitea/www/photography-admin"
BACKUP_DIR="/home/gitea/backups/photography-admin"
BUILD_DIR="./admin/dist"

# 创建备份
echo "📦 创建当前版本备份..."
mkdir -p "$BACKUP_DIR"
if [ -d "$ADMIN_DIR" ]; then
    tar -czf "$BACKUP_DIR/admin-$(date +%Y%m%d-%H%M%S).tar.gz" -C "$ADMIN_DIR" .
fi

# 创建部署目录
echo "📁 准备部署目录..."
mkdir -p "$ADMIN_DIR"

# 部署新版本
echo "🔄 部署新版本..."
rsync -av --delete "$BUILD_DIR/" "$ADMIN_DIR/"

# 设置权限
echo "🔐 设置文件权限..."
chown -R gitea:gitea "$ADMIN_DIR"
chmod -R 755 "$ADMIN_DIR"

# 清理旧备份 (保留最近5个)
echo "🧹 清理旧备份..."
cd "$BACKUP_DIR"
ls -t admin-*.tar.gz | tail -n +6 | xargs -r rm

echo "✅ 管理后台部署完成!"
echo "🌐 访问地址: https://admin.photography.iriver.top"

🗄️ 数据库配置

1. 数据库初始化

-- 创建数据库
CREATE DATABASE photography;
CREATE USER photography_user WITH ENCRYPTED PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE photography TO photography_user;

-- 使用数据库
\c photography;

-- 创建必要的扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

-- 设置时区
SET timezone = 'Asia/Shanghai';

2. 数据库备份脚本

#!/bin/bash
# scripts/backup.sh

set -e

# 配置变量
DB_HOST="${DB_HOST:-postgres}"
DB_NAME="${DB_NAME:-photography}"
DB_USER="${DB_USER:-postgres}"
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d-%H%M%S)

echo "🗄️ 开始数据库备份..."

# 创建备份目录
mkdir -p "$BACKUP_DIR"

# 执行备份
pg_dump -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" \
    --no-password --verbose --clean --no-acl --no-owner \
    -f "$BACKUP_DIR/photography-$DATE.sql"

# 压缩备份文件
gzip "$BACKUP_DIR/photography-$DATE.sql"

# 清理旧备份 (保留最近7天)
find "$BACKUP_DIR" -name "photography-*.sql.gz" -mtime +7 -delete

echo "✅ 数据库备份完成: photography-$DATE.sql.gz"

🌐 Web 服务器配置

Caddy 配置文件

# docs/deployment/Caddyfile

# 前端网站
photography.iriver.top {
    # 根目录
    root * /home/gitea/www/photography
    
    # 静态文件服务
    file_server
    
    # SPA 路由支持
    try_files {path} /index.html
    
    # 压缩
    encode gzip
    
    # 缓存配置
    header {
        # 静态资源缓存
        Cache-Control "public, max-age=31536000" {
            path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2
        }
        
        # HTML 文件不缓存
        Cache-Control "no-cache" {
            path *.html
        }
        
        # 安全头
        X-Frame-Options "DENY"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
    
    # 日志
    log {
        output file /var/log/caddy/photography.log
        format json
    }
}

# 管理后台
admin.photography.iriver.top {
    # 根目录
    root * /home/gitea/www/photography-admin
    
    # 静态文件服务
    file_server
    
    # SPA 路由支持
    try_files {path} /index.html
    
    # 压缩
    encode gzip
    
    # 基本认证 (可选)
    # basicauth {
    #     admin $2a$14$encrypted_password_hash
    # }
    
    # 缓存配置
    header {
        Cache-Control "public, max-age=31536000" {
            path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2
        }
        Cache-Control "no-cache" {
            path *.html
        }
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
    }
    
    # 日志
    log {
        output file /var/log/caddy/admin.photography.log
        format json
    }
}

# API 服务
api.photography.iriver.top {
    # 反向代理到后端服务
    reverse_proxy localhost:8080 {
        # 健康检查
        health_uri /health
        health_interval 30s
        health_timeout 10s
        
        # 请求头
        header_up Host {upstream_hostport}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-For {remote_host}
    }
    
    # CORS 处理
    header {
        Access-Control-Allow-Origin "https://photography.iriver.top, https://admin.photography.iriver.top"
        Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
        Access-Control-Allow-Headers "Content-Type, Authorization"
        Access-Control-Max-Age "86400"
    }
    
    # 预检请求处理
    @options method OPTIONS
    respond @options 204
    
    # 上传文件大小限制
    request_body {
        max_size 10MB
    }
    
    # 日志
    log {
        output file /var/log/caddy/api.photography.log
        format json
    }
}

# 全局配置
{
    # 自动 HTTPS
    auto_https on
    
    # Let's Encrypt 邮箱
    email admin@iriver.top
    
    # 日志级别
    log {
        level INFO
    }
}

🔒 SSL 证书配置

Caddy 会自动处理 SSL 证书,但也可以手动配置:

# 手动获取证书 (如果需要)
certbot certonly --webroot -w /var/www/html -d photography.iriver.top -d admin.photography.iriver.top -d api.photography.iriver.top

# 设置自动续期
echo "0 3 * * * certbot renew --quiet && systemctl reload caddy" | crontab -

📊 监控和备份

1. 系统监控脚本

#!/bin/bash
# scripts/monitor.sh

# 检查服务状态
check_service() {
    local service=$1
    local url=$2
    
    echo "检查 $service..."
    if curl -f -s "$url" > /dev/null; then
        echo "✅ $service 正常运行"
    else
        echo "❌ $service 服务异常"
        # 发送告警 (可集成邮件、微信等)
        # send_alert "$service 服务异常"
    fi
}

# 检查磁盘空间
check_disk() {
    local usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
    echo "磁盘使用率: $usage%"
    
    if [ "$usage" -gt 80 ]; then
        echo "⚠️ 磁盘空间不足"
        # send_alert "磁盘空间不足: $usage%"
    fi
}

# 检查内存使用
check_memory() {
    local usage=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
    echo "内存使用率: $usage%"
}

# 执行检查
echo "🔍 开始系统监控..."
check_service "前端" "https://photography.iriver.top"
check_service "管理后台" "https://admin.photography.iriver.top"
check_service "API" "https://api.photography.iriver.top/health"
check_disk
check_memory
echo "✅ 监控检查完成"

2. 自动备份任务

# 设置定时任务
crontab -e

# 添加以下内容:
# 每天凌晨2点备份数据库
0 2 * * * /path/to/photography/scripts/backup.sh

# 每周日凌晨3点重启服务 (可选)
0 3 * * 0 cd /path/to/photography && docker-compose restart

# 每小时检查一次服务状态
0 * * * * /path/to/photography/scripts/monitor.sh

🐛 故障排除

常见问题和解决方案

1. 后端服务无法启动

# 查看日志
docker-compose logs backend

# 检查配置
docker-compose config

# 重新构建
docker-compose build backend --no-cache

2. 数据库连接失败

# 检查数据库状态
docker-compose ps postgres

# 检查数据库日志
docker-compose logs postgres

# 手动连接测试
docker-compose exec postgres psql -U postgres -d photography

3. 前端/管理后台访问异常

# 检查文件权限
ls -la /home/gitea/www/photography/
ls -la /home/gitea/www/photography-admin/

# 检查 Caddy 配置
caddy validate --config /etc/caddy/Caddyfile

# 重新加载 Caddy
systemctl reload caddy

4. SSL 证书问题

# 检查证书状态
curl -I https://photography.iriver.top

# 查看 Caddy 日志
tail -f /var/log/caddy/photography.log

# 手动重新申请证书
systemctl stop caddy
caddy run --config /etc/caddy/Caddyfile

日志文件位置

  • 后端日志: ./backend/logs/
  • Caddy 日志: /var/log/caddy/
  • 数据库日志: docker-compose logs postgres
  • 系统日志: /var/log/syslog

🚀 部署命令速查

# 完整部署流程
git pull origin main
cd photography

# 后端部署
docker-compose build backend
docker-compose up -d

# 前端部署
cd frontend && bun run build && cd ..
./scripts/deploy-frontend.sh

# 管理后台部署
cd admin && npm run build && cd ..
./scripts/deploy-admin.sh

# 重启 Web 服务器
sudo systemctl reload caddy

# 检查服务状态
docker-compose ps
curl https://photography.iriver.top
curl https://admin.photography.iriver.top
curl https://api.photography.iriver.top/health

📞 技术支持

如果在部署过程中遇到问题,请:

  1. 查看相关日志文件
  2. 检查系统资源使用情况
  3. 验证配置文件语法
  4. 联系技术支持团队

📝 文档版本: v1.0
🕒 最后更新: 2024年
👥 维护团队: 摄影作品集项目组