From 38e389cf42cd2a9c046b043f61702d70b9bcb979 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Wed, 3 Dec 2025 12:59:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(deployment):=20=E6=B7=BB=E5=8A=A0=E7=94=9F?= =?UTF-8?q?=E4=BA=A7=E7=8E=AF=E5=A2=83=E9=83=A8=E7=BD=B2=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=92=8C=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 docker-compose.prod.yml 生产环境配置 添加生产部署指南文档 更新 .gitignore 忽略 .env.prod 文件 优化 nginx 配置保持 /api/ 前缀 升级 Python 基础镜像到 3.12 添加 nginx 镜像到 Makefile 使用国内镜像源加速 pnpm 安装 --- .gitignore | 1 + Makefile | 1 + docker-compose.prod.yml | 243 +++++++++++++++++++++++++++++ docker-compose.yml | 28 ---- docker/nginx/default.conf | 2 +- docker/web.Dockerfile | 2 +- docs/.vitepress/config.mts | 3 +- docs/latest/advanced/deployment.md | 69 ++++++++ docs/latest/intro/quick-start.md | 6 +- 9 files changed, 321 insertions(+), 34 deletions(-) create mode 100644 docker-compose.prod.yml create mode 100644 docs/latest/advanced/deployment.md diff --git a/.gitignore b/.gitignore index 0e1338f4..a75cff3d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules ### common gitignore .DS_Store .env +.env.prod .env.test .env.local .env.*.local diff --git a/Makefile b/Makefile index 103e336f..99e941f6 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ pull: bash docker/pull_image.sh neo4j:5.26 bash docker/pull_image.sh minio/minio:RELEASE.2023-03-20T20-16-18Z bash docker/pull_image.sh ghcr.io/astral-sh/uv:0.7.2 + bash docker/pull_image.sh nginx:alpine start: @if [ ! -f .env ]; then \ diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..1e2052ca --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,243 @@ +services: + api: + build: + context: . + dockerfile: docker/api.Dockerfile + image: yuxi-api:0.4.prod + container_name: api-prod + working_dir: /app + networks: + - app-network + volumes: + - ./saves:/app/saves + extra_hosts: + - "host.docker.internal:host-gateway" + env_file: + - .env.prod + environment: + - HOST_IP=${HOST_IP:-} + - NEO4J_URI=${NEO4J_URI:-bolt://graph:7687} + - NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j} + - NEO4J_PASSWORD=${NEO4J_PASSWORD:-0123456789} + - MILVUS_URI=${MILVUS_URI:-http://milvus:19530} + - MILVUS_TOKEN=${MILVUS_TOKEN:-} + - MINERU_OCR_URI=${MINERU_OCR_URI:-http://mineru:30000} + - PADDLEX_URI=${PADDLEX_URI:-http://paddlex:8080} + - MINIO_URI=${MINIO_URI:-http://milvus-minio:9000} + - MODEL_DIR_IN_DOCKER=/models + - RUNNING_IN_DOCKER=true + - NO_PROXY=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd,etcd,minio,mineru,paddlex,api.siliconflow.cn + - no_proxy=localhost,127.0.0.1,milvus,graph,milvus-minio,milvus-etcd,etcd,minio,mineru,paddlex,api.siliconflow.cn + command: uv run --no-dev uvicorn server.main:app --host 0.0.0.0 --port 5050 + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:5050/api/system/health || exit 1"] + interval: 30s + timeout: 15s + retries: 8 + start_period: 180s + depends_on: + milvus: + condition: service_healthy + minio: + condition: service_healthy + + web: + build: + context: . + dockerfile: docker/web.Dockerfile + target: production + image: yuxi-web:0.4.prod + container_name: web-prod + ports: + - "80:80" + depends_on: + - api + networks: + - app-network + environment: + - NODE_ENV=production + - VITE_API_URL=http://api:5050 + command: nginx -g "daemon off;" + restart: unless-stopped + + graph: + image: neo4j:5.26 + container_name: graph + volumes: + - ./docker/volumes/neo4j/data:/data + - ./docker/volumes/neo4j/logs:/var/lib/neo4j/logs + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:7474 || exit 1"] + interval: 20s + timeout: 10s + retries: 5 + start_period: 30s + environment: + - NEO4J_AUTH=${NEO4J_USERNAME:-neo4j}/${NEO4J_PASSWORD:-0123456789} + - NEO4J_server_bolt_listen__address=0.0.0.0:7687 + - NEO4J_server_http_listen__address=0.0.0.0:7474 + - ENTITY_EMBEDDING=true + networks: + - app-network + restart: unless-stopped + + etcd: + container_name: milvus-etcd + image: quay.io/coreos/etcd:v3.5.5 + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + volumes: + - ./docker/volumes/milvus/etcd:/etcd + command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 60s + timeout: 30s + retries: 5 + start_period: 30s + networks: + - app-network + restart: unless-stopped + + minio: + container_name: milvus-minio + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + environment: + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin} + volumes: + - ./docker/volumes/milvus/minio:/minio_data + - ./docker/volumes/milvus/minio_config:/root/.minio + command: minio server /minio_data --address 0.0.0.0:9000 --console-address 0.0.0.0:9001 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 60s + timeout: 30s + retries: 5 + start_period: 30s + networks: + - app-network + restart: unless-stopped + + milvus: + image: milvusdb/milvus:v2.5.6 + container_name: milvus + command: ["milvus", "run", "standalone"] + security_opt: + - seccomp:unconfined + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + MILVUS_LOG_LEVEL: error + volumes: + - ./docker/volumes/milvus/milvus:/var/lib/milvus + - ./docker/volumes/milvus/logs:/var/lib/milvus/logs + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 60s + start_period: 120s + timeout: 30s + retries: 5 + depends_on: + - "etcd" + - "minio" + networks: + - app-network + restart: unless-stopped + + mineru-vllm-server: + build: + context: . + dockerfile: docker/mineru.Dockerfile + image: mineru-vllm:latest + container_name: mineru + profiles: + - all + env_file: + - .env + environment: + MINERU_MODEL_SOURCE: local + entrypoint: mineru-vllm-server + command: + --host 0.0.0.0 + --port 30000 + ulimits: + memlock: -1 + stack: 67108864 + ipc: host + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:30000/health || exit 1"] + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ["0"] + capabilities: [gpu] + networks: + - app-network + restart: unless-stopped + + mineru-api: + build: + context: . + dockerfile: docker/mineru.Dockerfile + image: mineru-vllm:latest + container_name: mineru-api + profiles: + - all + env_file: + - .env + environment: + MINERU_MODEL_SOURCE: local + entrypoint: mineru-api + command: + --host 0.0.0.0 + --port 30001 + ulimits: + memlock: -1 + stack: 67108864 + ipc: host + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: [ "0" ] + capabilities: [ gpu ] + restart: unless-stopped + + paddlex: + build: + context: . + dockerfile: docker/paddlex.Dockerfile + image: paddlex:latest + container_name: paddlex-ocr + profiles: + - all + volumes: + - ./docker/volumes/paddlex:/paddlex + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"] + interval: 20s + timeout: 10s + retries: 5 + start_period: 60s + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['0'] + capabilities: [gpu] + networks: + - app-network + restart: unless-stopped + +networks: + app-network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml index 26a47f51..5a1f0eef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,34 +81,6 @@ services: command: pnpm run server restart: unless-stopped - # PostgreSQL 服务 - 基于官方推荐的 shangor/postgres-for-rag 镜像 - # 提供 KV store, VectorDB (pgvector) 和 GraphDB (Apache AGE) 功能 - # postgres: - # image: shangor/postgres-for-rag:v1.0 - # container_name: postgres-lightrag - # environment: - # - POSTGRES_DATABASE=${POSTGRES_DATABASE:-lightrag} - # - POSTGRES_USER=${POSTGRES_USER:-lightrag} - # - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-lightrag} - # - POSTGRES_HOST_AUTH_METHOD=md5 - # # 启用必要的扩展 - # - POSTGRES_INITDB_ARGS=--auth-host=md5 - # volumes: - # - ./docker/volumes/postgres/data:/var/lib/postgresql/data - # - ./docker/init-postgres.sh:/init-postgres.sh - # ports: - # - "5432:5432" - # healthcheck: - # test: ["CMD-SHELL", "PGPASSWORD=${POSTGRES_PASSWORD:-lightrag} psql -h localhost -U ${POSTGRES_USER:-lightrag} -d ${POSTGRES_DATABASE:-lightrag} -c \"SELECT ag_catalog.create_graph('test_ready');\" || PGPASSWORD=${POSTGRES_PASSWORD:-lightrag} psql -h localhost -U ${POSTGRES_USER:-lightrag} -d ${POSTGRES_DATABASE:-lightrag} -c 'SELECT 1'"] - # interval: 30s - # timeout: 15s - # retries: 15 - # start_period: 120s - # networks: - # - app-network - # restart: unless-stopped - # command: ["bash", "/init-postgres.sh"] - # region neo4j graph: image: neo4j:5.26 diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf index f9be5e4b..32b340db 100644 --- a/docker/nginx/default.conf +++ b/docker/nginx/default.conf @@ -11,7 +11,7 @@ server { } location /api/ { - proxy_pass http://api:5050/; + proxy_pass http://api:5050/api/; # 保持 /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; diff --git a/docker/web.Dockerfile b/docker/web.Dockerfile index b6101e9e..3e576cf9 100644 --- a/docker/web.Dockerfile +++ b/docker/web.Dockerfile @@ -41,7 +41,7 @@ COPY ./web/package*.json ./ COPY ./web/pnpm-lock.yaml* ./ # 安装依赖 -RUN pnpm install --frozen-lockfile +RUN pnpm install --frozen-lockfile --registry=https://registry.npmmirror.com # 复制源代码并构建 COPY ./web . diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index a81e9f26..fdf700b0 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -44,7 +44,8 @@ export default defineConfig({ { text: '文档解析', link: '/latest/advanced/document-processing' }, { text: '智能体', link: '/latest/advanced/agents-config' }, { text: '品牌自定义', link: '/latest/advanced/branding' }, - { text: '其他配置', link: '/latest/advanced/misc' } + { text: '其他配置', link: '/latest/advanced/misc' }, + { text: '生产部署', link: '/latest/advanced/deployment' } ] }, { diff --git a/docs/latest/advanced/deployment.md b/docs/latest/advanced/deployment.md new file mode 100644 index 00000000..c3868d4b --- /dev/null +++ b/docs/latest/advanced/deployment.md @@ -0,0 +1,69 @@ +# 生产部署指南 + +本指南介绍了如何在生产环境中部署 Yuxi-Know。 + +## 前置要求 + +- **Docker Engine** (v24.0+) +- **Docker Compose** (v2.20+) +- **NVIDIA Container Toolkit** (如果在生产环境使用 GPU 服务) + +注意事项: + +1. 生产环境和开发环境最好是两台独立的机器,不然会存在端口和资源的冲突问题。 +2. 虽然名为“生产环境”,但实际上只是做了一些基本的配置而已,真要上线业务,需要根据实际情况进行调整。 + +## 部署步骤 + +### 1. 配置环境变量 + +为了避免与开发环境的冲突,建议在生产环境中使用 `.env.prod` 文件。请确保你已经从模板创建了该文件并填写了必要的密钥。 + +```bash +cp .env.template .env.prod +``` + +编辑 `.env.prod` 文件,设置强密码并配置必要的 API 密钥: + +- `NEO4J_PASSWORD`: 修改默认密码 +- `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY`: 修改默认密钥 +- `SILICONFLOW_API_KEY` 等模型密钥 + +### 2. 启动服务 + +使用 `docker-compose.prod.yml` 文件启动生产环境: + +```bash +# 仅启动核心服务 (CPU 模式) +docker compose -f docker-compose.prod.yml up -d --build + +# 启动所有服务 (包含 GPU OCR 服务) +docker compose -f docker-compose.prod.yml --profile all up -d --build +``` + +### 3. 验证部署 + +- **Web 访问**: `http://localhost` (直接通过 80 端口访问,无需 :5173) +- **API 健康检查**: `curl http://localhost/api/system/health` + +## 维护与更新 + +### 更新代码并重新部署 + +```bash +# 拉取最新代码 +git pull + +# 重新构建并启动 +docker compose -f docker-compose.prod.yml up -d --build +``` + +### 查看日志 + +```bash +# 查看 API 日志 +docker logs -f api-prod + +# 查看 Nginx 访问日志 +docker logs -f web-prod +``` diff --git a/docs/latest/intro/quick-start.md b/docs/latest/intro/quick-start.md index 61a7a12c..968b48b9 100644 --- a/docs/latest/intro/quick-start.md +++ b/docs/latest/intro/quick-start.md @@ -34,7 +34,7 @@ cd Yuxi-Know cp .env.template .env ``` -编辑 `.env` 文件,配置必需的 API 密钥: +编辑 `.env` 文件,配置必需的 API 密钥,这里强烈建议先使用硅基流动的 API 和模型(DeepSeek)验证平台的功能无误后,再尝试切换到自己的模型: <<< @/../.env.template#model_provider{bash 5} @@ -91,10 +91,10 @@ docker logs web-dev -f ```bash # Linux/macOS -bash docker/pull_image.sh python:3.11-slim +bash docker/pull_image.sh python:3.12-slim # Windows PowerShell -powershell -ExecutionPolicy Bypass -File docker/pull_image.ps1 python:3.11-slim +powershell -ExecutionPolicy Bypass -File docker/pull_image.ps1 python:3.12-slim ``` **离线部署方案**: