27 KiB
27 KiB
🚀 单机 VPS 部署方案 - 优化 TodoList
部署环境:单机 VPS(公网 IP + 大带宽 + 100GB 存储) 优化方向:资源优化、单机部署、简化运维 项目周期:4-5 周 | 总任务数:72 项 | 优先级分布:P0(20) | P1(30) | P2(15) | P3(7)
📋 环境特点分析
✅ 优势
- 单一公网 IP,简化网络配置
- 大带宽支持高并发
- 100GB 存储足够应用 + 数据库 + 备份
⚠️ 制约
- 单机故障 = 全部服务宕机
- 内存/CPU 有限(需要优化)
- 需要更严格的监控和备份
🎯 优化策略
- 容器精简 - 使用 Alpine 基础镜像
- 资源共享 - 数据库、应用、Web 服务器在同一机器
- 缓存优先 - Redis 缓存热数据
- 监控告警 - 及时发现问题
- 自动备份 - 防止数据丢失
🎯 第一阶段:环境准备与优化(第 1 周)
🔴 P0 任务:VPS 环境初始化
1.1 VPS 系统准备
- SSH 连接 VPS,验证系统版本(建议 Ubuntu 20.04 LTS)
- 更新系统:
sudo apt update && apt upgrade -y - 安装基础工具:
sudo apt install -y curl wget git htop - 配置防火墙(UFW)
sudo ufw enable sudo ufw allow 22/tcp # SSH sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS - 配置时区和 NTP
- 创建普通用户用于应用运行(非 root)
1.2 Docker 和 Docker Compose 安装
- 安装 Docker:
curl -fsSL https://get.docker.com | sh - 配置 Docker 权限:添加用户到 docker 组
- 安装 Docker Compose(最新版本)
- 验证 Docker 和 Compose 可用性
1.3 域名和 SSL 配置
- 配置域名 DNS 解析到公网 IP
- 申请 Let's Encrypt SSL 证书(使用 Certbot)
- 配置 SSL 证书自动续期
- 测试 HTTPS 连接
1.4 存储规划
- 检查磁盘使用情况:
df -h - 规划存储分配(100GB)
系统:20GB 数据库:30GB 应用:20GB 备份:20GB 日志:10GB - 创建数据目录结构
🟠 P1 任务:后端项目创建
1.5 创建后端项目
- 在 VPS 上克隆项目:
git clone <repo> /home/app/backend - 创建
/backend目录结构backend/ ├── src/ │ ├── server.ts │ ├── config/ │ ├── routes/ │ ├── controllers/ │ ├── middleware/ │ ├── database/ │ └── types/ ├── docker/ │ ├── Dockerfile │ └── .dockerignore ├── scripts/ │ ├── db-init.sql │ └── backup.sh ├── package.json ├── tsconfig.json └── .env - 本地初始化 Node.js 项目(npm init)
- 编写最小化 package.json(仅必需依赖)
1.6 依赖选择(针对单机优化)
- 后端依赖:
{ "express": "^4.18.2", "pg": "^8.10.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "zod": "^3.22.4", "pino": "^8.16.1" } - 开发依赖:
{ "typescript": "^5.2.2", "ts-node": "^10.9.1", "nodemon": "^3.0.1", "@types/express": "^4.17.20", "@types/node": "^20.8.0", "jest": "^29.7.0", "@types/jest": "^29.5.6" } - 移除不必要包:@astrojs/node, 重量级 ORM 等
🟡 P2 任务:文档和规划
1.7 部署文档编写
- 编写 VPS 部署指南
- 记录环境配置清单
- 编写故障恢复流程
- 编写备份和恢复步骤
🎯 第二阶段:后端开发(第 2 周)
🔴 P0 任务:核心后端功能
2.1 Server 基础配置(精简版)
- 创建
src/server.ts主文件 - 配置 Express 应用
app.use(cors({ origin: process.env.FRONTEND_URL })); app.use(express.json({ limit: '10mb' })); app.use(compression()); // 启用 Gzip - 配置错误处理中间件
- 实现健康检查端点
GET /health - 配置日志(使用 Pino,性能优于 Winston)
2.2 数据库配置(针对单机)
- 创建 PostgreSQL 容器配置
postgres: image: postgres:15-alpine # 使用 Alpine 减少镜像大小 environment: POSTGRES_DB: jiao77_db POSTGRES_USER: app POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data restart: always - 创建连接池配置
new Pool({ max: 20, // 单机限制连接数 idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }) - 实现连接池监控函数
2.3 数据库 Schema(优化版)
- 创建 SQL 初始化脚本
-- 评论表(带分区考虑) CREATE TABLE comments ( id SERIAL PRIMARY KEY, report_id VARCHAR(100) NOT NULL, author VARCHAR(100) NOT NULL, content TEXT NOT NULL CHECK (char_length(content) <= 5000), status VARCHAR(20) DEFAULT 'pending', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); -- 索引优化 CREATE INDEX CONCURRENTLY idx_comments_report_id ON comments(report_id, created_at DESC); CREATE INDEX CONCURRENTLY idx_comments_status ON comments(status, created_at DESC); -- 统计表 CREATE TABLE report_stats ( id SERIAL PRIMARY KEY, report_id VARCHAR(100) UNIQUE NOT NULL, views INTEGER DEFAULT 0, comments INTEGER DEFAULT 0, likes INTEGER DEFAULT 0, shares INTEGER DEFAULT 0, last_updated TIMESTAMP DEFAULT NOW() ); -- 点赞表 CREATE TABLE likes ( id SERIAL PRIMARY KEY, report_id VARCHAR(100) NOT NULL, client_id VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT NOW(), UNIQUE(report_id, client_id) ); - 创建数据库初始化脚本
scripts/db-init.sql - 准备数据库迁移工具(简单的 SQL 文件版本控制)
2.4 评论 API 实现(轻量级)
GET /api/comments?reportId=xxx&page=1&limit=20- 分页获取POST /api/comments- 创建评论(含速率限制)DELETE /api/comments/:id- 删除评论(仅作者或管理员)- 实现数据验证(使用 Zod)
- 实现错误处理
2.5 统计 API 实现(轻量级)
GET /api/stats/:reportId- 获取统计数据(加缓存)POST /api/stats/:reportId/view- 记录浏览(批量处理)POST /api/stats/:reportId/like- 点赞- 实现请求去重(基于 IP + clientId)
- 实现缓存策略
2.6 中间件实现(安全 + 性能)
- 速率限制中间件
const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 分钟 max: 100, // 单机限制请求数 keyGenerator: (req) => req.ip, skip: (req) => req.path === '/health' }); - 请求日志中间件(Pino)
- 数据验证中间件(Zod)
- 错误处理中间件
2.7 本地测试
- 运行
npm run dev本地启动 - 测试各个 API 端点
- 测试数据库连接
- 验证错误处理
🟠 P1 任务:后端测试
2.8 单元测试(简化版)
- 编写 API 端点测试
- 编写数据验证测试
- 编写错误处理测试
- 目标覆盖率 > 70%(单机优先功能质量)
2.9 集成测试
- 测试完整的评论流程
- 测试完整的统计流程
- 测试异常场景
🎯 第三阶段:前端开发(第 2-3 周)
🔴 P0 任务:前端集成
3.1 Astro 混合渲染配置
- 更新
astro.config.mjsexport default defineConfig({ integrations: [react(), tailwind()], output: 'hybrid', adapter: node({ mode: 'standalone' }), vite: { ssr: { external: ['pg'] } } }); - 本地测试混合渲染
3.2 API 客户端库
- 创建
src/lib/api-client.tsconst API_BASE = process.env.PUBLIC_API_URL || 'http://localhost:3000'; export async function fetchAPI( path: string, options?: RequestInit ) { const response = await fetch(`${API_BASE}${path}`, { headers: { 'Content-Type': 'application/json', ...options?.headers, }, ...options, }); if (!response.ok) { throw new Error(`API Error: ${response.status}`); } return response.json(); } - 实现缓存策略
3.3 React 组件开发(轻量级)
- 开发
CommentSection组件export default function CommentSection({ reportId }: { reportId: string }) { const [comments, setComments] = useState<Comment[]>([]); const [loading, setLoading] = useState(false); useEffect(() => { setLoading(true); fetchAPI(`/api/comments?reportId=${reportId}`) .then(setComments) .finally(() => setLoading(false)); }, [reportId]); // ... 组件逻辑 } - 开发
StatsPanel组件(简化版)export default function StatsPanel({ reportId }: { reportId: string }) { const [stats, setStats] = useState<Stats | null>(null); useEffect(() => { fetchAPI(`/api/stats/${reportId}`).then(setStats); }, [reportId]); if (!stats) return <Skeleton />; return ( <div className="grid grid-cols-2 md:grid-cols-4 gap-4"> <StatCard label="浏览" value={stats.views} /> <StatCard label="评论" value={stats.comments} /> <StatCard label="点赞" value={stats.likes} /> <StatCard label="分享" value={stats.shares} /> </div> ); } - 开发
LikeButton组件
3.4 页面集成
- 在报告页面导入组件
- 设置客户端加载指令
- 样式适配
🟠 P1 任务:前端测试
3.5 组件测试
- 编写简单的组件测试(Vitest)
- 测试数据加载
- 测试用户交互
🎯 第四阶段:单机容器化部署(第 3 周)
🔴 P0 任务:Docker 化应用
4.1 后端 Dockerfile(Alpine 优化)
- 创建
backend/Dockerfile# 构建阶段 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force # 运行阶段 FROM node:18-alpine WORKDIR /app RUN apk add --no-cache dumb-init COPY --from=builder /app/node_modules ./node_modules COPY . . EXPOSE 3000 ENTRYPOINT ["dumb-init", "--"] CMD ["node", "dist/server.js"] - 镜像大小目标:< 200MB
4.2 前端 Dockerfile(静态优化)
- 创建
frontend/DockerfileFROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist EXPOSE 3000 CMD ["node", "./dist/server/entry.mjs"]
4.3 Docker Compose 配置(单机专用)
- 创建
docker-compose.ymlversion: '3.8' services: postgres: image: postgres:15-alpine container_name: jiao77_postgres environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data - ./scripts/db-init.sql:/docker-entrypoint-initdb.d/init.sql restart: unless-stopped # 资源限制 deploy: resources: limits: cpus: '1' memory: 1G reservations: cpus: '0.5' memory: 512M healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: jiao77_redis restart: unless-stopped deploy: resources: limits: cpus: '0.5' memory: 512M volumes: - redis_data:/data api: build: context: ./backend dockerfile: Dockerfile container_name: jiao77_api depends_on: postgres: condition: service_healthy redis: condition: service_started environment: NODE_ENV: production DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME} REDIS_URL: redis://redis:6379 PORT: 3000 ports: - "3000:3000" restart: unless-stopped deploy: resources: limits: cpus: '1' memory: 1G reservations: cpus: '0.5' memory: 512M healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 web: build: context: ./frontend dockerfile: Dockerfile container_name: jiao77_web depends_on: - api environment: PUBLIC_API_URL: http://api:3000 ports: - "3001:3000" restart: unless-stopped deploy: resources: limits: cpus: '0.5' memory: 512M nginx: image: nginx:alpine container_name: jiao77_nginx ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro - nginx_cache:/var/cache/nginx depends_on: - web - api restart: unless-stopped deploy: resources: limits: cpus: '0.5' memory: 256M volumes: postgres_data: redis_data: nginx_cache: - 本地测试 Docker Compose
4.4 Nginx 配置(单机反向代理)
- 创建
nginx.confuser nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 2048; use epoll; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # 性能优化 sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; # 日志格式 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; # 缓存配置 proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=http_cache:10m max_size=1g inactive=60m use_temp_path=off; gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss; upstream api { server api:3000; } upstream web { server web:3000; } server { listen 80; server_name _; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name jiao77.cn www.jiao77.cn; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 静态文件 location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff|woff2)$ { proxy_pass http://web; proxy_cache http_cache; proxy_cache_valid 200 30d; expires 30d; add_header Cache-Control "public, immutable"; } # API 接口 location /api/ { proxy_pass http://api; proxy_cache http_cache; proxy_cache_valid 200 10m; proxy_cache_key "$scheme$request_method$host$request_uri"; 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; proxy_pass http://api; } # 前端 location / { proxy_pass http://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; } } }
4.5 环境配置
- 创建
.env模板NODE_ENV=production # 数据库 DB_NAME=jiao77_db DB_USER=app DB_PASSWORD=<strong-password> # Redis REDIS_URL=redis://redis:6379 # 应用 PORT=3000 FRONTEND_URL=https://jiao77.cn API_BASE=https://jiao77.cn/api # 日志 LOG_LEVEL=info
4.6 启动脚本
- 创建
scripts/start.sh#!/bin/bash set -e echo "🚀 启动应用..." # 拉取最新代码 git pull origin main # 构建镜像 docker-compose build --no-cache # 启动服务 docker-compose up -d # 等待数据库启动 sleep 10 # 运行数据库迁移 docker-compose exec -T api npm run migrate # 健康检查 echo "✅ 等待服务健康..." for i in {1..30}; do if curl -f http://localhost:3000/health > /dev/null 2>&1; then echo "✅ 应用已启动" exit 0 fi echo "⏳ 尝试 $i/30..." sleep 1 done echo "❌ 启动失败" exit 1 - 创建
scripts/stop.sh- 优雅关闭 - 创建
scripts/backup.sh- 数据备份
🟠 P1 任务:性能优化
4.7 数据库优化(单机)
- 优化 PostgreSQL 配置
environment: POSTGRES_INITDB_ARGS: | -c shared_buffers=256MB -c effective_cache_size=1GB -c maintenance_work_mem=64MB -c work_mem=16MB - 创建必要的数据库索引
- 配置连接池大小
4.8 API 性能优化
- 实现 API 分页(20 条/页)
- 实现查询结果缓存(Redis)
- 实现请求压缩(Gzip)
- 实现 HTTP 缓存头
4.9 前端性能优化
- Astro 静态生成优化
- 图片优化和懒加载
- 代码分割
- 浏览器缓存配置
🎯 第五阶段:监控与备份(第 4 周)
🔴 P0 任务:核心监控
5.1 应用健康监控
- 配置
/health端点 - 配置
/metrics端点(Prometheus 格式) - 编写简单的监控脚本
#!/bin/bash # 定期检查服务状态 curl -f http://localhost:3000/health || { echo "❌ API 宕机" | mail -s "告警" admin@jiao77.cn docker-compose restart api }
5.2 数据库监控
- 监控数据库连接数
- 监控磁盘使用率
- 监控查询缓慢日志
5.3 系统监控
- 监控 CPU 使用率(< 70%)
- 监控内存使用率(< 80%)
- 监控磁盘使用率(< 80%)
- 配置告警规则
5.4 日志管理
- 配置 Docker 日志驱动(json-file + 轮转)
logging: driver: "json-file" options: max-size: "100m" max-file: "3" - 实现日志聚合(可选:ELK Stack 精简版)
🔴 P0 任务:备份策略
5.5 数据库备份
- 创建自动备份脚本
#!/bin/bash BACKUP_DIR="/backup/postgresql" TIMESTAMP=$(date +%Y%m%d_%H%M%S) docker-compose exec -T postgres pg_dump \ -U app jiao77_db | gzip > $BACKUP_DIR/backup_$TIMESTAMP.sql.gz # 保留最近 7 天的备份 find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +7 -delete - 配置每日凌晨 2 点自动备份(crontab)
- 测试备份恢复流程
5.6 应用备份
- 备份应用代码(Git)
- 备份配置文件
- 备份日志文件(定期轮转)
5.7 存储规划
- 本地备份:30GB(7 天备份)
- 云存储备份:20GB(使用 Aliyun OSS 或 COS)
- 监控备份完成状态
🟠 P1 任务:故障恢复
5.8 故障恢复流程
- 编写数据库恢复脚本
#!/bin/bash # 恢复数据库 docker-compose exec -T postgres psql -U app jiao77_db < backup.sql - 编写服务重启脚本
- 编写完整的应急响应手册
5.9 测试和演练
- 测试备份恢复(月度)
- 测试服务重启(周度)
- 演练故障场景(季度)
🎯 第六阶段:上线和运维(第 5 周)
🔴 P0 任务:上线前准备
6.1 最终检查清单
- 所有功能测试通过
- 性能基线建立
- 安全审计完成
- 备份策略验证
- 文档完备
- 监控告警配置
- 回滚计划准备
6.2 SSL 证书配置
- 使用 Certbot 申请证书
sudo certbot certonly --standalone -d jiao77.cn -d www.jiao77.cn - 配置自动续期
sudo systemctl enable certbot.timer - 配置 Nginx 使用证书
6.3 域名配置
- 配置 A 记录指向公网 IP
- 配置 CNAME(www)
- 配置 MX 记录(邮件,可选)
- 测试 DNS 解析
6.4 上线检查
- SSH 配置(禁用密码登录)
- 防火墙规则验证
- 资源使用率基线
- 日志系统就位
🔴 P0 任务:正式部署
6.5 发布到 VPS
- 登录 VPS
- 执行部署脚本:
bash scripts/start.sh - 验证所有服务正常运行
- 验证 HTTPS 连接
- 验证所有功能可用
6.6 上线后验证
- 访问前端页面
- 测试评论功能
- 测试统计功能
- 检查日志无错误
6.7 持续监控(上线后 24h)
- 监控 CPU、内存、磁盘
- 监控应用日志
- 监控用户反馈
- 记录性能数据
🟠 P1 任务:运维自动化
6.8 Cron 任务设置
- 每日 02:00 - 数据库备份
- 每周日 03:00 - 系统备份
- 每小时 - 健康检查
- 每 10 分钟 - 监控检查
6.9 日常运维任务
- 周度备份验证
- 月度性能分析
- 季度灾难恢复演练
- 定期安全更新
6.10 长期维护计划
- Docker 镜像定期更新
- 依赖包定期更新
- PostgreSQL 大版本升级计划
- 磁盘空间管理计划
🟠 P1 任务:文档和培训
6.11 运维文档
- 部署操作手册
- 故障排查指南
- 备份恢复流程
- 监控告警规则
6.12 应急响应
- 编写应急响应计划
- 列出主要故障场景
- 编写恢复步骤
🎯 可选优化(P2 任务)
🟡 P2 任务:性能优化
7.1 查询优化
- 数据库慢查询分析
- 添加查询索引
- 优化 N+1 查询
- 实现查询结果缓存
7.2 缓存优化
- Redis 缓存热数据
- 实现缓存预热
- 实现缓存失效策略
7.3 API 优化
- 减少 API 响应大小
- 实现字段选择
- 实现 API 聚合
🎯 后续扩展(P3 任务)
🟢 P3 任务:功能扩展
8.1 用户系统
- 用户认证
- 用户资料
- 权限管理
8.2 社区功能
- 评论回复
- 用户关注
- 排行榜
8.3 数据分析
- 用户行为分析
- 内容热力分析
📊 单机配置资源预算
VPS 规格建议
配置:4核 CPU、8GB 内存、100GB SSD
操作系统:Ubuntu 20.04 LTS
带宽:大带宽(>10 Mbps)
容器资源分配
PostgreSQL:
- CPU limit: 1 核
- Memory limit: 1GB
- 实际使用:0.5 核、500MB
Redis:
- CPU limit: 0.5 核
- Memory limit: 512MB
- 实际使用:0.2 核、256MB
API (Node.js):
- CPU limit: 1 核
- Memory limit: 1GB
- 实际使用:0.3 核、300MB
Web (Astro):
- CPU limit: 0.5 核
- Memory limit: 512MB
- 实际使用:0.1 核、100MB
Nginx:
- CPU limit: 0.5 核
- Memory limit: 256MB
- 实际使用:0.05 核、50MB
总计峰值:3 核、3.5GB
实际使用:1.15 核、1.2GB(预留安全边际)
存储分配(100GB)
系统和 Docker:20GB
PostgreSQL 数据:30GB
Redis 数据:2GB
应用代码:5GB
日志文件:3GB
备份文件:30GB
缓冲区:10GB
⏱️ 时间表(针对单机优化)
第1周 - VPS 准备 + 后端开发 60 小时
第2周 - 前端开发 + 集成 50 小时
第3周 - Docker 化 + 部署 40 小时
第4周 - 监控 + 备份 + 测试 40 小时
第5周 - 上线 + 优化 30 小时
──────────────────────────────────
总计:220 小时 ≈ 5-6 周(单人开发)
≈ 3-4 周(双人开发)
🚀 快速开始指南
立即开始(第 1 天)
# 1. SSH 登录 VPS
ssh root@<ip>
# 2. 安装 Docker 和 Compose
curl -fsSL https://get.docker.com | sh
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 3. 克隆项目
git clone <repo> /home/app
# 4. 配置环境
cd /home/app
cp .env.example .env
# 编辑 .env,配置数据库密码等
# 5. 启动应用
docker-compose up -d
# 6. 验证
curl http://localhost:3000/health
配置 SSL(第 2 天)
# 使用 Certbot
sudo apt install certbot
sudo certbot certonly --standalone -d jiao77.cn -d www.jiao77.cn
# 在 docker-compose.yml 中配置证书路径
# 重启 Nginx
docker-compose restart nginx
配置备份(第 3 天)
# 添加 cron 任务
crontab -e
# 添加备份命令
0 2 * * * cd /home/app && bash scripts/backup.sh
💡 单机部署最佳实践
✅ DO(应该做)
- ✅ 定期备份数据库
- ✅ 监控资源使用率
- ✅ 设置告警规则
- ✅ 使用 Alpine 镜像减少内存
- ✅ 配置资源限制
- ✅ 日志轮转
- ✅ 定期更新依赖
❌ DON'T(不应该做)
- ❌ 不使用 root 运行容器
- ❌ 不在生产用开发镜像
- ❌ 不忽视监控告警
- ❌ 不手动管理依赖版本
- ❌ 不连续部署到生产(需要测试)
🔧 常见问题排查
问题 1:内存不足
# 检查内存使用
docker stats
# 解决方案:
# 1. 减少 PostgreSQL 缓冲区
# 2. 减少 Redis 最大内存
# 3. 优化 Node.js 堆大小
问题 2:磁盘满
# 检查磁盘
df -h
# 清理 Docker 镜像
docker image prune -a
# 清理 Docker 容器
docker container prune
问题 3:性能下降
# 检查慢查询
docker-compose logs api | grep "SLOW"
# 检查数据库连接
docker-compose exec postgres psql -c "SELECT count(*) FROM pg_stat_activity;"
📈 性能指标目标
| 指标 | 目标 | 说明 |
|---|---|---|
| 页面加载时间 | < 2s | 首次加载 |
| API 响应时间 | < 200ms | 平均响应 |
| 数据库查询 | < 100ms | 95 分位 |
| CPU 使用率 | < 60% | 平均 |
| 内存使用率 | < 75% | 峰值 |
| 磁盘使用率 | < 80% | 实时 |
| 可用性 | 99.5% | 月度 |
🎯 总结
这个方案针对单机 VPS 环境进行了全面优化:
- 资源优化 - 使用 Alpine 镜像、资源限制、连接池优化
- 部署简化 - Docker Compose 单文件部署、Nginx 反向代理
- 监控自动化 - 健康检查、告警规则、自动重启
- 备份完善 - 每日备份、7 天保留、恢复流程
- 成本低 - 无需复杂基础设施、单机成本 ~¥100/月
建议:从 P0 任务开始,按阶段稳步推进,确保每个阶段的质量。