掌握生产环境部署技能,让应用稳定高效运行🚀

学习目标

  • ✅ 掌握Linux服务器环境配置
  • ✅ 学会使用Docker容器化部署
  • ✅ 掌握Nginx反向代理和负载均衡
  • ✅ 学会应用性能监控和优化技巧
  • ✅ 实现自动化部署和持续集成

📖📖 教程概览

项目部署是开发的最后一步,也是最重要的一步。本教程将带你从零开始配置生产环境,实现应用的容器化部署、性能优化和自动化运维。

💻💻 第一步:服务器环境配置

1.1 Linux服务器基础

服务器选择:根据业务需求选择合适的云服务器

  • 小型项目:1核2G配置,月付约30-50元
  • 中型项目:2核4G配置,月付约80-120元
  • 大型项目:4核8G以上,按需配置

1.2 服务器安全配置

# 1. 更新系统
sudo apt update && sudo apt upgrade -y

# 2. 创建新用户(避免使用root)
adduser deployer
usermod -aG sudo deployer

# 3. 配置SSH密钥登录
mkdir ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# 4. 禁用密码登录
sudo vim /etc/ssh/sshd_config
# 修改以下配置:
# PasswordAuthentication no
# PermitRootLogin no

# 5. 配置防火墙
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

1.3 基础软件安装

# 安装Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# 安装PM2进程管理
sudo npm install -g pm2

# 安装Nginx
sudo apt install nginx -y

# 安装MongoDB
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

# 安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

🛠🛠 第二步:Docker容器化部署

2.1 Docker基础概念

  • 镜像(Image):应用的打包模板
  • 容器(Container):镜像的运行实例
  • 仓库(Registry):镜像的存储和分发中心
  • Dockerfile:镜像构建脚本

2.2 创建Dockerfile

# 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 nextjs -u 1001

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

# 暴露端口
EXPOSE 3000

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

2.3 Docker Compose编排

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MONGODB_URI=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis
    restart: unless-stopped

  mongo:
    image: mongo:6
    ports:
      - "27017:27017"
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password
    volumes:
      - mongodb_data:/data/db
    restart: unless-stopped

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - app
    restart: unless-stopped

volumes:
  mongodb_data:
  redis_data:

2.4 构建和运行

# 构建镜像
docker-compose build

# 启动服务
docker-compose up -d

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

# 停止服务
docker-compose down

🌟🌟 第三步:Nginx配置与优化

3.1 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"';
    
    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_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    
    # 上游服务配置
    upstream nodejs_app {
        server app:3000;
        keepalive 32;
    }
    
    # 服务器配置
    server {
        listen 80;
        server_name yourdomain.com;
        
        # 静态文件缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
        
        # API代理
        location /api {
            proxy_pass http://nodejs_app;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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_cache_bypass $http_upgrade;
        }
        
        # 静态文件服务
        location / {
            root /usr/share/nginx/html;
            index index.html;
            try_files $uri $uri/ /index.html;
        }
    }
}

3.2 SSL证书配置

# 使用Certbot获取免费SSL证书
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com

# 自动续期配置
sudo crontab -e
# 添加以下行:
# 0 12 * * * /usr/bin/certbot renew --quiet

🎮🎮 第四步:性能监控与优化

4.1 应用性能监控

// utils/monitoring.js
const prometheus = require('prom-client');

// 收集默认指标
const collectDefaultMetrics = prometheus.collectDefaultMetrics;
collectDefaultMetrics({ timeout: 5000 });

// 自定义指标
const httpRequestDurationMicroseconds = new prometheus.Histogram({
    name: 'http_request_duration_ms',
    help: 'HTTP请求持续时间',
    labelNames: ['method', 'route', 'code'],
    buckets: [0.1, 5, 15, 50, 100, 500]
});

// 请求监控中间件
const monitoringMiddleware = (req, res, next) => {
    const start = Date.now();
    
    res.on('finish', () => {
        const duration = Date.now() - start;
        httpRequestDurationMicroseconds
            .labels(req.method, req.route?.path || req.path, res.statusCode)
            .observe(duration);
    });
    
    next();
};

// 指标暴露端点
app.get('/metrics', async (req, res) => {
    res.set('Content-Type', prometheus.register.contentType);
    res.end(await prometheus.register.metrics());
});

module.exports = { monitoringMiddleware };

4.2 数据库性能优化

// config/database.js
const mongoose = require('mongoose');

// 连接配置
mongoose.connect(process.env.MONGODB_URI, {
    maxPoolSize: 10, // 连接池大小
    serverSelectionTimeoutMS: 5000,
    socketTimeoutMS: 45000,
});

// 索引优化
const userSchema = new mongoose.Schema({
    email: { type: String, unique: true },
    username: { type: String, unique: true },
    createdAt: { type: Date, default: Date.now }
});

// 创建复合索引
userSchema.index({ email: 1, createdAt: -1 });
userSchema.index({ username: 1 });

// 查询优化示例
const getActiveUsers = async () => {
    return await User.find({ isActive: true })
        .select('username email createdAt')
        .sort({ createdAt: -1 })
        .limit(100)
        .lean(); // 返回纯JavaScript对象,提高性能
};

4.3 Redis缓存优化

// utils/cache.js
const redis = require('redis');

class CacheService {
    constructor() {
        this.client = redis.createClient({
            url: process.env.REDIS_URL
        });
        this.client.connect();
        
        this.client.on('error', (err) => {
            console.error('Redis错误:', err);
        });
    }
    
    // 设置缓存
    async set(key, value, expireSeconds = 3600) {
        try {
            await this.client.set(key, JSON.stringify(value), {
                EX: expireSeconds
            });
        } catch (error) {
            console.error('缓存设置失败:', error);
        }
    }
    
    // 获取缓存
    async get(key) {
        try {
            const data = await this.client.get(key);
            return data ? JSON.parse(data) : null;
        } catch (error) {
            console.error('缓存获取失败:', error);
            return null;
        }
    }
    
    // 删除缓存
    async del(key) {
        try {
            await this.client.del(key);
        } catch (error) {
            console.error('缓存删除失败:', error);
        }
    }
    
    // 缓存用户数据示例
    async cacheUserProfile(userId, userData) {
        const key = `user:profile:${userId}`;
        await this.set(key, userData, 1800); // 缓存30分钟
    }
}

module.exports = new CacheService();

🚀🚀 第五步:自动化部署与CI/CD

5.1 GitHub Actions自动化部署

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [18.x]
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
      
    - name: Run tests
      run: npm test
      
    - name: Run linting
      run: npm run lint

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Deploy to server
      uses: appleboy/ssh-action@v0.1.3
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        key: ${{ secrets.SERVER_SSH_KEY }}
        script: |
          cd /opt/app
          git pull origin main
          npm ci --production
          docker-compose down
          docker-compose up -d --build
          echo "部署成功"

5.2 PM2进程管理

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'server.js',
    instances: 'max', // 使用所有CPU核心
    exec_mode: 'cluster', // 集群模式
    env: {
      NODE_ENV: 'development',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    // 监控配置
    watch: false,
    max_memory_restart: '1G',
    // 日志配置
    log_file: './logs/combined.log',
    out_file: './logs/out.log',
    error_file: './logs/error.log',
    time: true,
    // 重启策略
    autorestart: true,
    max_restarts: 10,
    min_uptime: '10s'
  }]
};

// PM2常用命令
// pm2 start ecosystem.config.js --env production
// pm2 monit
// pm2 logs
// pm2 reload all
// pm2 delete all

5.3 健康检查端点

// routes/health.js
const router = require('express').Router();
const mongoose = require('mongoose');
const redis = require('../utils/redis');

router.get('/health', async (req, res) => {
    const checks = {
        server: 'ok',
        database: 'checking',
        redis: 'checking',
        uptime: process.uptime(),
        timestamp: new Date().toISOString()
    };
    
    try {
        // 数据库健康检查
        await mongoose.connection.db.admin().ping();
        checks.database = 'ok';
    } catch (error) {
        checks.database = 'error';
    }
    
    try {
        // Redis健康检查
        await redis.ping();
        checks.redis = 'ok';
    } catch (error) {
        checks.redis = 'error';
    }
    
    const status = checks.database === 'ok' && checks.redis === 'ok' ? 200 : 503;
    
    res.status(status).json({
        success: status === 200,
        data: checks
    });
});

module.exports = router;

📚📚 「后端修炼篇」系列总结

六篇教程学习路径回顾:

  1. Node.js入门 - 开启JavaScript全栈之旅 ✅
  2. 数据库操作 - MySQL与MongoDB实战 ✅
  3. RESTful API设计 - 构建规范接口 ✅
  4. 用户认证与授权 - JWT实战 ✅
  5. 文件上传与云存储 - 多媒体处理 ✅
  6. 项目部署与性能优化 - 从开发到上线 ✅

您已掌握的后端核心技能:

  • ✅ 能够使用Node.js构建完整的后端应用
  • ✅ 掌握数据库设计和优化技巧
  • ✅ 能够设计规范的RESTful API接口
  • ✅ 实现安全的用户认证和权限控制
  • ✅ 处理文件上传和云存储集成
  • ✅ 部署应用到生产环境并进行性能优化

💡💡 生产环境常见问题

Q:如何选择服务器配置?
A:根据预估流量选择,小型项目1核2G起步,预留30%性能余量

Q:Docker和虚拟机有什么区别?
A:Docker更轻量,启动更快,资源占用更少,适合微服务架构

Q:如何监控应用性能?
A:使用PM2内置监控、添加业务指标、集成APM工具(如New Relic)

Q:数据库如何备份?
A:定期自动备份到云存储,重要数据实现异地容灾

🎉🎉 系列完结与进阶学习

恭喜你完成了「后端修炼篇」全部六篇教程!

你已经从一个后端新手成长为能够独立开发、部署和维护生产级应用的开发者。接下来可以继续学习:

  • 微服务架构:Spring Cloud、Dubbo、gRPC
  • 消息队列:RabbitMQ、Kafka、Redis Stream
  • 搜索引擎:Elasticsearch、Solr
  • DevOps:Kubernetes、Jenkins、Terraform
  • 云原生:Service Mesh、Serverless

记住,技术学习永无止境,保持好奇心和实践精神,你一定能成为优秀的高级工程师!

分类: 🔧后端修炼「从零到上线」Web开发新手村  标签: 项目部署DockerNginx性能优化CI/CD后端修炼完结

评论

暂无评论数据

暂无评论数据

目录