Files
jiebanke/docs/部署文档.md

16 KiB
Raw Blame History

结伴客项目部署文档

1. 部署概述

1.1 部署架构

graph TB
    A[用户] --> B[CDN/负载均衡]
    B --> C[Nginx反向代理]
    C --> D[小程序静态资源]
    C --> E[管理后台静态资源]
    C --> F[后端API服务]
    
    F --> G[Redis缓存]
    F --> H[MySQL主库]
    H --> I[MySQL从库]
    
    F --> J[文件存储OSS]
    F --> K[消息队列]
    
    subgraph "服务器集群"
        L[Web服务器1]
        M[Web服务器2]
        N[API服务器1]
        O[API服务器2]
    end
    
    C --> L
    C --> M
    F --> N
    F --> O

1.2 环境规划

环境 用途 服务器配置 域名
开发环境 开发测试 2C4G dev.jiebanke.com
测试环境 功能测试 4C8G test.jiebanke.com
预发布环境 集成测试 8C16G pre.jiebanke.com
生产环境 线上服务 16C32G www.jiebanke.com

2. 服务器环境准备

2.1 系统要求

# CentOS 7/8 或 Ubuntu 18.04+
# 最低配置4C8G推荐8C16G
# 磁盘空间100GB+
# 网络带宽10Mbps+

# 系统更新
sudo yum update -y  # CentOS
sudo apt update && sudo apt upgrade -y  # Ubuntu

2.2 基础软件安装

#!/bin/bash
# install-base.sh - 基础环境安装脚本

# 安装Docker
curl -fsSL https://get.docker.com | bash
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER

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

# 安装Node.js
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs

# 安装PM2
sudo npm install -g pm2

# 安装Nginx
sudo yum install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginx

echo "基础环境安装完成"

2.3 目录结构规划

# 创建项目目录结构
sudo mkdir -p /opt/jiebanke/{
    backend,
    admin-system,
    mini-program,
    website,
    nginx,
    logs,
    data,
    scripts,
    ssl
}

# 设置权限
sudo chown -R $USER:$USER /opt/jiebanke
chmod -R 755 /opt/jiebanke

3. 数据库部署

3.1 MySQL主从部署

# docker-compose-mysql.yml
version: '3.8'
services:
  mysql-master:
    image: mysql:8.0
    container_name: mysql-master
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: jiebanke
      MYSQL_USER: jiebanke
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - ./data/mysql-master:/var/lib/mysql
      - ./config/mysql-master.cnf:/etc/mysql/conf.d/mysql.cnf
    ports:
      - "3306:3306"
    command: --server-id=1 --log-bin=mysql-bin --binlog-format=ROW
    networks:
      - jiebanke-network

  mysql-slave:
    image: mysql:8.0
    container_name: mysql-slave
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: jiebanke
      MYSQL_USER: jiebanke
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - ./data/mysql-slave:/var/lib/mysql
      - ./config/mysql-slave.cnf:/etc/mysql/conf.d/mysql.cnf
    ports:
      - "3307:3306"
    command: --server-id=2 --relay-log=relay-bin --read-only=1
    depends_on:
      - mysql-master
    networks:
      - jiebanke-network

networks:
  jiebanke-network:
    driver: bridge

3.2 Redis集群部署

# docker-compose-redis.yml
version: '3.8'
services:
  redis-master:
    image: redis:7-alpine
    container_name: redis-master
    ports:
      - "6379:6379"
    volumes:
      - ./data/redis-master:/data
      - ./config/redis-master.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    networks:
      - jiebanke-network

  redis-slave:
    image: redis:7-alpine
    container_name: redis-slave
    ports:
      - "6380:6379"
    volumes:
      - ./data/redis-slave:/data
      - ./config/redis-slave.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf --slaveof redis-master 6379
    depends_on:
      - redis-master
    networks:
      - jiebanke-network

4. 后端服务部署

4.1 后端API服务

# backend/Dockerfile
FROM node:18-alpine

WORKDIR /app

# 复制package文件
COPY package*.json ./
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用
RUN npm run build

# 暴露端口
EXPOSE 3000

# 启动命令
CMD ["npm", "start"]

4.2 PM2配置

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'jiebanke-api',
    script: './dist/app.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000,
      DB_HOST: 'localhost',
      DB_PORT: 3306,
      DB_NAME: 'jiebanke',
      REDIS_HOST: 'localhost',
      REDIS_PORT: 6379
    },
    log_file: '/opt/jiebanke/logs/api.log',
    error_file: '/opt/jiebanke/logs/api-error.log',
    out_file: '/opt/jiebanke/logs/api-out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    max_memory_restart: '1G',
    node_args: '--max_old_space_size=1024'
  }]
};

4.3 部署脚本

#!/bin/bash
# deploy-backend.sh - 后端部署脚本

set -e

PROJECT_DIR="/opt/jiebanke"
BACKEND_DIR="$PROJECT_DIR/backend"
BACKUP_DIR="$PROJECT_DIR/backup/$(date +%Y%m%d_%H%M%S)"

echo "开始部署后端服务..."

# 创建备份
if [ -d "$BACKEND_DIR" ]; then
    echo "创建备份..."
    mkdir -p "$BACKUP_DIR"
    cp -r "$BACKEND_DIR" "$BACKUP_DIR/"
fi

# 拉取最新代码
cd "$PROJECT_DIR"
git pull origin main

# 安装依赖
cd "$BACKEND_DIR"
npm ci --only=production

# 构建项目
npm run build

# 数据库迁移
npm run migrate

# 重启服务
pm2 reload ecosystem.config.js --env production

# 健康检查
sleep 10
if curl -f http://localhost:3000/health; then
    echo "后端服务部署成功"
else
    echo "后端服务部署失败,回滚..."
    pm2 stop jiebanke-api
    rm -rf "$BACKEND_DIR"
    cp -r "$BACKUP_DIR/backend" "$PROJECT_DIR/"
    cd "$BACKEND_DIR"
    pm2 start ecosystem.config.js --env production
    exit 1
fi

5. 前端部署

5.1 管理后台部署

#!/bin/bash
# deploy-admin.sh - 管理后台部署脚本

set -e

PROJECT_DIR="/opt/jiebanke"
ADMIN_DIR="$PROJECT_DIR/admin-system"
NGINX_DIR="/var/www/admin"

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

# 构建项目
cd "$ADMIN_DIR"
npm ci
npm run build

# 部署到Nginx目录
sudo rm -rf "$NGINX_DIR"
sudo mkdir -p "$NGINX_DIR"
sudo cp -r dist/* "$NGINX_DIR/"
sudo chown -R nginx:nginx "$NGINX_DIR"

# 重载Nginx配置
sudo nginx -t && sudo nginx -s reload

echo "管理后台部署完成"

5.2 小程序部署

#!/bin/bash
# deploy-miniprogram.sh - 小程序部署脚本

set -e

PROJECT_DIR="/opt/jiebanke"
MINI_DIR="$PROJECT_DIR/mini-program"

echo "开始构建小程序..."

cd "$MINI_DIR"
npm ci
npm run build

echo "小程序构建完成,请使用微信开发者工具上传"
echo "构建产物位置: $MINI_DIR/dist"

6. Nginx配置

6.1 主配置文件

# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /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"';
    
    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_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    
    # 包含站点配置
    include /etc/nginx/conf.d/*.conf;
}

6.2 站点配置

# /etc/nginx/conf.d/jiebanke.conf
# API服务负载均衡
upstream api_backend {
    server 127.0.0.1:3000 weight=1 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 weight=1 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

# 管理后台
server {
    listen 80;
    server_name admin.jiebanke.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name admin.jiebanke.com;
    
    # SSL配置
    ssl_certificate /opt/jiebanke/ssl/admin.crt;
    ssl_certificate_key /opt/jiebanke/ssl/admin.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    root /var/www/admin;
    index index.html;
    
    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # SPA路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # API代理
    location /api/ {
        proxy_pass http://api_backend;
        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 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }
}

# API服务
server {
    listen 80;
    server_name api.jiebanke.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.jiebanke.com;
    
    # SSL配置
    ssl_certificate /opt/jiebanke/ssl/api.crt;
    ssl_certificate_key /opt/jiebanke/ssl/api.key;
    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 / {
        proxy_pass http://api_backend;
        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 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
        
        # CORS配置
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        
        if ($request_method = 'OPTIONS') {
            return 204;
        }
    }
}

7. SSL证书配置

7.1 Let's Encrypt证书

#!/bin/bash
# ssl-setup.sh - SSL证书配置脚本

# 安装certbot
sudo yum install -y certbot python3-certbot-nginx

# 申请证书
sudo certbot --nginx -d admin.jiebanke.com -d api.jiebanke.com

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

7.2 证书更新脚本

#!/bin/bash
# renew-ssl.sh - SSL证书更新脚本

# 更新证书
certbot renew --quiet

# 重载Nginx
if [ $? -eq 0 ]; then
    nginx -s reload
    echo "SSL证书更新成功"
else
    echo "SSL证书更新失败"
    exit 1
fi

8. 监控和日志

8.1 系统监控

# docker-compose-monitoring.yml
version: '3.8'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3001:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'

volumes:
  prometheus_data:
  grafana_data:

8.2 日志管理

# docker-compose-logging.yml
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - xpack.security.enabled=false
    ports:
      - "9200:9200"
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data

  logstash:
    image: docker.elastic.co/logstash/logstash:8.8.0
    container_name: logstash
    ports:
      - "5044:5044"
    volumes:
      - ./config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    depends_on:
      - elasticsearch

  kibana:
    image: docker.elastic.co/kibana/kibana:8.8.0
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      - elasticsearch

volumes:
  elasticsearch_data:

9. 备份和恢复

9.1 数据库备份

#!/bin/bash
# backup-database.sh - 数据库备份脚本

BACKUP_DIR="/opt/jiebanke/backup/database"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="jiebanke"
DB_USER="root"
DB_PASSWORD="your_password"

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

# 备份数据库
mysqldump -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" > "$BACKUP_DIR/jiebanke_$DATE.sql"

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

# 删除7天前的备份
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete

echo "数据库备份完成: jiebanke_$DATE.sql.gz"

9.2 文件备份

#!/bin/bash
# backup-files.sh - 文件备份脚本

BACKUP_DIR="/opt/jiebanke/backup/files"
DATE=$(date +%Y%m%d_%H%M%S)
SOURCE_DIRS=("/opt/jiebanke/backend" "/var/www/admin" "/opt/jiebanke/data")

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

# 备份文件
for dir in "${SOURCE_DIRS[@]}"; do
    if [ -d "$dir" ]; then
        tar -czf "$BACKUP_DIR/$(basename $dir)_$DATE.tar.gz" -C "$(dirname $dir)" "$(basename $dir)"
    fi
done

# 删除30天前的备份
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

echo "文件备份完成"

10. 部署检查清单

10.1 部署前检查

  • 服务器资源充足CPU、内存、磁盘
  • 网络连通性正常
  • 域名DNS解析配置
  • SSL证书准备就绪
  • 数据库连接测试
  • 缓存服务正常
  • 文件存储服务配置

10.2 部署后验证

  • 服务启动状态检查
  • 接口功能测试
  • 前端页面访问测试
  • 数据库连接测试
  • 缓存功能测试
  • 日志输出正常
  • 监控指标正常
  • 备份任务配置

10.3 性能验证

  • 接口响应时间 < 500ms
  • 页面加载时间 < 2s
  • 并发处理能力测试
  • 内存使用率 < 80%
  • CPU使用率 < 70%
  • 磁盘IO正常

11. 故障排查

11.1 常见问题

问题 可能原因 解决方案
服务无法启动 端口占用、配置错误 检查端口、配置文件
数据库连接失败 网络、权限问题 检查网络、用户权限
接口响应慢 数据库查询、网络延迟 优化查询、检查网络
内存不足 内存泄漏、配置不当 检查内存使用、调整配置
SSL证书错误 证书过期、配置错误 更新证书、检查配置

11.2 日志查看命令

# 查看应用日志
pm2 logs jiebanke-api

# 查看Nginx日志
tail -f /var/log/nginx/error.log
tail -f /var/log/nginx/access.log

# 查看系统日志
journalctl -u nginx -f
journalctl -u docker -f

# 查看容器日志
docker logs -f mysql-master
docker logs -f redis-master

12. 总结

本部署文档涵盖了结伴客项目的完整部署流程,包括:

  • 基础环境:服务器配置、软件安装
  • 数据库部署MySQL主从、Redis集群
  • 应用部署后端API、前端应用
  • 负载均衡Nginx配置、SSL证书
  • 监控日志:系统监控、日志管理
  • 备份恢复:数据备份、故障恢复

通过遵循本文档的部署流程,可以确保系统的稳定性、可靠性和可维护性。