12 KiB
12 KiB
Mobile Upgrade Admin - 部署指南
部署概述
本文档描述 Mobile Upgrade Admin 前端应用的部署方案,包括本地构建、Docker 容器化和生产环境部署。
部署架构
┌─────────────────────────────────────────────────────────────┐
│ Nginx / Caddy │
│ (Reverse Proxy) │
└─────────────────┬───────────────────────┬───────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Mobile Upgrade │ │ Admin Service │
│ Frontend (3001)│ │ Backend (3000) │
└─────────────────┘ └─────────────────┘
环境要求
| 环境 | 要求 |
|---|---|
| Node.js | >= 18.x |
| npm | >= 9.x |
| Docker | >= 20.x (可选) |
| 内存 | >= 512MB |
| 磁盘 | >= 500MB |
环境变量配置
开发环境
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:3000
生产环境
# .env.production
NEXT_PUBLIC_API_URL=https://api.example.com
| 变量 | 说明 | 默认值 |
|---|---|---|
| NEXT_PUBLIC_API_URL | Admin Service API 地址 | http://localhost:3000 |
| PORT | 应用监听端口 | 3000 |
部署方式
方式一:本地构建部署
1. 构建生产版本
cd frontend/mobile-upgrade
# 安装依赖
npm ci
# 构建
npm run build
构建产物在 .next/ 目录。
2. 启动生产服务
# 使用 Node.js 直接运行
npm run start
# 或指定端口
PORT=3001 npm run start
3. 使用 PM2 管理
# 安装 PM2
npm install -g pm2
# 启动应用
pm2 start npm --name "mobile-upgrade" -- start
# 查看状态
pm2 status
# 查看日志
pm2 logs mobile-upgrade
# 重启
pm2 restart mobile-upgrade
# 停止
pm2 stop mobile-upgrade
PM2 配置文件:
// ecosystem.config.js
module.exports = {
apps: [{
name: 'mobile-upgrade',
script: 'npm',
args: 'start',
cwd: '/path/to/mobile-upgrade',
env: {
NODE_ENV: 'production',
PORT: 3001,
},
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '500M',
}],
}
方式二:Docker 容器部署
1. Dockerfile
# Dockerfile
FROM node:18-alpine AS base
# 安装依赖阶段
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# 构建阶段
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 设置环境变量
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
RUN npm run build
# 运行阶段
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# 复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
2. 更新 next.config.js
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone', // 启用独立输出模式
// ... 其他配置
}
module.exports = nextConfig
3. 构建 Docker 镜像
# 构建镜像
docker build \
--build-arg NEXT_PUBLIC_API_URL=https://api.example.com \
-t mobile-upgrade:latest \
.
# 运行容器
docker run -d \
--name mobile-upgrade \
-p 3001:3000 \
mobile-upgrade:latest
4. Docker Compose
# docker-compose.yml
version: '3.8'
services:
mobile-upgrade:
build:
context: .
args:
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://admin-service:3000}
image: mobile-upgrade:latest
container_name: mobile-upgrade
ports:
- "3001:3000"
environment:
- NODE_ENV=production
restart: unless-stopped
networks:
- rwa-network
depends_on:
- admin-service
networks:
rwa-network:
external: true
启动命令:
# 启动
docker-compose up -d
# 查看日志
docker-compose logs -f mobile-upgrade
# 停止
docker-compose down
方式三:静态导出部署
适用于不需要 SSR 的场景。
1. 配置静态导出
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
trailingSlash: true,
images: {
unoptimized: true,
},
}
module.exports = nextConfig
2. 构建静态文件
npm run build
静态文件输出到 out/ 目录。
3. 使用 Nginx 部署
# nginx.conf
server {
listen 80;
server_name upgrade.example.com;
root /var/www/mobile-upgrade;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://admin-service:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
反向代理配置
Nginx 配置
# /etc/nginx/sites-available/mobile-upgrade
upstream mobile_upgrade {
server 127.0.0.1:3001;
}
upstream admin_service {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name upgrade.example.com;
# 前端应用
location / {
proxy_pass http://mobile_upgrade;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
# API 代理
location /api {
proxy_pass http://admin_service;
proxy_http_version 1.1;
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;
# 大文件上传支持
client_max_body_size 200M;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
}
Caddy 配置
# Caddyfile
upgrade.example.com {
reverse_proxy /api/* admin-service:3000
reverse_proxy /* mobile-upgrade:3001
}
健康检查
应用健康检查
// src/app/api/health/route.ts
export async function GET() {
return Response.json({
status: 'healthy',
timestamp: new Date().toISOString(),
})
}
Docker 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
Kubernetes 探针
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
CI/CD 集成
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
paths:
- 'frontend/mobile-upgrade/**'
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
cache-dependency-path: frontend/mobile-upgrade/package-lock.json
- name: Install dependencies
working-directory: frontend/mobile-upgrade
run: npm ci
- name: Build
working-directory: frontend/mobile-upgrade
run: npm run build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.API_URL }}
- name: Build Docker image
working-directory: frontend/mobile-upgrade
run: |
docker build \
--build-arg NEXT_PUBLIC_API_URL=${{ secrets.API_URL }} \
-t mobile-upgrade:${{ github.sha }} \
.
- name: Push to registry
run: |
docker tag mobile-upgrade:${{ github.sha }} registry.example.com/mobile-upgrade:${{ github.sha }}
docker push registry.example.com/mobile-upgrade:${{ github.sha }}
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull registry.example.com/mobile-upgrade:${{ github.sha }}
docker stop mobile-upgrade || true
docker rm mobile-upgrade || true
docker run -d \
--name mobile-upgrade \
-p 3001:3000 \
--restart unless-stopped \
registry.example.com/mobile-upgrade:${{ github.sha }}
监控和日志
日志收集
# Docker 日志
docker logs -f mobile-upgrade
# PM2 日志
pm2 logs mobile-upgrade
# 日志文件位置
/var/log/mobile-upgrade/access.log
/var/log/mobile-upgrade/error.log
性能监控
建议集成:
- Prometheus + Grafana: 指标监控
- Sentry: 错误追踪
- Datadog / New Relic: APM
集成 Sentry
npm install @sentry/nextjs
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1,
})
故障排查
常见问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 页面空白 | 构建失败 | 检查构建日志 |
| API 请求失败 | CORS / 网络 | 检查代理配置 |
| 静态资源 404 | 路径配置 | 检查 basePath 配置 |
| 内存不足 | 并发过高 | 增加实例或内存 |
调试命令
# 检查进程
ps aux | grep node
# 检查端口
netstat -tlnp | grep 3001
# 检查容器
docker ps -a
docker inspect mobile-upgrade
# 检查日志
docker logs --tail 100 mobile-upgrade
回滚策略
Docker 回滚
# 查看历史版本
docker images mobile-upgrade
# 回滚到指定版本
docker stop mobile-upgrade
docker rm mobile-upgrade
docker run -d \
--name mobile-upgrade \
-p 3001:3000 \
mobile-upgrade:previous-tag
PM2 回滚
# 保存当前配置
pm2 save
# 回滚
pm2 reload ecosystem.config.js --update-env
安全建议
- 环境变量:不要在代码中硬编码敏感信息
- HTTPS:生产环境强制使用 HTTPS
- CSP:配置内容安全策略
- 更新依赖:定期更新依赖修复安全漏洞
- 访问控制:配置合适的访问权限