update
This commit is contained in:
parent
a4a9c69b37
commit
eb44dc3491
|
|
@ -1,3 +1,5 @@
|
||||||
|
ENTERPRISE_BACKEND_VERSION=prod-v1.1.0
|
||||||
|
|
||||||
# ==================== 服务器配置 ====================
|
# ==================== 服务器配置 ====================
|
||||||
# API 服务器配置
|
# API 服务器配置
|
||||||
API.HOST=0.0.0.0
|
API.HOST=0.0.0.0
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,92 @@
|
||||||
# Python 3.11 + uv(与 pyproject 中 requires-python 一致)
|
# =============================================================================
|
||||||
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim
|
# 阶段一:编译阶段
|
||||||
|
# 将核心业务目录编译为原生二进制,源码不进入最终镜像
|
||||||
|
# =============================================================================
|
||||||
|
FROM python:3.11-slim-bookworm AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /build
|
||||||
|
|
||||||
|
# 替换为阿里云 apt 镜像源,解决国内网络访问 Debian 官方源超时问题
|
||||||
|
RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources \
|
||||||
|
|| sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list
|
||||||
|
|
||||||
|
# 系统依赖:gcc/g++ 用于 Nuitka 编译;patchelf 用于修正共享库路径
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
gcc g++ patchelf ccache \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 配置镜像源
|
||||||
|
ENV PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
ENV UV_HTTP_TIMEOUT=120
|
||||||
|
ENV UV_HTTP_RETRIES=5
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir uv
|
||||||
|
|
||||||
COPY pyproject.toml uv.lock ./
|
COPY pyproject.toml uv.lock ./
|
||||||
RUN uv sync --frozen --no-dev
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
# nuitka 安装到 venv 中,确保与 .venv/bin/python 一致
|
||||||
|
RUN uv pip install --no-cache-dir nuitka
|
||||||
|
|
||||||
|
# 复制所有源码
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
# 编译需要保护的目录(admin api core logger models services tools utils)
|
||||||
|
# --module:编译为可 import 的扩展模块(.so),而不是独立可执行文件
|
||||||
|
# --follow-import-to:只跟踪项目自身的包,不拉入标准库和第三方包
|
||||||
|
# --output-dir:编译产物输出目录(每个包单独编译)
|
||||||
|
RUN for pkg in admin api core logger models services tools utils; do \
|
||||||
|
uv run python -m nuitka \
|
||||||
|
--module \
|
||||||
|
--follow-import-to=admin \
|
||||||
|
--follow-import-to=api \
|
||||||
|
--follow-import-to=core \
|
||||||
|
--follow-import-to=logger \
|
||||||
|
--follow-import-to=models \
|
||||||
|
--follow-import-to=services \
|
||||||
|
--follow-import-to=tools \
|
||||||
|
--follow-import-to=utils \
|
||||||
|
--include-package=${pkg} \
|
||||||
|
--output-dir=/compiled \
|
||||||
|
--remove-output \
|
||||||
|
${pkg} ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 阶段二:运行阶段
|
||||||
|
# 只包含编译产物和必要运行时,不含任何 .py 源码
|
||||||
|
# =============================================================================
|
||||||
|
FROM python:3.11-slim-bookworm
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
ENV UV_HTTP_TIMEOUT=120
|
||||||
|
ENV UV_HTTP_RETRIES=5
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir uv
|
||||||
|
|
||||||
|
# 复制依赖声明文件并安装生产依赖
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
# 从编译阶段复制二进制模块(.so 文件)
|
||||||
|
COPY --from=builder /compiled/ ./
|
||||||
|
|
||||||
|
# 保留必要的明文文件
|
||||||
|
# main.py:uvicorn 入口,只有两行 import,不含业务逻辑
|
||||||
|
COPY main.py ./
|
||||||
|
# prompt/:提示词模板,运行时动态读取
|
||||||
|
COPY prompt/ ./prompt/
|
||||||
|
# services/fonts/:字体资源文件
|
||||||
|
COPY services/fonts/ ./services/fonts/
|
||||||
|
|
||||||
|
# 工作目录固定为 /app,所有路径相关代码基于 cwd 解析
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
ENV APP_DIR=/app
|
||||||
|
|
||||||
EXPOSE 7861 7862
|
EXPOSE 7862
|
||||||
|
|
||||||
# 端口以环境变量 API.PORT / API_PORT 为准(见 core.config)
|
|
||||||
CMD ["uv", "run", "python", "-m", "main"]
|
CMD ["uv", "run", "python", "-m", "main"]
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,11 @@ from urllib.parse import quote_plus
|
||||||
from pydantic import AliasChoices, Field, model_validator
|
from pydantic import AliasChoices, Field, model_validator
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
# backend/ 目录(与 uvicorn CWD 无关,始终读取该目录下的 .env)
|
# backend/ 目录
|
||||||
_BACKEND_DIR = Path(__file__).resolve().parent.parent
|
# 编译为二进制后 __file__ 路径不可靠,优先使用环境变量 APP_DIR,
|
||||||
|
# 其次使用当前工作目录(Docker WORKDIR /app 固定为 /app)。
|
||||||
|
import os as _os
|
||||||
|
_BACKEND_DIR = Path(_os.environ.get("APP_DIR", "")).resolve() if _os.environ.get("APP_DIR") else Path(_os.getcwd())
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,14 @@ FastAPI 应用主模块
|
||||||
也可使用 ``uvicorn core.main:app``(与 ``main:app`` 等价)。
|
也可使用 ``uvicorn core.main:app``(与 ``main:app`` 等价)。
|
||||||
默认 host/port 来自配置项 api_host / api_port(可通过环境变量覆盖)。
|
默认 host/port 来自配置项 api_host / api_port(可通过环境变量覆盖)。
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv(Path(__file__).resolve().parent.parent / ".env")
|
# 编译为二进制后 __file__ 路径不可靠,使用工作目录(Docker WORKDIR /app)
|
||||||
|
_env_path = Path(os.environ.get("APP_DIR", os.getcwd())) / ".env"
|
||||||
|
load_dotenv(_env_path)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
@ -155,8 +158,8 @@ def create_app() -> FastAPI:
|
||||||
# 注册全局异常处理器
|
# 注册全局异常处理器
|
||||||
register_exception_handlers(app)
|
register_exception_handlers(app)
|
||||||
|
|
||||||
# 静态文件服务(backend/core/main.py -> backend/static)
|
# 静态文件服务(相对工作目录 /app/static)
|
||||||
static_path = Path(__file__).resolve().parent.parent / "static"
|
static_path = Path(os.getcwd()) / "static"
|
||||||
if static_path.exists():
|
if static_path.exists():
|
||||||
app.mount("/static", StaticFiles(directory=str(static_path)), name="static")
|
app.mount("/static", StaticFiles(directory=str(static_path)), name="static")
|
||||||
logger.info(f"静态文件目录已挂载: {static_path}")
|
logger.info(f"静态文件目录已挂载: {static_path}")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ services:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/qing358/zlsj-huoyan-enterprise-backend-viersin:${ENTERPRISE_BACKEND_VERSION:-latest}
|
image: registry.cn-hangzhou.aliyuncs.com/qing358/zlsj-huoyan-enterprise-backend:${ENTERPRISE_BACKEND_VERSION:-latest}
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@ def setup_logger(
|
||||||
if Path(log_dir_name).is_absolute():
|
if Path(log_dir_name).is_absolute():
|
||||||
log_dir = Path(log_dir_name)
|
log_dir = Path(log_dir_name)
|
||||||
else:
|
else:
|
||||||
# 相对路径:使用项目根目录
|
# 相对路径:使用工作目录(编译为二进制后 __file__ 不可靠)
|
||||||
# __file__ 是 backend/logger/logging.py,需要向上两级到项目根目录
|
# Docker WORKDIR /app,直接相对于 cwd 解析
|
||||||
project_root = Path(__file__).parent.parent
|
import os
|
||||||
log_dir = project_root / log_dir_name
|
log_dir = Path(os.getcwd()) / log_dir_name
|
||||||
else:
|
else:
|
||||||
log_dir = Path(log_dir)
|
log_dir = Path(log_dir)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue