chore: Docker 部署——多阶段 Dockerfile + compose + 数据卷持久化
- 前端 node:22-alpine 构建阶段(npm ci + vite build) - 运行时 python:3.14-slim + uv --frozen 冻结安装(依赖层独立缓存) - entrypoint: 数据卷为空时自动建库并导入 254 套样板 - SQLite 落数据卷 /app/db(HMC_DATABASE_URL 可切 MySQL); healthcheck /api/health - .dockerignore 排除构建无关资产; .gitattributes 强制 sh LF
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
# 版本控制
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python 运行产物
|
||||
.venv
|
||||
**/__pycache__
|
||||
*.py[oc]
|
||||
huamenchuang.db
|
||||
|
||||
# 前端构建产物与依赖(Docker 内重建)
|
||||
frontend/node_modules
|
||||
frontend/dist
|
||||
frontend/scripts
|
||||
|
||||
# 本地开发/验证资产(非运行必需)
|
||||
/doc
|
||||
/shots
|
||||
/scripts
|
||||
.claude
|
||||
*.log
|
||||
|
||||
# 抓取残留与单文件脚本
|
||||
data/dxf-study
|
||||
data/full-site
|
||||
data/api-endpoint-inventory.txt
|
||||
data/fetch-images.py
|
||||
|
||||
# 杂项
|
||||
image.png
|
||||
3D窗型.png
|
||||
.env
|
||||
@@ -0,0 +1,2 @@
|
||||
# shell 脚本强制 LF(容器内 sh 对 CRLF 敏感)
|
||||
*.sh text eol=lf
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
# 华门窗云平台镜像(多阶段:前端构建 → Python 运行时)
|
||||
# 云端构建: git 仓库直接构建即可; 本地: docker build -t menchuang .
|
||||
|
||||
# ---------- 阶段 1: 前端构建 (Vue3 + Vite → dist) ----------
|
||||
FROM node:22-alpine AS web
|
||||
WORKDIR /web
|
||||
COPY frontend/package.json frontend/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY frontend/ ./
|
||||
RUN npm run build
|
||||
|
||||
# ---------- 阶段 2: 后端运行时 (Python 3.14 + uv) ----------
|
||||
FROM python:3.14-slim-bookworm
|
||||
|
||||
# uv 包管理器(按 uv.lock 冻结安装)
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /usr/local/bin/uv
|
||||
ENV UV_COMPILE_BYTECODE=1 \
|
||||
UV_LINK_MODE=copy \
|
||||
TZ=Asia/Shanghai
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 依赖层(独立缓存: 代码变更不触发依赖重装)
|
||||
COPY pyproject.toml uv.lock README.md ./
|
||||
RUN uv sync --frozen --no-dev --no-install-project
|
||||
|
||||
# 应用代码 + 样板数据资产 + 前端产物
|
||||
COPY src/ ./src/
|
||||
COPY data/ ./data/
|
||||
COPY --from=web /web/dist/ ./frontend/dist/
|
||||
RUN uv sync --frozen --no-dev
|
||||
|
||||
# 运行配置: SQLite 落在数据卷 /app/db (compose 挂载持久化)
|
||||
ENV HMC_DATABASE_URL="sqlite+aiosqlite:////app/db/huamenchuang.db"
|
||||
VOLUME ["/app/db"]
|
||||
|
||||
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
|
||||
EXPOSE 8000
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
|
||||
CMD python -c "import urllib.request;urllib.request.urlopen('http://127.0.0.1:8000/api/health',timeout=4)" || exit 1
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
CMD ["/app/.venv/bin/uvicorn", "huamenchuang.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: menchuang:latest
|
||||
container_name: menchuang
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
# SQLite 落在数据卷; 如需 MySQL: mysql+aiomysql://user:pwd@host:3306/hmc
|
||||
HMC_DATABASE_URL: sqlite+aiosqlite:////app/db/huamenchuang.db
|
||||
# 生产务必换成随机长密钥(登录态签名)
|
||||
HMC_JWT_SECRET: ${HMC_JWT_SECRET:-change-me-in-production-please-set-a-long-random-secret-key}
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- db_data:/app/db
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request;urllib.request.urlopen('http://127.0.0.1:8000/api/health',timeout=4)"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# 容器入口: 数据卷为空时自动建库并导入 254 套样板, 之后交给 CMD 启动服务
|
||||
set -e
|
||||
|
||||
DB_FILE="/app/db/huamenchuang.db"
|
||||
export PATH="/app/.venv/bin:$PATH"
|
||||
|
||||
mkdir -p /app/db
|
||||
if [ ! -f "$DB_FILE" ]; then
|
||||
echo "[entrypoint] 首次启动: 初始化数据库并导入样板数据..."
|
||||
python -m huamenchuang.scripts.seed
|
||||
echo "[entrypoint] 种子完成: 管理员 13800000000/123456"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
Reference in New Issue
Block a user