Egg.js 应用部署与上线指南
1. 概述
本指南旨在为开发者提供一份详尽的 Egg.js 应用部署与上线手册。无论您是初次接触服务器部署,还是希望优化现有的部署流程,本文都将为您提供从环境准备到自动化部署的全方位指导。
1.1. 部署架构概览
下图展示了 Egg.js 应用的典型生产环境部署架构:
┌─────────────┐ ┌──────────────────────────────────────────┐
│ 用户 │ │ 服务器 (Linux) │
│ (浏览器) │ │ │
└──────┬──────┘ │ ┌─────────────────────────────────────┐ │
│ │ │ Nginx (反向代理) │ │
│ HTTPS (443) │ │ - SSL 终止 │ │
│ HTTP (80) │ │ - 负载均衡 │ │
└────────────────┼─→│ - 静态资源服务 │ │
│ └──────────────┬──────────────────────┘ │
│ │ proxy_pass │
│ │ 127.0.0.1:7001 │
│ ┌──────────────▼──────────────────────┐ │
│ │ PM2 (进程管理器) │ │
│ │ ┌───────────┐ ┌───────────┐ │ │
│ │ │ Worker 1 │ │ Worker 2 │ ... │ │
│ │ │ (Egg.js) │ │ (Egg.js) │ │ │
│ │ └─────┬─────┘ └─────┬─────┘ │ │
│ └────────┼──────────────┼─────────────┘ │
│ │ │ │
│ ┌────────▼──────────────▼─────────────┐ │
│ │ MongoDB (数据库) │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ CI/CD 流程 (GitHub Actions) │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────────────┐ │
│ │ 代码 │───→│ 测试 │───→│ 构建 │───→│ 自动部署服务器 │ │
│ │ 推送 │ │ │ │ │ │ │ │
│ └────────┘ └────────┘ └────────┘ └────────────────┘ │
└──────────────────────────────────────────────────────────────────┘1.2. 核心组件说明
| 组件 | 作用 | 默认端口 |
|---|---|---|
| Nginx | 反向代理、SSL 终止、负载均衡 | 80, 443 |
| PM2 | Node.js 进程管理、集群模式 | - |
| Egg.js | Web 应用框架 | 7001 |
| MongoDB | 数据存储 | 27017 |
| Certbot | SSL 证书自动管理 | - |
2. 前提条件
在开始之前,请确保您已具备以下条件:
- 一台 Linux 服务器:建议使用 Ubuntu 20.04 或其他主流的 Linux 发行版。
- 一个域名 (可选):如果希望通过域名访问您的应用,您需要注册一个域名。
- 一个 Egg.js 应用:一个已经开发完成、可以进行部署的 Egg.js 项目。
- SSH 客户端:用于连接您的远程服务器。macOS 和 Linux 通常自带,Windows 用户可以使用 PuTTY 或 Windows Terminal。
3. 服务器环境准备
一个稳定、可靠的服务器环境是应用成功上线的基石。本章节将指导您完成 Node.js、MongoDB、Nginx 和 Git 的安装与配置。
在开始之前,建议先更新您的服务器软件包列表:
sudo apt update && sudo apt upgrade -y提示:为了提升软件包下载速度,建议将 Ubuntu 的软件源更换为国内镜像,例如清华大学开源软件镜像站。
3.1. 安装 Node.js
推荐使用 nvm (Node Version Manager) 来安装和管理 Node.js,它可以让您轻松地在不同版本之间切换。
1. 安装 nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash安装完成后,您需要重新加载 shell 配置或重新登录才能使用 nvm 命令。
source ~/.bashrc2. 配置 nvm 镜像源 (可选但推荐):
为了加速 Node.js 的下载,您可以将 nvm 的镜像源指向国内镜像。
export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node
echo 'export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node' >> ~/.bashrc3. 安装并切换 Node.js 版本:
推荐安装最新的 LTS (长期支持) 版本。
nvm install --lts
nvm use --lts
nvm alias default lts验证安装是否成功:
node -v
npm -v4. 配置 npm 镜像源:
为了加速项目依赖的安装,建议将 npm 的镜像源也更换为国内镜像。
npm config set registry https://registry.npm.taobao.org/3.2. 安装 MongoDB
MongoDB 是一个流行的 NoSQL 数据库,常与 Node.js 应用配合使用。
1. 导入 MongoDB GPG 密钥:
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -2. 创建 MongoDB 的源列表文件:
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list3. 更新软件包列表并安装 MongoDB:
sudo apt-get update
sudo apt-get install -y mongodb-org4. 管理 MongoDB 服务:
# 启动 MongoDB 服务
sudo systemctl start mongod
# 查看服务状态
sudo systemctl status mongod
# 设置为开机自启
sudo systemctl enable mongod
# 停止服务
sudo systemctl stop mongod
# 重启服务
sudo systemctl restart mongod您可以使用 mongo 命令进入 MongoDB 的 shell,进行数据库操作。
3.3. 安装 Nginx
Nginx 是一个高性能的 Web 服务器和反向代理服务器,将使用它来将外部请求转发到我们的 Egg.js 应用。
1. 安装 Nginx:
sudo apt install nginx -y2. 管理 Nginx 服务:
# 启动 Nginx
sudo systemctl start nginx
# 查看 Nginx 状态
sudo systemctl status nginx
# 设置为开机自启
sudo systemctl enable nginx
# 重启 Nginx
sudo systemctl restart nginx
# 重新加载配置 (在不中断服务的情况下)
sudo systemctl reload nginx安装完成后,在浏览器中访问您的服务器 IP 地址,如果看到 Nginx 的欢迎页面,则表示安装成功。
3.4. 安装 Git
将使用 Git 从代码仓库拉取我们的应用代码。
sudo apt install git -y
git --version # 验证安装4. 手动部署
手动部署是了解部署流程基础的好方法。它包括将代码部署到服务器、安装依赖并启动应用。
4.1. 获取应用代码
首先,通过 Git 将您的应用代码从代码仓库克隆到服务器。
# 推荐将项目放在 /var/www 目录下
cd /var/www
git clone <你的 Git 仓库地址>
cd <你的项目目录>4.2. 配置生产环境
在安装依赖之前,建议先配置 Egg.js 应用的生产环境参数。
1. 配置生产环境参数
创建或修改 config/config.prod.js:
// config/config.prod.js
'use strict';
exports.keys = 'your-production-secret-keys-change-it';
// 安全配置
exports.security = {
csrf: {
enable: true, // 生产环境必须开启
},
xframe: {
enable: true,
},
};
// 日志配置
exports.logger = {
level: 'INFO', // 生产环境使用 INFO 级别
consoleLevel: 'ERROR', // 控制台只输出 ERROR
dir: '/var/log/egg-app', // 日志存放目录
};
// 集群配置
exports.cluster = {
listen: {
port: 7001,
hostname: '127.0.0.1', // 仅监听本地地址
},
};
// 性能优化
exports.middleware = [
'gzip', // 启用 gzip 压缩
];
exports.gzip = {
threshold: 1024, // 大于 1KB 才压缩
};
// 静态资源缓存
exports.static = {
maxAge: 31536000, // 1年
gzip: true,
};2. 环境变量配置
创建 .env 文件(确保已添加到 .gitignore):
# .env
NODE_ENV=production
EGG_SERVER_ENV=prod
# 数据库配置
MONGODB_URL=mongodb://localhost:27017/your-database
MONGODB_USER=your-username
MONGODB_PASSWORD=your-password
# 应用密钥
APP_KEYS=your-secret-keys
# 其他配置
PORT=70013. 启动脚本配置
检查 package.json 中的启动脚本:
{
"scripts": {
"start": "egg-scripts start --daemon --title=my-egg-app",
"stop": "egg-scripts stop --title=my-egg-app",
"start:prod": "EGG_SERVER_ENV=prod npm start"
}
}重要提示:确保生产环境的敏感配置(如数据库密码、密钥等)不要硬编码在代码中,应通过环境变量注入。
4.3. 安装依赖
进入项目目录,安装生产环境所需的依赖。
npm install --production--production 标志会确保只安装 dependencies 中的依赖,而忽略 devDependencies,这在生产环境中是最佳实践。
4.4. 部署前检查清单
在启动应用前,请逐一检查以下项目:
| 检查项 | 说明 | 状态 |
|---|---|---|
| ✓ 环境变量 | 所有必需的环境变量已配置 | ☐ |
| ✓ 数据库连接 | MongoDB 连接正常 | ☐ |
| ✓ 端口可用 | 7001 端口未被占用 | ☐ |
| ✓ 日志目录 | /var/log/egg-app 目录存在且可写 | ☐ |
| ✓ 静态资源 | public 目录权限正确 | ☐ |
| ✓ 密钥配置 | config.keys 已修改为生产密钥 | ☐ |
| ✓ CSRF 保护 | 已启用 CSRF 防护 | ☐ |
| ✓ 日志级别 | 生产环境日志级别设置为 INFO | ☐ |
验证端口是否被占用:
netstat -tlnp | grep 7001
# 或
lsof -i :70014.5. 使用 PM2 管理应用 (推荐)
直接使用 npm start 启动应用在生产环境中是不可靠的。如果应用崩溃,它不会自动重启,并且您无法充分利用服务器的多核 CPU。因此,强烈推荐使用 PM2,一个功能强大的 Node.js 进程管理器。
1. 安装 PM2:
npm install pm2 -g2. 创建 PM2 配置文件
创建 ecosystem.config.js 文件,以便更好地管理应用配置:
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'my-egg-app',
script: 'npm',
args: 'start',
cwd: '/var/www/my-egg-app',
instances: 'max', // 启动最大 CPU 核心数的实例
exec_mode: 'cluster', // 集群模式
watch: false, // 生产环境不建议开启 watch
max_memory_restart: '500M', // 内存达到 500M 自动重启
env_production: {
NODE_ENV: 'production',
EGG_SERVER_ENV: 'prod',
},
// 日志配置
error_file: '/var/log/egg-app/pm2-error.log',
out_file: '/var/log/egg-app/pm2-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
// 重启策略
exp_backoff_restart_delay: 100, // 指数退避重启延迟
max_restarts: 10, // 最大重启次数
restart_delay: 1000, // 重启延迟 1 秒
autorestart: true, // 自动重启
},
],
};配置参数详解:
| 参数 | 说明 | 推荐值 |
|---|---|---|
instances | 实例数量 | max (CPU 核心数) |
exec_mode | 执行模式 | cluster (集群) |
max_memory_restart | 内存超限重启 | 500M - 1G |
watch | 文件监听 | 生产环境 false |
autorestart | 自动重启 | true |
max_restarts | 最大重启次数 | 10-30 次 |
3. 使用配置文件启动应用:
# 进入项目目录
cd /var/www/<你的项目目录>
# 使用配置文件启动
pm2 start ecosystem.config.js --env production
# 或者使用命令行方式启动
pm2 start npm --name "my-egg-app" -- run start -- -i max4. PM2 常用命令:
# 列出所有由 PM2 管理的应用
pm2 list
# 查看特定应用的详细信息
pm2 show my-egg-app
# 查看特定应用的实时日志
pm2 logs my-egg-app
# 查看最近 100 行日志
pm2 logs my-egg-app --lines 100
# 监控应用的 CPU 和内存使用情况
pm2 monit
# 停止应用
pm2 stop my-egg-app
# 重启应用 (硬重启)
pm2 restart my-egg-app
# 重载应用 (零停机重启)
pm2 reload my-egg-app
# 删除应用
pm2 delete my-egg-app
# 查看进程状态
pm2 status5. 设置开机自启:
为了确保服务器重启后您的应用也能自动运行,您需要配置 PM2 的开机自启脚本。
pm2 startup该命令会生成一行配置命令,您需要复制并执行它。然后,保存当前的 PM2 进程列表:
pm2 save现在,您的 Egg.js 应用已经以稳定、可靠的方式在后台运行了。
在启动成功后,您可以先通过 http://<服务器IP地址>:7001 来测试应用是否正常运行。
注意:请确保您的服务器防火墙(如
ufw)或云服务商的安全组策略已开放了7001端口的访问权限。bash# 如果使用 ufw sudo ufw allow 7001
6. PM2 监控仪表板
PM2 提供了一个在线监控平台 PM2 Plus,可以实时监控应用状态:
# 连接到 PM2 Plus (需要注册账号)
pm2 link <secret_key> <public_key>5. 自动化部署 (使用 GitHub Actions)
手动部署虽然直观,但在频繁更新的开发流程中效率低下且容易出错。自动化部署(CI/CD)可以将代码提交、测试、构建和部署等一系列流程自动化,极大地提升了开发效率和部署的可靠性。本节将介绍如何使用 GitHub Actions 实现自动化部署。
5.1. 工作原理
我们的目标是实现当代码被推送到 GitHub 仓库的 main 分支时,GitHub Actions 会自动触发一个工作流 (workflow),该工作流会:
- 连接到您的远程服务器。
- 进入项目目录,拉取最新的代码。
- 安装最新的依赖。
- 重新启动应用,使变更生效。

5.2. 配置 SSH 免密登录
为了让 GitHub Actions 能够安全地访问您的服务器,推荐使用 SSH 密钥进行认证,而不是密码。
1. 在服务器上生成 SSH 密钥对:
登录到您的服务器,执行以下命令。它会生成一个私钥 (id_rsa) 和一个公钥 (id_rsa.pub)。
# -t 指定密钥类型,-b 指定密钥长度,-C 添加注释
ssh-keygen -t rsa -b 4096 -C "github_actions_deploy_key"当提示输入文件路径和密码时,直接按回车键使用默认设置且不设置密码。
2. 将公钥添加到 GitHub 仓库的 Deploy Keys:
首先,查看并复制公钥的内容:
cat ~/.ssh/id_rsa.pub然后,在您的 GitHub 项目页面,进入 Settings > Deploy Keys,点击 Add deploy key。
- Title: 给这个密钥起一个可识别的名称,例如
My App Server。 - Key: 粘贴您刚刚复制的公钥内容。
- Allow write access: 勾选此项,因为我们的部署脚本需要拉取代码。
3. 验证连接:
在服务器上执行以下命令,测试是否可以成功连接到 GitHub。
ssh -T git@github.com如果看到类似 Hi <your-username>/<your-repo>! You've successfully authenticated... 的消息,说明配置成功。
5.3. 配置 GitHub Secrets
为了安全地在 GitHub Actions 中使用敏感信息(如服务器 IP 地址、用户名和 SSH 私钥),需要将它们存储在 GitHub 的 Secrets 中。
在您的 GitHub 项目页面,进入 Settings > Secrets > Actions,点击 New repository secret 添加以下 secrets:
HOST: 您的服务器 IP 地址或域名。PORT: SSH 连接端口,默认为22。USERNAME: 您用于登录服务器的用户名(例如root或ubuntu)。SSH_PRIVATE_KEY: 私钥的内容。复制您服务器上~/.ssh/id_rsa文件的内容并粘贴到这里。bashcat ~/.ssh/id_rsaAPP_NAME: 您在 PM2 中为应用设置的名称(例如my-egg-app)。PROJECT_PATH: 您在服务器上的项目路径(例如/var/www/my-egg-app)。
如果您的应用需要其他环境变量(例如数据库密码、API 密钥),也应该将它们添加为 Secrets,并在 workflow 文件中传递。
5.4. 编写 GitHub Actions Workflow
在您的项目根目录下,创建 .github/workflows 文件夹,并在其中创建一个 YAML 文件,例如 deploy.yml。
# .github/workflows/deploy.yml
name: Deploy to Server
# 触发条件:当有代码 push 到 main 分支时触发
on:
push:
branches: [main] # 或者 master
jobs:
deploy:
# 运行环境
runs-on: ubuntu-latest
steps:
# 步骤1: 使用 appleboy/ssh-action 连接到服务器并执行部署脚本
- name: Deploy to Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.PORT }}
script: |
# 进入项目目录
cd ${{ secrets.PROJECT_PATH }}
# 从 main 分支拉取最新代码
git pull origin main
# 使用 nvm 加载正确的 Node.js 版本
# 注意:这里的路径可能需要根据您的 nvm 安装情况进行调整
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# 安装生产依赖
npm install --production
# 使用 PM2 重新加载应用,实现零停机更新
pm2 reload ${{ secrets.APP_NAME }}Workflow 文件解析:
name: Workflow 的名称。on.push.branches: 指定了触发此 workflow 的条件,即当代码被推送到main分支时。jobs.deploy.runs-on: 指定了运行此 job 的虚拟机环境。steps: 定义了 job 中要执行的步骤。appleboy/ssh-action@master: 这是一个非常流行的 GitHub Action,用于通过 SSH 在远程服务器上执行命令。with: 用于配置ssh-action。在这里使用了之前设置的 Secrets。script: 这是将在您的服务器上执行的 shell 脚本。cd ${{ secrets.PROJECT_PATH }}: 进入项目目录。git pull origin main: 拉取最新代码。export NVM_DIR...: 加载nvm环境,以确保后续命令使用的是正确的 Node.js 版本。npm install --production: 更新依赖。pm2 reload ${{ secrets.APP_NAME }}: 这是关键的一步。pm2 reload会平滑地重启应用,新的请求会由新的进程处理,而旧的进程会在处理完当前请求后退出,从而实现零停机更新 (Zero-Downtime Reload)。这比pm2 restart更加优雅。
5.5. 触发自动部署
现在,将您的代码(包括新创建的 .github/workflows/deploy.yml 文件)提交并推送到 GitHub 仓库的 main 分支。
git add .
git commit -m "feat: Add GitHub Actions for auto-deployment"
git push origin main推送后,您可以进入 GitHub 项目的 Actions 标签页,查看您的 workflow 是否正在运行。如果一切顺利,几分钟后,您的服务器上的应用就会被更新。
6. 配置 Nginx 反向代理与 HTTPS
现在我们的应用已经通过 PM2 在后台运行,但直接通过 IP 地址和端口号访问是不专业且不安全的。需要配置 Nginx 作为反向代理,将来自公网的 HTTP/HTTPS 请求转发到本地运行的 Egg.js 应用。同时,还将配置 HTTPS 来加密数据传输。
6.1. 配置 Nginx 反向代理
1. 创建 Nginx 配置文件:
为您的应用创建一个新的 Nginx 配置文件。
sudo nano /etc/nginx/sites-available/my-egg-app.conf将以下内容粘贴到文件中,并根据您的实际情况进行修改:
server {
listen 80;
server_name your_domain.com; # 替换为您的域名
location / {
proxy_pass http://127.0.0.1:7001; # 转发到本地的 Egg.js 应用
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;
}
}2. 启用该配置:
通过创建一个从 sites-available 到 sites-enabled 的符号链接来启用这个配置。
sudo ln -s /etc/nginx/sites-available/my-egg-app.conf /etc/nginx/sites-enabled/3. 测试并重启 Nginx:
在应用配置之前,务必测试 Nginx 配置的语法是否正确。
sudo nginx -t如果看到 syntax is ok 和 test is successful 的消息,就可以安全地重启 Nginx 了。
sudo systemctl restart nginx现在,您应该可以通过您的域名(例如 http://your_domain.com)访问您的 Egg.js 应用了。
6.2. 配置 HTTPS (使用 Certbot 和 Let's Encrypt)
HTTPS 可以加密客户端和服务器之间的通信,保护数据不被窃取或篡改。强烈推荐使用 Certbot,它可以自动从 Let's Encrypt 获取免费的 SSL 证书,并自动配置 Nginx。
1. 安装 Certbot:
Certbot 团队提供了一个 PPA (Personal Package Archive) 来分发最新的 Certbot。
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot2. 获取并安装 SSL 证书:
运行以下命令,Certbot 会自动检测您在 Nginx 中配置的 server_name,并为您申请证书。
# --nginx: 指定使用 Nginx 插件
# -d: 指定要为其申请证书的域名
sudo certbot --nginx -d your_domain.com在安装过程中,Certbot 会询问您几个问题:
- 输入您的电子邮件地址:用于接收续订提醒和安全通知。
- 同意服务条款。
- 是否愿意分享您的电子邮件地址。
- 选择是否将所有 HTTP 请求重定向到 HTTPS:强烈推荐选择
Redirect,这样可以确保所有访问者都使用安全连接。
完成后,Certbot 会自动修改您的 Nginx 配置文件 (/etc/nginx/sites-available/my-egg-app.conf),添加 SSL 证书相关的配置,并自动重启 Nginx。
3. 验证自动续订:
Let's Encrypt 颁发的证书有效期为 90 天,但 Certbot 会自动为您处理续订。您可以运行以下命令来模拟续订过程,以确保其正常工作。
sudo certbot renew --dry-run如果命令成功执行,说明自动续订已正确配置。
现在,再次访问您的域名,您会发现浏览器地址栏已经显示了安全锁标志,并且所有流量都通过 HTTPS 进行了加密。
7. Docker 容器化部署
Docker 提供了一种轻量级、可移植的应用部署方式,可以确保应用在任何环境中都能一致运行。
7.1. 创建 Dockerfile
在项目根目录创建 Dockerfile:
# 使用 Node.js 官方镜像
FROM node:16-alpine
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install --production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 7001
# 设置环境变量
ENV NODE_ENV=production \
EGG_SERVER_ENV=prod
# 启动应用
CMD ["npm", "start"]7.2. 创建 docker-compose.yml
使用 Docker Compose 可以更方便地管理多容器应用:
version: '3.8'
services:
app:
build: .
container_name: egg-app
restart: always
ports:
- "7001:7001"
environment:
- NODE_ENV=production
- EGG_SERVER_ENV=prod
- MONGODB_URL=mongodb://mongo:27017/egg-db
depends_on:
- mongo
networks:
- egg-network
mongo:
image: mongo:4.4
container_name: egg-mongo
restart: always
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
networks:
- egg-network
nginx:
image: nginx:alpine
container_name: egg-nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- egg-network
volumes:
mongo-data:
networks:
egg-network:
driver: bridge7.3. 构建和运行
# 构建镜像
docker build -t my-egg-app:latest .
# 使用 Docker Compose 启动
docker-compose up -d
# 查看日志
docker-compose logs -f app
# 停止服务
docker-compose down7.4. Docker 部署优势
| 特性 | 说明 |
|---|---|
| 环境一致性 | 开发、测试、生产环境完全一致 |
| 快速部署 | 几秒钟内启动应用 |
| 易于扩展 | 轻松启动多个实例 |
| 资源隔离 | 容器间相互隔离,互不影响 |
| 版本控制 | 镜像可以打标签,方便回滚 |
8. 监控与告警
生产环境中的应用需要实时监控和告警机制,以确保服务的稳定性和可用性。
8.1. 应用性能监控 (APM)
使用 PM2 监控:
# 启动监控
pm2 monit
# 查看进程详情
pm2 describe my-egg-app集成 Egg-APM:
安装并配置 Egg-APM 插件:
npm install egg-apm --save// config/plugin.js
exports.apm = {
enable: true,
package: 'egg-apm',
};
// config/config.prod.js
exports.apm = {
serverUrl: 'http://your-apm-server:8200',
serviceName: 'my-egg-app',
};8.2. 日志监控
ELK Stack 集成:
将 Egg.js 应用日志发送到 ELK Stack 进行集中管理:
// config/config.prod.js
exports.logger = {
level: 'INFO',
dir: '/var/log/egg-app',
// 自定义日志格式
formatter(meta) {
return `${meta.date} ${meta.level} ${meta.pid} ${meta.message}`;
},
};日志分析工具对比:
| 工具 | 特点 | 适用场景 |
|---|---|---|
| ELK Stack | 功能强大、可扩展性强 | 大型应用、需要复杂查询 |
| Graylog | 易于安装、界面友好 | 中小型应用 |
| Sentry | 错误追踪、性能监控 | 错误监控、性能分析 |
| LogDNA | 云端日志服务 | SaaS 方案 |
8.3. 告警配置
使用 PM2 Plus 告警:
# 安装 pm2-logrotate 插件
pm2 install pm2-logrotate
# 配置日志切割
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30自定义告警脚本:
创建健康检查脚本 health-check.sh:
#!/bin/bash
# 健康检查脚本
APP_URL="http://localhost:7001/health"
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
# 发送 HTTP 请求
response=$(curl -s -o /dev/null -w "%{http_code}" $APP_URL)
if [ $response != "200" ]; then
# 发送告警到 Slack
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"⚠️ Egg.js 应用健康检查失败! HTTP 状态码: $response\"}" \
$WEBHOOK_URL
# 尝试重启应用
pm2 restart my-egg-app
fi添加到 crontab 定时任务:
# 每 5 分钟检查一次
*/5 * * * * /var/www/my-egg-app/scripts/health-check.sh8.4. 性能指标监控
关键性能指标 (KPI):
| 指标 | 说明 | 阈值建议 |
|---|---|---|
| CPU 使用率 | 应用进程 CPU 占用 | < 80% |
| 内存使用 | 应用内存占用 | < 预设限制的 80% |
| 响应时间 | HTTP 请求平均响应时间 | < 200ms |
| 错误率 | HTTP 5xx 错误比例 | < 1% |
| QPS | 每秒查询数 | 根据业务峰值设定 |
| 连接数 | 数据库连接数 | < 连接池上限 |
使用 Node.js 性能钩子:
// app.js
const perfHooks = require('perf_hooks');
// 监控事件循环延迟
const monitor = new perfHooks.Monitor({
sampleInterval: 2000,
});
monitor.enable();
setInterval(() => {
const lag = monitor.eventLoopLag;
if (lag > 100) {
console.warn(`事件循环延迟过高: ${lag}ms`);
}
}, 10000);9. 常见问题与最佳实践
9.1. 常见问题 (FAQ)
Q1: 为什么我的应用在服务器上启动后,通过 IP 地址无法访问?
A: 这通常是由于防火墙或安全组策略导致的。
- 检查服务器防火墙:如果您使用的是
ufw,请确保 Egg.js 应用的端口(默认为 7001)是开放的。bashsudo ufw status sudo ufw allow 7001 - 检查云服务商安全组:如果您使用的是云服务器(如阿里云、腾讯云、AWS),请登录到您的控制台,检查实例的安全组规则,确保入站规则允许了
7001端口的 TCP 访问。
Q2: pm2 start npm --name "my-app" -- run start 和 pm2 start app.js 有什么区别?
A: Egg.js 官方推荐使用 egg-scripts 来启动应用,npm start 通常就是执行 egg-scripts start。egg-scripts 会处理好多核启动、日志切割等问题。直接使用 pm2 start app.js 会绕过 egg-scripts,可能会导致一些非预期的行为。因此,推荐使用 pm2 start npm -- run start 的方式。
Q3: GitHub Actions 部署失败,如何排查问题?
A:
- 查看 Actions 日志:在 GitHub 项目的
Actions标签页,点击失败的 workflow,查看详细的日志输出,通常能定位到具体的错误命令和原因。 - 检查 Secrets:确保您在 GitHub Secrets 中配置的
HOST,USERNAME,SSH_PRIVATE_KEY等变量是正确的。特别是SSH_PRIVATE_KEY,要确保复制的是完整的私钥内容。 - 手动模拟执行:在您的本地机器上,尝试使用
ssh命令和私钥连接到服务器,并手动执行 workflow 中的script部分,看是否能复现问题。
Q4: Certbot 申请证书失败,提示域名解析不正确。
A: Certbot 需要通过访问您的域名来验证您对该域名的所有权。
- 检查 DNS 解析:确保您的域名已经正确地解析到了您的服务器 IP 地址。您可以使用
ping your_domain.com或nslookup your_domain.com来验证。 - 等待 DNS 生效:如果您是刚刚修改的 DNS 解析,可能需要一些时间(几分钟到几小时不等)才能全球生效。
Q5: 应用内存占用过高,如何优化?
A: 内存问题通常由以下原因引起:
- 内存泄漏:使用
node --inspect或 Chrome DevTools 进行内存分析 - 缓存过多:检查应用缓存策略,避免无限增长
- 大文件处理:使用流式处理大文件,避免一次性加载到内存
- 数据库连接池:检查连接池配置是否合理
# 生成堆快照分析内存
kill -USR2 <pid> # 生成 heapdumpQ6: 如何实现零停机部署?
A: 使用 PM2 的 reload 命令:
# 零停机重启
pm2 reload my-egg-app
# 配合 graceful shutdown
// app.js
module.exports = app => {
app.beforeClose(() => {
// 清理工作,如关闭数据库连接
return new Promise(resolve => setTimeout(resolve, 1000));
});
};9.2. 故障排查流程
遇到问题时,按以下流程进行排查:
开始
│
├── 检查进程状态
│ └─ pm2 list / pm2 logs
│
├── 检查端口监听
│ └─ netstat -tlnp | grep 7001
│
├── 检查应用日志
│ └─ /var/log/egg-app/
│
├── 检查系统资源
│ ├─ top / htop (CPU/内存)
│ └─ df -h (磁盘空间)
│
├── 检查网络连接
│ ├─ curl http://localhost:7001
│ └─ ping your_domain.com
│
└── 检查数据库连接
└─ mongo --eval "db.stats()"常见错误代码及解决方案:
| 错误代码 | 可能原因 | 解决方案 |
|---|---|---|
| ECONNREFUSED | 服务未启动或端口被占用 | 检查服务状态、端口占用 |
| ETIMEDOUT | 网络超时 | 检查网络、防火墙设置 |
| ENOMEM | 内存不足 | 增加服务器内存或优化应用 |
| EMFILE | 打开文件过多 | 增加 ulimit -n 限制 |
| EADDRINUSE | 端口已被占用 | 停止占用端口的进程 |
| 502 Bad Gateway | 后端服务未响应 | 检查 Egg.js 应用状态 |
| 504 Gateway Timeout | 后端响应超时 | 优化接口性能、增加超时时间 |
9.3. 最佳实践
1. 环境变量管理
- 不要硬编码配置:切勿将数据库密码、API 密钥等敏感信息硬编码在代码中。
- 使用
.env文件:在开发环境中使用.env文件来管理环境变量,并将其添加到.gitignore中。 - 生产环境使用 Secrets:在生产环境中,应该通过系统的环境变量或 CI/CD 工具的 Secrets 功能来注入这些变量。对于 PM2,您可以在启动时通过
--env参数或生态系统文件来加载环境变量。
环境变量管理方案对比:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
.env 文件 | 简单易用 | 需手动管理 | 开发环境 |
| PM2 ecosystem | 集中管理 | 仅限 PM2 | PM2 部署 |
| Kubernetes Secrets | 安全、原生 | 配置复杂 | K8s 环境 |
| Vault | 安全性高 | 架构复杂 | 大型企业 |
2. 日志管理
- 使用 PM2 的日志功能:PM2 提供了强大的日志管理功能,包括日志切割、按日期归档等。
- 结构化日志:在您的 Egg.js 应用中,考虑输出结构化(例如 JSON 格式)的日志,这会使日志的查询和分析变得更加容易。
- 集中式日志:对于大型应用,可以考虑将日志发送到集中的日志管理平台(如 ELK Stack, Graylog, Sentry 等)。
日志配置示例:
// config/config.prod.js
exports.logger = {
level: 'INFO',
dir: '/var/log/egg-app',
bufferLogs: true, // 启用日志缓冲
outputJSON: true, // JSON 格式输出
consoleLevel: 'NONE', // 生产环境不输出到控制台
};
// 自定义日志分类
exports.customLogger = {
accessLogger: {
file: '/var/log/egg-app/access.log',
formatter: meta => `${meta.timestamp} ${meta.method} ${meta.url} ${meta.status}`,
},
};3. 安全加固
- 定期更新:定期更新您的服务器操作系统、Node.js、Nginx 以及所有 npm 依赖,以修复已知的安全漏洞。
- 最小权限原则:为您的应用和数据库使用专用的、权限受限的用户,而不是
root用户。 - 使用 Helmet:Egg.js 默认集成并开启了
egg-security插件,它底层使用了 Helmet 来帮助设置一些重要的 HTTP 头,以防止常见的 Web 攻击(如 XSS, CSRF 等)。确保您没有禁用它。
安全配置清单:
// config/config.prod.js
exports.security = {
csrf: {
enable: true,
ignoreJSON: false,
},
xframe: {
enable: true,
value: 'SAMEORIGIN',
},
hsts: {
enable: true,
maxAge: 31536000,
},
xssProtection: {
enable: true,
},
csp: {
enable: true,
policy: {
'default-src': ["'self'"],
'script-src': ["'self'"],
'style-src': ["'self'"],
},
},
};
// 限流配置
exports.ratelimit = {
enable: true,
max: 100, // 每分钟最大请求数
duration: 60000, // 时间窗口(毫秒)
};安全检查命令:
# 检查 npm 依赖漏洞
npm audit
# 自动修复
npm audit fix
# 检查服务器开放端口
netstat -tlnp
# 检查防火墙状态
sudo ufw status verbose4. 性能优化
- 开启集群模式:通过
pm2 start ... -i max来开启集群模式,充分利用服务器的多核 CPU 资源。 - 使用 PM2 监控:使用
pm2 monit来实时监控应用的 CPU 和内存使用情况。 - 集成应用性能监控 (APM):考虑集成如 Egg-APM 或商业化的 APM 工具(如 New Relic, Datadog)来深入了解应用的性能瓶颈。
性能优化建议:
| 优化项 | 方法 | 预期提升 |
|---|---|---|
| 数据库查询 | 添加索引、优化查询语句 | 50-80% |
| 缓存策略 | Redis 缓存热点数据 | 30-50% |
| 压缩传输 | 启用 gzip/brotli | 60-70% |
| 静态资源 CDN | 使用 CDN 分发 | 40-60% |
| 连接池 | 合理配置数据库连接池 | 20-40% |
| 异步处理 | 非核心操作异步化 | 30-50% |
连接池配置:
// config/config.prod.js
exports.mongoose = {
url: process.env.MONGODB_URL,
options: {
poolSize: 10, // 连接池大小
bufferMaxEntries: 0,
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
},
};
// Redis 连接池
exports.redis = {
client: {
port: 6379,
host: '127.0.0.1',
password: process.env.REDIS_PASSWORD,
db: 0,
pool: {
max: 10, // 最大连接数
min: 2, // 最小连接数
},
},
};5. 数据库备份与恢复
- 定期备份:为您的 MongoDB 数据库设置定期的自动备份策略。您可以使用
mongodump结合cron来实现。 - 异地备份:将备份文件存储在与应用服务器不同的物理位置,以防服务器发生灾难性故障。
备份脚本示例:
#!/bin/bash
# backup-mongodb.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/mongodb"
DB_NAME="egg-db"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 执行备份
mongodump --db $DB_NAME --out $BACKUP_DIR/$DATE
# 压缩备份文件
tar -czf $BACKUP_DIR/$DATE.tar.gz -C $BACKUP_DIR/$DATE .
# 删除临时目录
rm -rf $BACKUP_DIR/$DATE
# 删除 7 天前的备份
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
# 上传到云存储 (示例使用 AWS S3)
aws s3 cp $BACKUP_DIR/$DATE.tar.gz s3://your-bucket/mongodb-backups/配置定时任务:
# 编辑 crontab
crontab -e
# 每天凌晨 2 点执行备份
0 2 * * * /var/www/scripts/backup-mongodb.sh >> /var/log/mongodb-backup.log 2>&16. 高可用架构
对于生产环境,建议采用高可用架构:
┌─────────────┐
│ 负载均衡 │
│ (Nginx/ALB) │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
┌─────▼─────┐ ┌───▼────┐ ┌────▼─────┐
│ Server 1 │ │Server 2│ │ Server 3 │
│ (Egg.js) │ │(Egg.js)│ │ (Egg.js) │
└─────┬─────┘ └───┬────┘ └────┬─────┘
│ │ │
└────────────┼────────────┘
│
┌──────▼──────┐
│ MongoDB │
│ (主从复制) │
└─────────────┘高可用配置要点:
- 负载均衡:使用 Nginx 或云服务商的负载均衡器
- 多实例部署:至少部署 2 个以上应用实例
- 数据库主从:MongoDB 配置副本集
- 健康检查:定期检查服务可用性
- 自动故障转移:配置故障自动切换机制
10. 部署流程总结
10.1. 完整部署流程
准备阶段
│
├── 1. 准备服务器和域名
├── 2. 安装基础环境 (Node.js, MongoDB, Nginx, Git)
└── 3. 配置防火墙和安全组
│
部署阶段
│
├── 4. 克隆代码到服务器
├── 5. 配置生产环境参数
├── 6. 安装依赖
├── 7. 使用 PM2 启动应用
└── 8. 配置 Nginx 反向代理
│
优化阶段
│
├── 9. 配置 HTTPS 证书
├── 10. 配置自动化部署
├── 11. 配置监控和告警
└── 12. 配置定期备份
│
维护阶段
│
├── 定期更新依赖
├── 监控应用性能
├── 检查安全漏洞
└── 优化和扩容10.2. 快速检查清单
部署前务必完成以下检查:
代码层面:
- 生产环境配置已完成 (
config/config.prod.js) - 敏感信息已提取到环境变量
- 数据库连接配置正确
- CSRF 和安全配置已启用
- 日志级别设置为 INFO
服务器层面:
- Node.js 版本符合要求 (推荐 LTS)
- MongoDB 服务正常运行
- Nginx 已安装并运行
- 防火墙端口已开放 (80, 443, 7001)
- PM2 已全局安装
安全层面:
- SSH 密钥认证已配置
- 不使用 root 用户运行应用
- 数据库密码已修改
- SSL 证书已配置
- 依赖安全漏洞已修复
监控层面:
- PM2 开机自启已配置
- 日志切割已配置
- 监控告警已配置
- 数据库备份已配置
11. 术语表
| 术语 | 英文 | 说明 |
|---|---|---|
| 反向代理 | Reverse Proxy | 代理服务器接收客户端请求,转发给内部服务器 |
| SSL 终止 | SSL Termination | 在负载均衡器或反向代理处解密 HTTPS 请求 |
| 零停机部署 | Zero-Downtime Deployment | 部署过程中服务不中断 |
| CI/CD | Continuous Integration/Deployment | 持续集成和持续部署 |
| PM2 | Process Manager 2 | Node.js 进程管理工具 |
| APM | Application Performance Monitoring | 应用性能监控 |
| 副本集 | Replica Set | MongoDB 的主从复制架构 |
| 连接池 | Connection Pool | 预先建立的数据库连接集合 |
| 负载均衡 | Load Balancing | 将请求分发到多个服务器 |
| 健康检查 | Health Check | 定期检查服务可用性 |
| 灰度发布 | Canary Deployment | 逐步向部分用户发布新版本 |
| 回滚 | Rollback | 将应用恢复到之前的版本 |
12. 参考资源
12.1. 官方文档
12.2. 推荐工具
| 工具类型 | 工具名称 | 用途 |
|---|---|---|
| 进程管理 | PM2 | Node.js 进程管理 |
| 容器化 | Docker | 应用容器化部署 |
| 监控 | PM2 Plus | 应用性能监控 |
| 日志管理 | ELK Stack | 集中式日志管理 |
| 错误追踪 | Sentry | 应用错误追踪 |
| 负载测试 | Apache Bench | HTTP 负载测试 |
| 压力测试 | Artillery | 现代化压力测试工具 |
12.3. 相关插件
# Egg.js 生产环境推荐插件
npm install egg-scripts --save # 启动脚本
npm install egg-logger --save # 日志管理
npm install egg-mongoose --save # MongoDB 连接
npm install egg-redis --save # Redis 连接
npm install egg-cors --save # CORS 支持
npm install egg-validate --save # 参数验证
npm install egg-jwt --save # JWT 认证
npm install egg-ratelimit --save # 限流
npm install egg-helmet --save # 安全头设置
npm install egg-compress --save # 响应压缩文档版本: v1.0
最后更新: 2026-02-14
维护者: Egg.js 技术团队