# 部署文档

## 版本历史
| 版本 | 日期 | 作者 | 变更说明 |
|------|------|------|----------|
| 1.0 | 2024-01-20 | 运维团队 | 初始版本 |
| 1.1 | 2024-09-21 | 运维团队 | 更新部署架构，简化技术栈 |

## 1. 部署概述

### 1.1 部署架构

```mermaid
graph TB
    subgraph "负载均衡层"
        LB[Nginx负载均衡器]
    end
    
    subgraph "应用层"
        WEB1[Web服务器1]
        WEB2[Web服务器2]
        API1[API服务器1]
        API2[API服务器2]
    end
    
    subgraph "数据层"
        DB1[(MySQL主库)]
        DB2[(MySQL从库)]
        REDIS[(Redis集群)]
        MONGO[(MongoDB)]
    end
    
    subgraph "文件存储"
        OSS[对象存储]
    end
    
    LB --> WEB1
    LB --> WEB2
    LB --> API1
    LB --> API2
    
    WEB1 --> DB1
    WEB2 --> DB1
    API1 --> DB1
    API2 --> DB1
    
    DB1 --> DB2
    
    API1 --> REDIS
    API2 --> REDIS
    API1 --> MONGO
    API2 --> MONGO
    
    API1 --> OSS
    API2 --> OSS
```

### 1.2 部署环境

| 环境 | 用途 | 服务器配置 | 域名 |
|------|------|------------|------|
| 开发环境 | 开发测试 | 2核4G | dev.xlxumu.com |
| 测试环境 | 功能测试 | 4核8G | test.xlxumu.com |
| 预生产环境 | 生产前验证 | 8核16G | pre.xlxumu.com |
| 生产环境 | 正式运行 | 16核32G | www.xlxumu.com |

### 1.3 技术栈版本

| 组件 | 版本 | 说明 |
|------|------|------|
| Node.js | 18.x | 后端运行时 |
| MySQL | 8.0 | 主数据库 |
| Redis | 6.x | 缓存数据库 |
| MongoDB | 5.x | 文档数据库 |
| Nginx | 1.20+ | Web服务器 |
| Docker | 20.x | 容器化 |
| Docker Compose | 2.x | 容器编排 |

## 2. 服务器环境准备

### 2.1 系统要求

```bash
# CentOS 7/8 系统配置
# 1. 更新系统
sudo yum update -y

# 2. 安装基础工具
sudo yum install -y wget curl git vim htop

# 3. 配置防火墙
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload

# 4. 设置时区
sudo timedatectl set-timezone Asia/Shanghai

# 5. 配置系统限制
echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nofile 65536" >> /etc/security/limits.conf
```

### 2.2 Docker环境安装

```bash
#!/bin/bash
# install-docker.sh

# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

# 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加Docker仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

# 安装Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.15.1/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

# 配置Docker镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker
```

### 2.3 SSL证书配置

```bash
#!/bin/bash
# setup-ssl.sh

# 安装Certbot
sudo yum install -y epel-release
sudo yum install -y certbot python3-certbot-nginx

# 申请SSL证书
sudo certbot --nginx -d www.xlxumu.com -d api.xlxumu.com

# 设置自动续期
echo "0 12 * * * /usr/bin/certbot renew --quiet" | sudo crontab -
```

## 3. 数据库部署

### 3.1 MySQL部署配置

```yaml
# docker-compose.mysql.yml
version: '3.8'

services:
  mysql-master:
    image: mysql:8.0
    container_name: mysql-master
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: xlxumu_db
      MYSQL_USER: xlxumu_user
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - mysql_master_data:/var/lib/mysql
      - ./mysql/conf/master.cnf:/etc/mysql/conf.d/master.cnf
      - ./mysql/init:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - xlxumu_network

  mysql-slave:
    image: mysql:8.0
    container_name: mysql-slave
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: xlxumu_db
      MYSQL_USER: xlxumu_user
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    ports:
      - "3307:3306"
    volumes:
      - mysql_slave_data:/var/lib/mysql
      - ./mysql/conf/slave.cnf:/etc/mysql/conf.d/slave.cnf
    command: --default-authentication-plugin=mysql_native_password
    depends_on:
      - mysql-master
    networks:
      - xlxumu_network

volumes:
  mysql_master_data:
  mysql_slave_data:

networks:
  xlxumu_network:
    external: true
```

#### MySQL主从配置

```ini
# mysql/conf/master.cnf
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW
binlog-do-db = xlxumu_db
expire_logs_days = 7
max_binlog_size = 100M

# 性能优化
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
sync_binlog = 0
```

```ini
# mysql/conf/slave.cnf
[mysqld]
server-id = 2
relay-log = mysql-relay-bin
log-bin = mysql-bin
binlog-format = ROW
replicate-do-db = xlxumu_db
read_only = 1
```

#### 数据库初始化脚本

```sql
-- mysql/init/01-init-database.sql
CREATE DATABASE IF NOT EXISTS xlxumu_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE xlxumu_db;

-- 创建用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    role ENUM('admin', 'farmer', 'trader') NOT NULL,
    status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_username (username),
    INDEX idx_email (email),
    INDEX idx_role (role)
);

-- 创建养殖场表
CREATE TABLE farms (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    owner_id INT NOT NULL,
    location VARCHAR(200),
    area DECIMAL(10,2),
    description TEXT,
    status ENUM('active', 'inactive') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (owner_id) REFERENCES users(id),
    INDEX idx_owner (owner_id),
    INDEX idx_status (status)
);

-- 创建动物表
CREATE TABLE animals (
    id INT PRIMARY KEY AUTO_INCREMENT,
    farm_id INT NOT NULL,
    tag_number VARCHAR(50) UNIQUE NOT NULL,
    breed VARCHAR(50),
    birth_date DATE,
    gender ENUM('male', 'female'),
    weight DECIMAL(8,2),
    health_status ENUM('healthy', 'sick', 'quarantine', 'deceased') DEFAULT 'healthy',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (farm_id) REFERENCES farms(id),
    INDEX idx_farm (farm_id),
    INDEX idx_tag (tag_number),
    INDEX idx_breed (breed),
    INDEX idx_health_status (health_status)
);

-- 创建交易表
CREATE TABLE transactions (
    id INT PRIMARY KEY AUTO_INCREMENT,
    seller_id INT NOT NULL,
    buyer_id INT,
    animal_id INT NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    status ENUM('pending', 'completed', 'cancelled') DEFAULT 'pending',
    transaction_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (seller_id) REFERENCES users(id),
    FOREIGN KEY (buyer_id) REFERENCES users(id),
    FOREIGN KEY (animal_id) REFERENCES animals(id),
    INDEX idx_seller (seller_id),
    INDEX idx_buyer (buyer_id),
    INDEX idx_animal (animal_id),
    INDEX idx_status (status)
);
```

### 3.2 Redis集群部署

```yaml
# docker-compose.redis.yml
version: '3.8'

services:
  redis-master:
    image: redis:6-alpine
    container_name: redis-master
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - redis_master_data:/data
      - ./redis/redis-master.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    networks:
      - xlxumu_network

  redis-slave:
    image: redis:6-alpine
    container_name: redis-slave
    restart: always
    ports:
      - "6380:6379"
    volumes:
      - redis_slave_data:/data
      - ./redis/redis-slave.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    depends_on:
      - redis-master
    networks:
      - xlxumu_network

  redis-sentinel:
    image: redis:6-alpine
    container_name: redis-sentinel
    restart: always
    ports:
      - "26379:26379"
    volumes:
      - ./redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    depends_on:
      - redis-master
      - redis-slave
    networks:
      - xlxumu_network

volumes:
  redis_master_data:
  redis_slave_data:

networks:
  xlxumu_network:
    external: true
```

#### Redis配置文件

```conf
# redis/redis-master.conf
bind 0.0.0.0
port 6379
requirepass your_redis_password
masterauth your_redis_password

# 持久化配置
save 900 1
save 300 10
save 60 10000

# 内存配置
maxmemory 1gb
maxmemory-policy allkeys-lru

# 日志配置
loglevel notice
logfile /var/log/redis/redis-server.log
```

```conf
# redis/redis-slave.conf
bind 0.0.0.0
port 6379
requirepass your_redis_password
masterauth your_redis_password

# 主从配置
replicaof redis-master 6379
replica-read-only yes

# 持久化配置
save 900 1
save 300 10
save 60 10000

# 内存配置
maxmemory 1gb
maxmemory-policy allkeys-lru
```

### 3.3 MongoDB部署

```yaml
# docker-compose.mongodb.yml
version: '3.8'

services:
  mongodb:
    image: mongo:5
    container_name: mongodb
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
      MONGO_INITDB_DATABASE: xlxumu_logs
    ports:
      - "27017:27017"
    volumes:
      - mongodb_data:/data/db
      - ./mongodb/init:/docker-entrypoint-initdb.d
    networks:
      - xlxumu_network

volumes:
  mongodb_data:

networks:
  xlxumu_network:
    external: true
```

## 4. 应用部署

### 4.1 后端API服务部署

```dockerfile
# backend/Dockerfile
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制package文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制源代码
COPY . .

# 创建非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001

# 更改文件所有者
RUN chown -R nodejs:nodejs /app
USER nodejs

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# 启动应用
CMD ["npm", "start"]
```

```yaml
# docker-compose.backend.yml
version: '3.8'

services:
  backend-api-1:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: backend-api-1
    restart: always
    environment:
      NODE_ENV: production
      PORT: 3000
      DATABASE_URL: mysql://xlxumu_user:${MYSQL_PASSWORD}@mysql-master:3306/xlxumu_db
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis-master:6379
      MONGODB_URL: mongodb://${MONGO_ROOT_USERNAME}:${MONGO_ROOT_PASSWORD}@mongodb:27017/xlxumu_logs
      JWT_SECRET: ${JWT_SECRET}
    ports:
      - "3001:3000"
    volumes:
      - ./logs:/app/logs
    depends_on:
      - mysql-master
      - redis-master
      - mongodb
    networks:
      - xlxumu_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  backend-api-2:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: backend-api-2
    restart: always
    environment:
      NODE_ENV: production
      PORT: 3000
      DATABASE_URL: mysql://xlxumu_user:${MYSQL_PASSWORD}@mysql-master:3306/xlxumu_db
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis-master:6379
      MONGODB_URL: mongodb://${MONGO_ROOT_USERNAME}:${MONGO_ROOT_PASSWORD}@mongodb:27017/xlxumu_logs
      JWT_SECRET: ${JWT_SECRET}
    ports:
      - "3002:3000"
    volumes:
      - ./logs:/app/logs
    depends_on:
      - mysql-master
      - redis-master
      - mongodb
    networks:
      - xlxumu_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

networks:
  xlxumu_network:
    external: true
```

### 4.2 前端应用部署

```dockerfile
# admin-system/Dockerfile
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

FROM nginx:alpine

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制nginx配置
COPY nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
```

```nginx
# admin-system/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    
    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
    
    server {
        listen 80;
        server_name _;
        root /usr/share/nginx/html;
        index index.html;
        
        # 处理SPA路由
        location / {
            try_files $uri $uri/ /index.html;
        }
        
        # 静态资源缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
        
        # 安全头
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
    }
}
```

### 4.3 Nginx负载均衡配置

```nginx
# nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    '$request_time $upstream_response_time';
    
    access_log /var/log/nginx/access.log main;
    
    # 基础配置
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 50M;
    
    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;
    
    # 上游服务器配置
    upstream backend_api {
        least_conn;
        server backend-api-1:3000 max_fails=3 fail_timeout=30s;
        server backend-api-2:3000 max_fails=3 fail_timeout=30s;
        keepalive 32;
    }
    
    upstream admin_web {
        server admin-web-1:80 max_fails=3 fail_timeout=30s;
        server admin-web-2:80 max_fails=3 fail_timeout=30s;
    }
    
    # 限流配置
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    
    # API服务器配置
    server {
        listen 80;
        server_name api.xlxumu.com;
        
        # 重定向到HTTPS
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name api.xlxumu.com;
        
        # SSL配置
        ssl_certificate /etc/letsencrypt/live/api.xlxumu.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/api.xlxumu.com/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        
        # API代理
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            
            proxy_pass http://backend_api;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # 超时配置
            proxy_connect_timeout 5s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
            
            # 缓冲配置
            proxy_buffering on;
            proxy_buffer_size 4k;
            proxy_buffers 8 4k;
        }
        
        # 登录接口特殊限流
        location /api/auth/login {
            limit_req zone=login burst=5 nodelay;
            
            proxy_pass http://backend_api;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
        
        # 健康检查
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
    
    # 管理后台配置
    server {
        listen 80;
        server_name admin.xlxumu.com;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name admin.xlxumu.com;
        
        # SSL配置
        ssl_certificate /etc/letsencrypt/live/admin.xlxumu.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/admin.xlxumu.com/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        
        # 静态文件代理
        location / {
            proxy_pass http://admin_web;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
        
        # 静态资源缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
            proxy_pass http://admin_web;
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
}
```

## 5. 部署脚本

### 5.1 一键部署脚本

```bash
#!/bin/bash
# deploy.sh - 一键部署脚本

set -e

# 配置变量
PROJECT_NAME="xlxumu"
DEPLOY_ENV=${1:-production}
BACKUP_DIR="/backup"
LOG_FILE="/var/log/deploy.log"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# 日志函数
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a $LOG_FILE
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}" | tee -a $LOG_FILE
    exit 1
}

warn() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}" | tee -a $LOG_FILE
}

# 检查环境
check_environment() {
    log "检查部署环境..."
    
    # 检查Docker
    if ! command -v docker &> /dev/null; then
        error "Docker未安装"
    fi
    
    # 检查Docker Compose
    if ! command -v docker-compose &> /dev/null; then
        error "Docker Compose未安装"
    fi
    
    # 检查环境变量文件
    if [ ! -f ".env.${DEPLOY_ENV}" ]; then
        error "环境变量文件 .env.${DEPLOY_ENV} 不存在"
    fi
    
    log "环境检查完成"
}

# 备份数据
backup_data() {
    log "开始数据备份..."
    
    BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
    BACKUP_PATH="${BACKUP_DIR}/${PROJECT_NAME}_${BACKUP_DATE}"
    
    mkdir -p $BACKUP_PATH
    
    # 备份数据库
    if docker ps | grep -q mysql-master; then
        log "备份MySQL数据库..."
        docker exec mysql-master mysqldump -u root -p${MYSQL_ROOT_PASSWORD} --all-databases > ${BACKUP_PATH}/mysql_backup.sql
    fi
    
    # 备份Redis数据
    if docker ps | grep -q redis-master; then
        log "备份Redis数据..."
        docker exec redis-master redis-cli --rdb ${BACKUP_PATH}/redis_backup.rdb
    fi
    
    # 备份应用数据
    if [ -d "./data" ]; then
        log "备份应用数据..."
        cp -r ./data ${BACKUP_PATH}/
    fi
    
    log "数据备份完成: $BACKUP_PATH"
}

# 拉取最新代码
pull_code() {
    log "拉取最新代码..."
    
    git fetch origin
    git checkout main
    git pull origin main
    
    log "代码更新完成"
}

# 构建镜像
build_images() {
    log "构建Docker镜像..."
    
    # 复制环境变量文件
    cp .env.${DEPLOY_ENV} .env
    
    # 构建后端镜像
    log "构建后端API镜像..."
    docker build -t ${PROJECT_NAME}/backend:latest ./backend
    
    # 构建管理后台镜像
    log "构建管理后台镜像..."
    docker build -t ${PROJECT_NAME}/admin:latest ./admin-system
    
    log "镜像构建完成"
}

# 停止旧服务
stop_services() {
    log "停止旧服务..."
    
    if [ -f "docker-compose.yml" ]; then
        docker-compose down
    fi
    
    log "旧服务已停止"
}

# 启动新服务
start_services() {
    log "启动新服务..."
    
    # 创建网络
    docker network create xlxumu_network 2>/dev/null || true
    
    # 启动数据库服务
    log "启动数据库服务..."
    docker-compose -f docker-compose.mysql.yml up -d
    docker-compose -f docker-compose.redis.yml up -d
    docker-compose -f docker-compose.mongodb.yml up -d
    
    # 等待数据库启动
    log "等待数据库启动..."
    sleep 30
    
    # 启动应用服务
    log "启动应用服务..."
    docker-compose -f docker-compose.backend.yml up -d
    docker-compose -f docker-compose.frontend.yml up -d
    
    # 启动Nginx
    log "启动Nginx..."
    docker-compose -f docker-compose.nginx.yml up -d
    
    log "服务启动完成"
}

# 健康检查
health_check() {
    log "执行健康检查..."
    
    # 检查API服务
    for i in {1..30}; do
        if curl -f http://localhost:3001/health &>/dev/null; then
            log "API服务1健康检查通过"
            break
        fi
        if [ $i -eq 30 ]; then
            error "API服务1健康检查失败"
        fi
        sleep 2
    done
    
    for i in {1..30}; do
        if curl -f http://localhost:3002/health &>/dev/null; then
            log "API服务2健康检查通过"
            break
        fi
        if [ $i -eq 30 ]; then
            error "API服务2健康检查失败"
        fi
        sleep 2
    done
    
    # 检查前端服务
    for i in {1..30}; do
        if curl -f http://localhost:80 &>/dev/null; then
            log "前端服务健康检查通过"
            break
        fi
        if [ $i -eq 30 ]; then
            error "前端服务健康检查失败"
        fi
        sleep 2
    done
    
    log "健康检查完成"
}

# 清理旧镜像
cleanup() {
    log "清理旧镜像..."
    
    # 删除未使用的镜像
    docker image prune -f
    
    # 删除未使用的容器
    docker container prune -f
    
    log "清理完成"
}

# 发送通知
send_notification() {
    log "发送部署通知..."
    
    # 这里可以集成钉钉、企业微信等通知
    # curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
    #      -H 'Content-Type: application/json' \
    #      -d '{"msgtype": "text","text": {"content": "部署完成"}}'
    
    log "部署通知已发送"
}

# 主函数
main() {
    log "开始部署 ${PROJECT_NAME} 到 ${DEPLOY_ENV} 环境"
    
    check_environment
    backup_data
    pull_code
    build_images
    stop_services
    start_services
    health_check
    cleanup
    send_notification
    
    log "部署完成！"
}

# 错误处理
trap 'error "部署过程中发生错误"' ERR

# 执行主函数
main "$@"
```

### 5.2 回滚脚本

```bash
#!/bin/bash
# rollback.sh - 回滚脚本

set -e

BACKUP_DIR="/backup"
PROJECT_NAME="xlxumu"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
    exit 1
}

# 列出可用备份
list_backups() {
    log "可用备份列表:"
    ls -la ${BACKUP_DIR}/${PROJECT_NAME}_* 2>/dev/null || error "没有找到备份文件"
}

# 回滚到指定备份
rollback_to_backup() {
    local backup_name=$1
    local backup_path="${BACKUP_DIR}/${backup_name}"
    
    if [ ! -d "$backup_path" ]; then
        error "备份目录不存在: $backup_path"
    fi
    
    log "开始回滚到备份: $backup_name"
    
    # 停止当前服务
    log "停止当前服务..."
    docker-compose down
    
    # 恢复数据库
    if [ -f "${backup_path}/mysql_backup.sql" ]; then
        log "恢复MySQL数据库..."
        docker-compose -f docker-compose.mysql.yml up -d mysql-master
        sleep 30
        docker exec -i mysql-master mysql -u root -p${MYSQL_ROOT_PASSWORD} < ${backup_path}/mysql_backup.sql
    fi
    
    # 恢复Redis数据
    if [ -f "${backup_path}/redis_backup.rdb" ]; then
        log "恢复Redis数据..."
        docker cp ${backup_path}/redis_backup.rdb redis-master:/data/dump.rdb
        docker restart redis-master
    fi
    
    # 恢复应用数据
    if [ -d "${backup_path}/data" ]; then
        log "恢复应用数据..."
        rm -rf ./data
        cp -r ${backup_path}/data ./
    fi
    
    # 重启服务
    log "重启服务..."
    docker-compose up -d
    
    log "回滚完成"
}

# 主函数
main() {
    if [ $# -eq 0 ]; then
        list_backups
        echo "使用方法: $0 <backup_name>"
        exit 1
    fi
    
    rollback_to_backup $1
}

main "$@"
```

### 5.3 监控脚本

```bash
#!/bin/bash
# monitor.sh - 服务监控脚本

# 配置
SERVICES=("mysql-master" "redis-master" "mongodb" "backend-api-1" "backend-api-2" "nginx")
LOG_FILE="/var/log/monitor.log"
ALERT_EMAIL="admin@xlxumu.com"

# 检查服务状态
check_service() {
    local service=$1
    
    if docker ps --format "table {{.Names}}" | grep -q "^${service}$"; then
        echo "✅ $service 运行正常"
        return 0
    else
        echo "❌ $service 服务异常"
        return 1
    fi
}

# 检查服务健康状态
check_health() {
    local service=$1
    
    case $service in
        "backend-api-1")
            curl -f http://localhost:3001/health &>/dev/null
            ;;
        "backend-api-2")
            curl -f http://localhost:3002/health &>/dev/null
            ;;
        "nginx")
            curl -f http://localhost:80/health &>/dev/null
            ;;
        *)
            return 0
            ;;
    esac
}

# 检查系统资源
check_resources() {
    echo "=== 系统资源检查 ==="
    
    # CPU使用率
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | awk -F'%' '{print $1}')
    echo "CPU使用率: ${cpu_usage}%"
    
    # 内存使用率
    mem_usage=$(free | grep Mem | awk '{printf("%.2f"), $3/$2 * 100.0}')
    echo "内存使用率: ${mem_usage}%"
    
    # 磁盘使用率
    disk_usage=$(df -h / | awk 'NR==2 {print $5}')
    echo "磁盘使用率: $disk_usage"
    
    # 检查阈值
    if (( $(echo "$cpu_usage > 80" | bc -l) )); then
        echo "⚠️  CPU使用率过高: ${cpu_usage}%"
    fi
    
    if (( $(echo "$mem_usage > 80" | bc -l) )); then
        echo "⚠️  内存使用率过高: ${mem_usage}%"
    fi
}

# 发送告警
send_alert() {
    local message=$1
    
    # 发送邮件告警
    echo "$message" | mail -s "服务告警" $ALERT_EMAIL
    
    # 记录日志
    echo "[$(date)] ALERT: $message" >> $LOG_FILE
}

# 主监控循环
main() {
    echo "=== 服务监控开始 $(date) ==="
    
    failed_services=()
    
    # 检查所有服务
    for service in "${SERVICES[@]}"; do
        if ! check_service $service; then
            failed_services+=($service)
        elif ! check_health $service; then
            echo "⚠️  $service 健康检查失败"
            failed_services+=($service)
        fi
    done
    
    # 检查系统资源
    check_resources
    
    # 处理失败的服务
    if [ ${#failed_services[@]} -gt 0 ]; then
        alert_message="以下服务异常: ${failed_services[*]}"
        echo "$alert_message"
        send_alert "$alert_message"
    else
        echo "✅ 所有服务运行正常"
    fi
    
    echo "=== 监控完成 $(date) ==="
}

# 如果作为定时任务运行
if [ "$1" = "cron" ]; then
    main >> $LOG_FILE 2>&1
else
    main
fi
```

## 6. 环境配置

### 6.1 环境变量配置

```bash
# .env.production
# 数据库配置
MYSQL_ROOT_PASSWORD=your_mysql_root_password
MYSQL_PASSWORD=your_mysql_password
REDIS_PASSWORD=your_redis_password
MONGO_ROOT_USERNAME=admin
MONGO_ROOT_PASSWORD=your_mongo_password

# 应用配置
NODE_ENV=production
JWT_SECRET=your_jwt_secret_key
API_BASE_URL=https://api.xlxumu.com

# 第三方服务
ALIYUN_ACCESS_KEY_ID=your_aliyun_access_key
ALIYUN_ACCESS_KEY_SECRET=your_aliyun_secret_key
WECHAT_APP_ID=your_wechat_app_id
WECHAT_APP_SECRET=your_wechat_app_secret

# 监控配置
SENTRY_DSN=your_sentry_dsn
LOG_LEVEL=info
```

```bash
# .env.staging
# 测试环境配置
MYSQL_ROOT_PASSWORD=staging_mysql_password
MYSQL_PASSWORD=staging_mysql_password
REDIS_PASSWORD=staging_redis_password
MONGO_ROOT_USERNAME=admin
MONGO_ROOT_PASSWORD=staging_mongo_password

NODE_ENV=staging
JWT_SECRET=staging_jwt_secret
API_BASE_URL=https://test-api.xlxumu.com

LOG_LEVEL=debug
```

### 6.2 Docker Compose主配置

```yaml
# docker-compose.yml
version: '3.8'

services:
  # 数据库服务
  mysql-master:
    extends:
      file: docker-compose.mysql.yml
      service: mysql-master

  redis-master:
    extends:
      file: docker-compose.redis.yml
      service: redis-master

  mongodb:
    extends:
      file: docker-compose.mongodb.yml
      service: mongodb

  # 应用服务
  backend-api-1:
    extends:
      file: docker-compose.backend.yml
      service: backend-api-1

  backend-api-2:
    extends:
      file: docker-compose.backend.yml
      service: backend-api-2

  # 前端服务
  admin-web:
    build:
      context: ./admin-system
      dockerfile: Dockerfile
    container_name: admin-web
    restart: always
    ports:
      - "8080:80"
    networks:
      - xlxumu_network

  # 负载均衡
  nginx:
    image: nginx:alpine
    container_name: nginx-lb
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
      - /etc/letsencrypt:/etc/letsencrypt
    depends_on:
      - backend-api-1
      - backend-api-2
      - admin-web
    networks:
      - xlxumu_network

networks:
  xlxumu_network:
    driver: bridge
```

## 7. 部署流程

### 7.1 首次部署流程

```bash
# 1. 准备服务器环境
./scripts/setup-server.sh

# 2. 克隆项目代码
git clone https://github.com/your-org/xlxumu.git
cd xlxumu

# 3. 配置环境变量
cp .env.example .env.production
vim .env.production

# 4. 执行部署
./scripts/deploy.sh production

# 5. 验证部署
./scripts/health-check.sh
```

### 7.2 更新部署流程

```bash
# 1. 备份当前数据
./scripts/backup.sh

# 2. 拉取最新代码
git pull origin main

# 3. 执行部署
./scripts/deploy.sh production

# 4. 验证部署
./scripts/health-check.sh

# 5. 如有问题，执行回滚
# ./scripts/rollback.sh backup_20240120_143000
```

### 7.3 蓝绿部署流程

```bash
#!/bin/bash
# blue-green-deploy.sh

CURRENT_ENV=$(docker ps --format "table {{.Names}}" | grep backend | head -1 | grep -o "blue\|green" || echo "blue")
TARGET_ENV=$([ "$CURRENT_ENV" = "blue" ] && echo "green" || echo "blue")

echo "当前环境: $CURRENT_ENV"
echo "目标环境: $TARGET_ENV"

# 1. 部署到目标环境
echo "部署到 $TARGET_ENV 环境..."
docker-compose -f docker-compose.${TARGET_ENV}.yml up -d

# 2. 健康检查
echo "执行健康检查..."
sleep 30
if ! curl -f http://localhost:300${TARGET_ENV:0:1}/health; then
    echo "健康检查失败，回滚..."
    docker-compose -f docker-compose.${TARGET_ENV}.yml down
    exit 1
fi

# 3. 切换流量
echo "切换流量到 $TARGET_ENV 环境..."
sed -i "s/backend-${CURRENT_ENV}/backend-${TARGET_ENV}/g" nginx/nginx.conf
docker exec nginx-lb nginx -s reload

# 4. 停止旧环境
echo "停止 $CURRENT_ENV 环境..."
sleep 60  # 等待连接排空
docker-compose -f docker-compose.${CURRENT_ENV}.yml down

echo "蓝绿部署完成"
```

## 8. 监控和日志

### 8.1 日志收集配置

```yaml
# docker-compose.logging.yml
version: '3.8'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.15.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ports:
      - "9200:9200"
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data
    networks:
      - xlxumu_network

  logstash:
    image: docker.elastic.co/logstash/logstash:7.15.0
    container_name: logstash
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logs:/logs
    ports:
      - "5044:5044"
    depends_on:
      - elasticsearch
    networks:
      - xlxumu_network

  kibana:
    image: docker.elastic.co/kibana/kibana:7.15.0
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200
    depends_on:
      - elasticsearch
    networks:
      - xlxumu_network

volumes:
  elasticsearch_data:

networks:
  xlxumu_network:
    external: true
```

### 8.2 Prometheus监控配置

```yaml
# prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alert_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'backend-api'
    static_configs:
      - targets: ['backend-api-1:3000', 'backend-api-2:3000']
    metrics_path: '/metrics'

  - job_name: 'nginx'
    static_configs:
      - targets: ['nginx:9113']

  - job_name: 'mysql'
    static_configs:
      - targets: ['mysql-exporter:9104']

  - job_name: 'redis'
    static_configs:
      - targets: ['redis-exporter:9121']
```

## 9. 安全配置

### 9.1 防火墙配置

```bash
#!/bin/bash
# setup-firewall.sh

# 清空现有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X

# 设置默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许内部网络访问数据库
iptables -A INPUT -s 172.18.0.0/16 -p tcp --dport 3306 -j ACCEPT
iptables -A INPUT -s 172.18.0.0/16 -p tcp --dport 6379 -j ACCEPT
iptables -A INPUT -s 172.18.0.0/16 -p tcp --dport 27017 -j ACCEPT

# 防止DDoS攻击
iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT

# 保存规则
service iptables save
```

### 9.2 SSL/TLS配置

```bash
#!/bin/bash
# setup-ssl.sh

# 生成强DH参数
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

# 配置SSL证书自动续期
cat > /etc/cron.d/certbot << EOF
0 12 * * * /usr/bin/certbot renew --quiet --post-hook "docker exec nginx-lb nginx -s reload"
EOF
```

## 10. 故障排查

### 10.1 常见问题排查

```bash
#!/bin/bash
# troubleshoot.sh

echo "=== 系统故障排查 ==="

# 检查Docker服务
echo "1. 检查Docker服务状态"
systemctl status docker

# 检查容器状态
echo "2. 检查容器状态"
docker ps -a

# 检查容器日志
echo "3. 检查容器日志"
for container in $(docker ps --format "{{.Names}}"); do
    echo "--- $container 日志 ---"
    docker logs --tail 50 $container
done

# 检查网络连接
echo "4. 检查网络连接"
netstat -tlnp | grep -E "(80|443|3000|3306|6379|27017)"

# 检查磁盘空间
echo "5. 检查磁盘空间"
df -h

# 检查内存使用
echo "6. 检查内存使用"
free -h

# 检查CPU使用
echo "7. 检查CPU使用"
top -bn1 | head -20

# 检查数据库连接
echo "8. 检查数据库连接"
docker exec mysql-master mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "SHOW PROCESSLIST;"

# 检查Redis连接
echo "9. 检查Redis连接"
docker exec redis-master redis-cli ping
```

### 10.2 性能优化建议

```bash
# 系统内核参数优化
cat >> /etc/sysctl.conf << EOF
# 网络优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_tw_buckets = 5000

# 文件描述符限制
fs.file-max = 65535
EOF

sysctl -p
```

## 11. 总结

### 11.1 部署检查清单

- [ ] 服务器环境准备完成
- [ ] Docker和Docker Compose安装完成
- [ ] SSL证书配置完成
- [ ] 环境变量配置完成
- [ ] 数据库初始化完成
- [ ] 应用服务部署完成
- [ ] 负载均衡配置完成
- [ ] 监控系统配置完成
- [ ] 日志收集配置完成
- [ ] 备份策略配置完成
- [ ] 安全配置完成
- [ ] 健康检查通过
- [ ] 性能测试通过

### 11.2 运维要点

1. **定期备份**：每日自动备份数据库和重要文件
2. **监控告警**：配置完善的监控和告警机制
3. **日志管理**：集中收集和分析日志
4. **安全更新**：定期更新系统和应用安全补丁
5. **性能优化**：持续监控和优化系统性能
6. **容灾准备**：制定完善的容灾恢复方案

### 11.3 联系方式

- **运维团队**：ops@xlxumu.com
- **紧急联系**：+86 138-0000-0000
- **技术支持**：support@xlxumu.com

---

**文档版本**: v1.0.0  
**最后更新**: 2024年12月  
**维护团队**: 运维团队