# 🚀 单机 VPS 部署方案 - 优化 TodoList **部署环境**:单机 VPS(公网 IP + 大带宽 + 100GB 存储) **优化方向**:资源优化、单机部署、简化运维 **项目周期**:4-5 周 | **总任务数**:72 项 | **优先级分布**:P0(20) | P1(30) | P2(15) | P3(7) --- ## 📋 环境特点分析 ### ✅ 优势 - 单一公网 IP,简化网络配置 - 大带宽支持高并发 - 100GB 存储足够应用 + 数据库 + 备份 ### ⚠️ 制约 - 单机故障 = 全部服务宕机 - 内存/CPU 有限(需要优化) - 需要更严格的监控和备份 ### 🎯 优化策略 1. **容器精简** - 使用 Alpine 基础镜像 2. **资源共享** - 数据库、应用、Web 服务器在同一机器 3. **缓存优先** - Redis 缓存热数据 4. **监控告警** - 及时发现问题 5. **自动备份** - 防止数据丢失 --- ## 🎯 第一阶段:环境准备与优化(第 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) ```bash 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 /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 依赖选择(针对单机优化) - [ ] 后端依赖: ```json { "express": "^4.18.2", "pg": "^8.10.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "zod": "^3.22.4", "pino": "^8.16.1" } ``` - [ ] 开发依赖: ```json { "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 应用 ```typescript 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 容器配置 ```yaml 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 ``` - [ ] 创建连接池配置 ```typescript new Pool({ max: 20, // 单机限制连接数 idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }) ``` - [ ] 实现连接池监控函数 #### 2.3 数据库 Schema(优化版) - [ ] 创建 SQL 初始化脚本 ```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 中间件实现(安全 + 性能) - [ ] 速率限制中间件 ```typescript 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.mjs` ```javascript export default defineConfig({ integrations: [react(), tailwind()], output: 'hybrid', adapter: node({ mode: 'standalone' }), vite: { ssr: { external: ['pg'] } } }); ``` - [ ] 本地测试混合渲染 #### 3.2 API 客户端库 - [ ] 创建 `src/lib/api-client.ts` ```typescript const 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` 组件 ```typescript export default function CommentSection({ reportId }: { reportId: string }) { const [comments, setComments] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { setLoading(true); fetchAPI(`/api/comments?reportId=${reportId}`) .then(setComments) .finally(() => setLoading(false)); }, [reportId]); // ... 组件逻辑 } ``` - [ ] 开发 `StatsPanel` 组件(简化版) ```typescript export default function StatsPanel({ reportId }: { reportId: string }) { const [stats, setStats] = useState(null); useEffect(() => { fetchAPI(`/api/stats/${reportId}`).then(setStats); }, [reportId]); if (!stats) return ; return (
); } ``` - [ ] 开发 `LikeButton` 组件 #### 3.4 页面集成 - [ ] 在报告页面导入组件 - [ ] 设置客户端加载指令 - [ ] 样式适配 ### 🟠 P1 任务:前端测试 #### 3.5 组件测试 - [ ] 编写简单的组件测试(Vitest) - [ ] 测试数据加载 - [ ] 测试用户交互 --- ## 🎯 第四阶段:单机容器化部署(第 3 周) ### 🔴 P0 任务:Docker 化应用 #### 4.1 后端 Dockerfile(Alpine 优化) - [ ] 创建 `backend/Dockerfile` ```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/Dockerfile` ```dockerfile FROM 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.yml` ```yaml version: '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.conf` ```nginx user 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` 模板 ```bash NODE_ENV=production # 数据库 DB_NAME=jiao77_db DB_USER=app DB_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` ```bash #!/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 配置 ```yaml 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 格式) - [ ] 编写简单的监控脚本 ```bash #!/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 + 轮转) ```yaml logging: driver: "json-file" options: max-size: "100m" max-file: "3" ``` - [ ] 实现日志聚合(可选:ELK Stack 精简版) ### 🔴 P0 任务:备份策略 #### 5.5 数据库备份 - [ ] 创建自动备份脚本 ```bash #!/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 故障恢复流程 - [ ] 编写数据库恢复脚本 ```bash #!/bin/bash # 恢复数据库 docker-compose exec -T postgres psql -U app jiao77_db < backup.sql ``` - [ ] 编写服务重启脚本 - [ ] 编写完整的应急响应手册 #### 5.9 测试和演练 - [ ] 测试备份恢复(月度) - [ ] 测试服务重启(周度) - [ ] 演练故障场景(季度) --- ## 🎯 第六阶段:上线和运维(第 5 周) ### 🔴 P0 任务:上线前准备 #### 6.1 最终检查清单 - [ ] 所有功能测试通过 - [ ] 性能基线建立 - [ ] 安全审计完成 - [ ] 备份策略验证 - [ ] 文档完备 - [ ] 监控告警配置 - [ ] 回滚计划准备 #### 6.2 SSL 证书配置 - [ ] 使用 Certbot 申请证书 ```bash sudo certbot certonly --standalone -d jiao77.cn -d www.jiao77.cn ``` - [ ] 配置自动续期 ```bash 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 天) ```bash # 1. SSH 登录 VPS ssh root@ # 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 /home/app # 4. 配置环境 cd /home/app cp .env.example .env # 编辑 .env,配置数据库密码等 # 5. 启动应用 docker-compose up -d # 6. 验证 curl http://localhost:3000/health ``` ### 配置 SSL(第 2 天) ```bash # 使用 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 天) ```bash # 添加 cron 任务 crontab -e # 添加备份命令 0 2 * * * cd /home/app && bash scripts/backup.sh ``` --- ## 💡 单机部署最佳实践 ### ✅ DO(应该做) - ✅ 定期备份数据库 - ✅ 监控资源使用率 - ✅ 设置告警规则 - ✅ 使用 Alpine 镜像减少内存 - ✅ 配置资源限制 - ✅ 日志轮转 - ✅ 定期更新依赖 ### ❌ DON'T(不应该做) - ❌ 不使用 root 运行容器 - ❌ 不在生产用开发镜像 - ❌ 不忽视监控告警 - ❌ 不手动管理依赖版本 - ❌ 不连续部署到生产(需要测试) --- ## 🔧 常见问题排查 ### 问题 1:内存不足 ```bash # 检查内存使用 docker stats # 解决方案: # 1. 减少 PostgreSQL 缓冲区 # 2. 减少 Redis 最大内存 # 3. 优化 Node.js 堆大小 ``` ### 问题 2:磁盘满 ```bash # 检查磁盘 df -h # 清理 Docker 镜像 docker image prune -a # 清理 Docker 容器 docker container prune ``` ### 问题 3:性能下降 ```bash # 检查慢查询 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 环境**进行了全面优化: 1. **资源优化** - 使用 Alpine 镜像、资源限制、连接池优化 2. **部署简化** - Docker Compose 单文件部署、Nginx 反向代理 3. **监控自动化** - 健康检查、告警规则、自动重启 4. **备份完善** - 每日备份、7 天保留、恢复流程 5. **成本低** - 无需复杂基础设施、单机成本 ~¥100/月 **建议**:从 P0 任务开始,按阶段稳步推进,确保每个阶段的质量。