Docker 部署
使用 Docker 可以避免 better-sqlite3 的本地编译问题,并提供更一致的运行环境。本章提供 Dockerfile 和 docker-compose 配置参考。
Docker 部署是解决
better-sqlite3 编译失败的最简单方案,特别适合 Windows/macOS 开发环境或不想手动配置编译工具链的场景。
后端 Dockerfile
在 backend/ 目录创建 Dockerfile:
# backend/Dockerfile
FROM node:20-bullseye-slim
# 安装编译工具(better-sqlite3 需要)
RUN apt-get update && apt-get install -y \
build-essential \
python3 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# 先复制 package.json,利用 Docker 层缓存
COPY package*.json ./
RUN npm install
# 复制源码并编译
COPY . .
RUN npm run build
# 创建数据目录
RUN mkdir -p /app/data /app/uploads
EXPOSE 3001
CMD ["node", "dist/server.js"]
前端 Dockerfile
在 frontend/ 目录创建 Dockerfile:
# frontend/Dockerfile
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段:使用 Nginx 提供静态文件
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
# Nginx SPA 路由配置
RUN echo 'server { \
listen 80; \
root /usr/share/nginx/html; \
index index.html; \
location / { try_files $uri $uri/ /index.html; } \
location /api/ { proxy_pass http://backend:3001; } \
}' > /etc/nginx/conf.d/default.conf
EXPOSE 80
docker-compose.yml
在项目根目录创建 docker-compose.yml:
version: '3.8'
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: edubuddy-backend
restart: unless-stopped
ports:
- "3001:3001"
environment:
- NODE_ENV=production
- PORT=3001
- OPENAI_API_KEY=${OPENAI_API_KEY}
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o}
- JWT_SECRET=${JWT_SECRET:-change-me-in-production}
- DB_PATH=/app/data/edubuddy.db
- UPLOAD_DIR=/app/uploads
volumes:
# 持久化数据库和上传文件
- edubuddy-data:/app/data
- edubuddy-uploads:/app/uploads
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
interval: 30s
timeout: 10s
retries: 3
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: edubuddy-frontend
restart: unless-stopped
ports:
- "80:80"
depends_on:
backend:
condition: service_healthy
volumes:
edubuddy-data:
driver: local
edubuddy-uploads:
driver: local
环境变量文件
在项目根目录创建 .env(docker-compose 会自动读取):
OPENAI_API_KEY=sk-your-api-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o
JWT_SECRET=your-very-long-random-secret-string
启动命令
# 首次构建并启动
docker-compose up -d --build
# 查看运行状态
docker-compose ps
# 查看后端日志
docker-compose logs -f backend
# 停止服务
docker-compose down
# 停止并删除数据卷(危险!会删除数据库)
docker-compose down -v
更新部署
# 拉取最新代码
git pull origin main
# 重新构建并重启
docker-compose up -d --build
# 只重建特定服务
docker-compose up -d --build backend
数据库备份(Docker 环境)
# 从容器内复制数据库文件到宿主机
docker cp edubuddy-backend:/app/data/edubuddy.db ./backup-$(date +%Y%m%d).db
# 或使用 docker exec 执行 SQLite 在线备份
docker exec edubuddy-backend sqlite3 /app/data/edubuddy.db \
".backup /app/data/backup.db"
docker cp edubuddy-backend:/app/data/backup.db ./backup-$(date +%Y%m%d).db
常见 Docker 问题
better-sqlite3 编译错误
确保 Dockerfile 中包含 build-essential 和 python3,并使用 node:20-bullseye-slim 而非 Alpine(Alpine 编译环境较特殊)。
前端无法访问后端 API
确认 Nginx 配置中的 proxy_pass 指向 http://backend:3001(Docker 内部服务名),而非 localhost:3001。
数据卷权限问题
# 如果后端启动时报权限错误
docker exec -it edubuddy-backend sh
chown -R node:node /app/data /app/uploads