refactor: 优化 Docker 部署配置
- 后端使用 uv 管理依赖,镜像内包含所有依赖 - 前端使用生产构建 + serve 提供静态文件 - 添加 WeasyPrint 完整系统依赖 - 修复 PDF 报告 Logo 显示问题 - 添加 .dockerignore 优化构建 - 更新部署文档和 GitHub Actions 工作流 - 前端端口从 5173 改为 3000
This commit is contained in:
parent
db3d8fd9f8
commit
33c4df9645
|
|
@ -115,10 +115,11 @@ jobs:
|
|||
# 打包 Docker 配置文件
|
||||
tar -czf release/xcodereviewer-docker-${{ steps.version.outputs.VERSION }}.tar.gz \
|
||||
docker-compose.yml \
|
||||
Dockerfile \
|
||||
nginx.conf \
|
||||
backend/Dockerfile \
|
||||
backend/.dockerignore \
|
||||
frontend/Dockerfile \
|
||||
frontend/.dockerignore \
|
||||
frontend/docker-entrypoint.sh \
|
||||
backend/env.example \
|
||||
frontend/.env.example
|
||||
|
||||
|
|
@ -206,12 +207,12 @@ jobs:
|
|||
- name: 设置 Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# 16. 构建并推送前端 Docker 镜像(生产环境 Nginx)
|
||||
# 16. 构建并推送前端 Docker 镜像
|
||||
- name: 构建并推送前端 Docker 镜像
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
context: ./frontend
|
||||
file: ./frontend/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
|
|
|
|||
35
Dockerfile
35
Dockerfile
|
|
@ -1,35 +0,0 @@
|
|||
# 多阶段构建 - 构建阶段
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装 pnpm
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# 复制前端项目文件
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||
|
||||
# 安装依赖
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# 复制前端源代码
|
||||
COPY frontend/ .
|
||||
|
||||
# 构建应用
|
||||
RUN pnpm build
|
||||
|
||||
# 生产阶段 - 使用 nginx 提供静态文件服务
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制自定义 nginx 配置
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 从构建阶段复制构建产物
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 启动 nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
|
@ -95,7 +95,7 @@ cp backend/env.example backend/.env
|
|||
docker-compose up -d
|
||||
```
|
||||
|
||||
🎉 **搞定!** 打开 http://localhost:5173 开始体验吧!
|
||||
🎉 **搞定!** 打开 http://localhost:3000 开始体验吧!
|
||||
|
||||
### 演示账户
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
.venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
.env
|
||||
.vscode
|
||||
.DS_Store
|
||||
uploads/
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
|
|
@ -4,37 +4,45 @@ WORKDIR /app
|
|||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PIP_NO_CACHE_DIR=1
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
# 清除代理设置,避免容器内网络问题
|
||||
ENV http_proxy=
|
||||
ENV https_proxy=
|
||||
ENV HTTP_PROXY=
|
||||
ENV HTTPS_PROXY=
|
||||
|
||||
# 安装系统依赖(包含 WeasyPrint 所需的库和中文字体支持)
|
||||
RUN for i in 1 2 3; do \
|
||||
RUN rm -f /etc/apt/apt.conf.d/proxy.conf 2>/dev/null || true && \
|
||||
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libpq-dev \
|
||||
# WeasyPrint 依赖
|
||||
curl \
|
||||
# WeasyPrint 完整依赖
|
||||
libpango-1.0-0 \
|
||||
libpangoft2-1.0-0 \
|
||||
libpangocairo-1.0-0 \
|
||||
libcairo2 \
|
||||
libgdk-pixbuf2.0-0 \
|
||||
libgdk-pixbuf-2.0-0 \
|
||||
libffi-dev \
|
||||
libglib2.0-0 \
|
||||
shared-mime-info \
|
||||
# 字体支持(中文)
|
||||
fonts-noto-cjk \
|
||||
fonts-noto-cjk-extra \
|
||||
fontconfig \
|
||||
&& fc-cache -fv \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& break || sleep 5; \
|
||||
done
|
||||
&& fc-cache -fv \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 安装 uv
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||
|
||||
# 复制依赖文件
|
||||
COPY pyproject.toml .
|
||||
COPY requirements.txt .
|
||||
COPY pyproject.toml uv.lock ./
|
||||
|
||||
# 安装 Python 依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
# 使用 uv 安装依赖(确保无代理)
|
||||
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||
uv sync --frozen --no-dev
|
||||
|
||||
# 复制应用代码
|
||||
COPY . .
|
||||
|
|
|
|||
|
|
@ -375,13 +375,18 @@ class ReportGenerator:
|
|||
"""读取并编码 Logo 图片"""
|
||||
try:
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# 回退三级到项目根目录: services -> app -> backend -> root
|
||||
project_root = os.path.abspath(os.path.join(current_dir, '../../../'))
|
||||
logo_path = os.path.join(project_root, 'frontend/public/images/logo_nobg.png')
|
||||
# 尝试多个可能的路径
|
||||
possible_paths = [
|
||||
# Docker 容器内路径
|
||||
os.path.join(current_dir, '../../static/images/logo_nobg.png'),
|
||||
# 本地开发路径
|
||||
os.path.abspath(os.path.join(current_dir, '../../../frontend/public/images/logo_nobg.png')),
|
||||
]
|
||||
|
||||
if os.path.exists(logo_path):
|
||||
with open(logo_path, "rb") as image_file:
|
||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||
for logo_path in possible_paths:
|
||||
if os.path.exists(logo_path):
|
||||
with open(logo_path, "rb") as image_file:
|
||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f"Error loading logo: {e}")
|
||||
return ""
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 774 KiB |
|
|
@ -18,11 +18,10 @@ services:
|
|||
- xcodereviewer-network
|
||||
|
||||
backend:
|
||||
build:
|
||||
build:
|
||||
context: ./backend
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./backend/uploads:/app/uploads
|
||||
- backend_uploads:/app/uploads
|
||||
ports:
|
||||
- "8000:8000"
|
||||
env_file:
|
||||
|
|
@ -32,23 +31,19 @@ services:
|
|||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
command: sh -c "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload"
|
||||
command: sh -c ".venv/bin/alembic upgrade head && .venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000"
|
||||
networks:
|
||||
- xcodereviewer-network
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
ports:
|
||||
- "5173:5173"
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- VITE_API_BASE_URL=http://backend:8000/api/v1
|
||||
- VITE_API_BASE_URL=http://localhost:8000/api/v1
|
||||
depends_on:
|
||||
- backend
|
||||
command: npm run dev -- --host
|
||||
networks:
|
||||
- xcodereviewer-network
|
||||
|
||||
|
|
@ -58,3 +53,4 @@ networks:
|
|||
|
||||
volumes:
|
||||
postgres_data:
|
||||
backend_uploads:
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ cp backend/env.example backend/.env
|
|||
# 编辑 backend/.env,配置 LLM API Key
|
||||
|
||||
# 3. 启动所有服务
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# 4. 访问应用
|
||||
# 前端: http://localhost:5173
|
||||
# 前端: http://localhost:3000
|
||||
# 后端 API: http://localhost:8000/docs
|
||||
```
|
||||
|
||||
|
|
@ -89,26 +89,26 @@ LLM_MODEL=gpt-4o-mini
|
|||
|
||||
```bash
|
||||
# 3. 启动所有服务
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# 4. 查看服务状态
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
|
||||
# 5. 查看日志
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
### 服务说明
|
||||
|
||||
| 服务 | 端口 | 说明 |
|
||||
|------|------|------|
|
||||
| `frontend` | 5173 | React 前端应用(开发模式,支持热重载) |
|
||||
| `backend` | 8000 | FastAPI 后端 API |
|
||||
| `frontend` | 3000 | React 前端应用(生产构建,使用 serve 提供静态文件) |
|
||||
| `backend` | 8000 | FastAPI 后端 API(使用 uv 管理依赖) |
|
||||
| `db` | 5432 | PostgreSQL 15 数据库 |
|
||||
|
||||
### 访问地址
|
||||
|
||||
- 前端应用: http://localhost:5173
|
||||
- 前端应用: http://localhost:3000
|
||||
- 后端 API: http://localhost:8000
|
||||
- API 文档 (Swagger): http://localhost:8000/docs
|
||||
- API 文档 (ReDoc): http://localhost:8000/redoc
|
||||
|
|
@ -117,95 +117,70 @@ docker-compose logs -f
|
|||
|
||||
```bash
|
||||
# 停止所有服务
|
||||
docker-compose down
|
||||
docker compose down
|
||||
|
||||
# 停止并删除数据卷(清除数据库)
|
||||
docker-compose down -v
|
||||
docker compose down -v
|
||||
|
||||
# 重新构建镜像
|
||||
docker-compose build --no-cache
|
||||
docker compose build --no-cache
|
||||
|
||||
# 查看特定服务日志
|
||||
docker-compose logs -f backend
|
||||
docker compose logs -f backend
|
||||
|
||||
# 进入容器调试
|
||||
docker-compose exec backend bash
|
||||
docker-compose exec db psql -U postgres -d xcodereviewer
|
||||
docker compose exec backend sh
|
||||
docker compose exec db psql -U postgres -d xcodereviewer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 生产环境部署
|
||||
|
||||
生产环境建议使用 Nginx 提供前端静态文件服务,并配置 HTTPS。
|
||||
Docker Compose 默认配置已适用于生产环境:
|
||||
|
||||
### 方式一:使用预构建 Docker 镜像
|
||||
- 前端:构建生产版本,使用 serve 提供静态文件服务
|
||||
- 后端:使用 uv 管理依赖,镜像内包含所有依赖
|
||||
- 数据库:使用 Docker Volume 持久化数据
|
||||
|
||||
```bash
|
||||
# 拉取最新镜像
|
||||
docker pull ghcr.io/lintsinghua/xcodereviewer-frontend:latest
|
||||
docker pull ghcr.io/lintsinghua/xcodereviewer-backend:latest
|
||||
### 生产环境安全建议
|
||||
|
||||
# 启动后端和数据库
|
||||
docker-compose up -d db backend
|
||||
1. **修改默认密钥**:务必修改 `SECRET_KEY` 为随机字符串
|
||||
2. **配置 HTTPS**:使用 Nginx 反向代理并配置 SSL 证书
|
||||
3. **限制 CORS**:在生产环境配置具体的前端域名
|
||||
4. **数据库安全**:修改默认数据库密码,限制访问 IP
|
||||
5. **API 限流**:配置 Nginx 或应用层限流
|
||||
6. **日志监控**:配置日志收集和监控告警
|
||||
7. **删除演示账户**:生产环境请删除或禁用 demo 账户
|
||||
|
||||
# 启动前端(Nginx 生产镜像)
|
||||
docker run -d \
|
||||
--name xcodereviewer-frontend \
|
||||
-p 80:80 \
|
||||
--network xcodereviewer-network \
|
||||
ghcr.io/lintsinghua/xcodereviewer-frontend:latest
|
||||
```
|
||||
### Nginx 反向代理配置(可选)
|
||||
|
||||
### 方式二:本地构建生产镜像
|
||||
|
||||
```bash
|
||||
# 构建前端生产镜像(使用 Nginx)
|
||||
docker build -t xcodereviewer-frontend .
|
||||
|
||||
# 运行前端容器
|
||||
docker run -d \
|
||||
-p 80:80 \
|
||||
--name xcodereviewer-frontend \
|
||||
xcodereviewer-frontend
|
||||
|
||||
# 后端和数据库仍使用 docker-compose
|
||||
docker-compose up -d db backend
|
||||
```
|
||||
|
||||
### 方式三:手动部署
|
||||
|
||||
#### 前端部署
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 构建生产版本
|
||||
pnpm build
|
||||
|
||||
# 将 dist 目录部署到 Nginx/Apache 等 Web 服务器
|
||||
```
|
||||
|
||||
Nginx 配置示例:
|
||||
如需使用 Nginx 提供 HTTPS 和统一入口:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
root /var/www/xcodereviewer/dist;
|
||||
index index.html;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# 前端路由支持
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your-domain.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
# 前端
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# API 代理
|
||||
location /api {
|
||||
proxy_pass http://localhost:8000;
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8000/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
@ -214,38 +189,6 @@ server {
|
|||
}
|
||||
```
|
||||
|
||||
#### 后端部署
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# 创建虚拟环境
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 配置环境变量
|
||||
cp env.example .env
|
||||
# 编辑 .env 文件
|
||||
|
||||
# 初始化数据库
|
||||
alembic upgrade head
|
||||
|
||||
# 使用 Gunicorn 启动(生产环境)
|
||||
gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
||||
```
|
||||
|
||||
### 生产环境安全建议
|
||||
|
||||
1. **修改默认密钥**:务必修改 `SECRET_KEY` 为随机字符串
|
||||
2. **配置 HTTPS**:使用 Let's Encrypt 或其他 SSL 证书
|
||||
3. **限制 CORS**:在生产环境配置具体的前端域名
|
||||
4. **数据库安全**:修改默认数据库密码,限制访问 IP
|
||||
5. **API 限流**:配置 Nginx 或应用层限流
|
||||
6. **日志监控**:配置日志收集和监控告警
|
||||
|
||||
---
|
||||
|
||||
## 本地开发部署
|
||||
|
|
@ -259,13 +202,13 @@ gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
|||
| Node.js | 18+ | 前端运行环境 |
|
||||
| Python | 3.13+ | 后端运行环境 |
|
||||
| PostgreSQL | 15+ | 数据库 |
|
||||
| pnpm | 8+ | 推荐的包管理器 |
|
||||
| pnpm | 8+ | 推荐的前端包管理器 |
|
||||
| uv | 最新版 | 推荐的 Python 包管理器 |
|
||||
|
||||
### 数据库准备
|
||||
|
||||
```bash
|
||||
# 方式一:使用 Docker 启动 PostgreSQL
|
||||
# 方式一:使用 Docker 启动 PostgreSQL(推荐)
|
||||
docker run -d \
|
||||
--name xcodereviewer-db \
|
||||
-e POSTGRES_USER=postgres \
|
||||
|
|
@ -275,7 +218,6 @@ docker run -d \
|
|||
postgres:15-alpine
|
||||
|
||||
# 方式二:使用本地 PostgreSQL
|
||||
# 创建数据库
|
||||
createdb xcodereviewer
|
||||
```
|
||||
|
||||
|
|
@ -285,25 +227,21 @@ createdb xcodereviewer
|
|||
# 1. 进入后端目录
|
||||
cd backend
|
||||
|
||||
# 2. 创建虚拟环境(推荐使用 uv)
|
||||
uv venv
|
||||
source .venv/bin/activate # Linux/macOS
|
||||
# 或 .venv\Scripts\activate # Windows
|
||||
# 2. 安装 uv(如未安装)
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# 3. 安装依赖
|
||||
uv pip install -e .
|
||||
# 或使用 pip
|
||||
pip install -r requirements.txt
|
||||
# 3. 同步依赖
|
||||
uv sync
|
||||
|
||||
# 4. 配置环境变量
|
||||
cp env.example .env
|
||||
# 编辑 .env 文件,配置数据库和 LLM 参数
|
||||
|
||||
# 5. 初始化数据库
|
||||
alembic upgrade head
|
||||
uv run alembic upgrade head
|
||||
|
||||
# 6. 启动后端服务(开发模式,支持热重载)
|
||||
uvicorn app.main:app --reload --port 8000
|
||||
uv run uvicorn app.main:app --reload --port 8000
|
||||
```
|
||||
|
||||
### 前端启动
|
||||
|
|
@ -314,9 +252,8 @@ cd frontend
|
|||
|
||||
# 2. 安装依赖
|
||||
pnpm install
|
||||
# 或 npm install / yarn install
|
||||
|
||||
# 3. 配置环境变量(可选,也可使用运行时配置)
|
||||
# 3. 配置环境变量(可选)
|
||||
cp .env.example .env
|
||||
|
||||
# 4. 启动开发服务器
|
||||
|
|
@ -339,10 +276,10 @@ pnpm format
|
|||
|
||||
# 后端类型检查
|
||||
cd backend
|
||||
mypy app
|
||||
uv run mypy app
|
||||
|
||||
# 后端代码格式化
|
||||
ruff format app
|
||||
uv run ruff format app
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -364,10 +301,10 @@ XCodeReviewer 采用前后端分离架构,所有数据存储在后端 PostgreS
|
|||
|
||||
```bash
|
||||
# 导出 PostgreSQL 数据
|
||||
docker-compose exec db pg_dump -U postgres xcodereviewer > backup.sql
|
||||
docker compose exec db pg_dump -U postgres xcodereviewer > backup.sql
|
||||
|
||||
# 恢复数据
|
||||
docker-compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
||||
docker compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -380,7 +317,7 @@ docker-compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
|||
|
||||
```bash
|
||||
# 检查端口占用
|
||||
lsof -i :5173
|
||||
lsof -i :3000
|
||||
lsof -i :8000
|
||||
lsof -i :5432
|
||||
|
||||
|
|
@ -391,29 +328,37 @@ lsof -i :5432
|
|||
|
||||
```bash
|
||||
# 检查数据库容器状态
|
||||
docker-compose ps db
|
||||
docker compose ps db
|
||||
|
||||
# 查看数据库日志
|
||||
docker-compose logs db
|
||||
docker compose logs db
|
||||
|
||||
# 确保数据库健康检查通过后再启动后端
|
||||
docker-compose up -d db
|
||||
docker-compose exec db pg_isready -U postgres
|
||||
docker-compose up -d backend
|
||||
docker compose up -d db
|
||||
docker compose exec db pg_isready -U postgres
|
||||
docker compose up -d backend
|
||||
```
|
||||
|
||||
**Q: 构建时网络问题(代理相关)**
|
||||
|
||||
如果构建时遇到网络问题,检查 Docker Desktop 的代理设置:
|
||||
1. 打开 Docker Desktop → Settings → Resources → Proxies
|
||||
2. 关闭代理或配置正确的代理地址
|
||||
3. 重启 Docker Desktop
|
||||
4. 重新构建:`docker compose build --no-cache`
|
||||
|
||||
### 后端相关
|
||||
|
||||
**Q: PDF 导出功能报错(WeasyPrint 依赖问题)**
|
||||
|
||||
WeasyPrint 需要系统级依赖,Docker 镜像已包含。本地开发时:
|
||||
Docker 镜像已包含 WeasyPrint 所需的系统依赖。本地开发时需要安装:
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install pango cairo gdk-pixbuf libffi
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf2.0-0
|
||||
sudo apt-get install libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0 libglib2.0-0
|
||||
|
||||
# Windows - 参见 FAQ.md 中的详细说明
|
||||
```
|
||||
|
|
@ -435,14 +380,14 @@ LLM_GAP_MS=3000
|
|||
|
||||
**Q: 前端无法连接后端 API**
|
||||
|
||||
检查 `frontend/.env` 中的 API 地址配置:
|
||||
Docker Compose 部署时,前端通过 `http://localhost:8000/api/v1` 访问后端。确保:
|
||||
1. 后端容器正常运行:`docker compose ps backend`
|
||||
2. 后端端口 8000 可访问:`curl http://localhost:8000/docs`
|
||||
|
||||
本地开发时,检查 `frontend/.env` 中的 API 地址配置:
|
||||
|
||||
```env
|
||||
# 本地开发
|
||||
VITE_API_BASE_URL=http://localhost:8000/api/v1
|
||||
|
||||
# Docker Compose 部署
|
||||
VITE_API_BASE_URL=/api
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
node_modules
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
.env*
|
||||
.vscode
|
||||
.DS_Store
|
||||
|
|
@ -1,23 +1,56 @@
|
|||
FROM node:20-alpine
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 安装 pnpm
|
||||
RUN npm install -g pnpm
|
||||
# 清除代理设置
|
||||
ENV http_proxy=
|
||||
ENV https_proxy=
|
||||
ENV HTTP_PROXY=
|
||||
ENV HTTPS_PROXY=
|
||||
|
||||
# 安装 pnpm(确保无代理)
|
||||
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||
npm install -g pnpm
|
||||
|
||||
# 复制依赖文件
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# 安装依赖
|
||||
RUN pnpm install
|
||||
# 安装依赖(确保无代理)
|
||||
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 5173
|
||||
# 构建时使用占位符,运行时替换
|
||||
ENV VITE_API_BASE_URL=__API_BASE_URL__
|
||||
|
||||
# 开发模式启动命令
|
||||
CMD ["pnpm", "dev", "--host"]
|
||||
# 构建生产版本
|
||||
RUN pnpm build
|
||||
|
||||
# 生产镜像
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 清除代理设置
|
||||
ENV http_proxy=
|
||||
ENV https_proxy=
|
||||
ENV HTTP_PROXY=
|
||||
ENV HTTPS_PROXY=
|
||||
|
||||
# 安装 serve(确保无代理)
|
||||
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||
npm install -g serve
|
||||
|
||||
# 复制构建产物
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
# 复制启动脚本
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
# 替换 API 地址占位符
|
||||
API_URL="${VITE_API_BASE_URL:-http://localhost:8000/api/v1}"
|
||||
|
||||
# 在所有 JS 文件中替换占位符
|
||||
find /app/dist -name '*.js' -exec sed -i "s|__API_BASE_URL__|${API_URL}|g" {} \;
|
||||
|
||||
# 执行原始命令
|
||||
exec "$@"
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 处理 SPA 路由
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 代理 API 请求到后端
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000/api/;
|
||||
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 ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
38
nginx.conf
38
nginx.conf
|
|
@ -1,38 +0,0 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Gzip 压缩配置
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
|
||||
|
||||
# 安全头部
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# 处理 React Router 的客户端路由
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# API 代理(如果需要)
|
||||
# location /api {
|
||||
# proxy_pass http://backend:8000;
|
||||
# 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;
|
||||
# }
|
||||
}
|
||||
Loading…
Reference in New Issue