gendesign/tradein-mvp/backend/Dockerfile
lekss361 8423af5dd5
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-browser (push) Successful in 36s
Deploy Trade-In / build-frontend (push) Successful in 2m23s
Deploy Trade-In / test (push) Successful in 3m14s
Deploy Trade-In / build-backend (push) Successful in 4m19s
Deploy Trade-In / deploy (push) Successful in 1m44s
feat(tradein): версионирование продукта — единый источник, подвал, PDF, /versions (#2824)
2026-08-10 16:00:54 +00:00

111 lines
5.5 KiB
Docker
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Trade-In MVP backend — lean image (FastAPI + WeasyPrint).
# Не содержит Playwright/Chromium/Celery/Redis — только то что нужно для trade-in feature.
#
# Build context = tradein-mvp/ (uv workspace root), НЕ ./backend (#2137): образу нужны
# workspace-манифест (pyproject.toml + uv.lock) и packages/scraper-kit для editable install.
# Собирается через `dockerfile: backend/Dockerfile` (см. docker-compose*.yml +
# .forgejo/workflows/deploy-tradein.yml build-backend).
# ---- builder ----
FROM python:3.12-slim AS builder
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev
RUN pip install --no-cache-dir uv
# WORKDIR = uv workspace root. backend/ и packages/* — члены workspace.
WORKDIR /app
# Манифесты workspace + members сначала (кэшируемый слой зависимостей).
# packages/ копируем ДО uv sync целиком: editable-install scraper-kit требует
# src/ на этапе резолва (hatchling билдит editable-wheel по pyproject + src).
COPY pyproject.toml uv.lock ./
COPY backend/pyproject.toml backend/pyproject.toml
COPY packages/ packages/
# uv sync --frozen ставит зависимости backend ВКЛЮЧАЯ scraper-kit (editable member,
# .pth → /app/packages/scraper-kit/src). --no-dev: без pytest/ruff.
# NB: команда содержит import-assert'ы — они И bust'ят build-cache этого слоя
# (защита от stale-кэша без нужной deps), И валидируют что зависимость реально
# установлена (сборка падает громко, а не в рантайме).
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev \
&& /app/.venv/bin/python -c "import lxml; print('lxml', lxml.__version__)" \
&& /app/.venv/bin/python -c "import scraper_kit; print('scraper_kit', scraper_kit.__file__)"
COPY backend/app backend/app
COPY backend/scripts backend/scripts
# ---- runner ----
FROM python:3.12-slim AS runner
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/app/.venv/bin:$PATH"
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
libcairo2 \
libpango-1.0-0 \
libpangoft2-1.0-0 \
fonts-dejavu-core \
curl \
&& useradd --create-home --uid 1000 app
WORKDIR /app
# Runtime-layout сохраняем прежним (app в /app/app, scripts в /app/scripts), чтобы
# bind-mount'ы compose не менялись: ./backend/app:/app/app (dev hot-reload) и
# ../auth/roles.yaml:/app/auth/roles.yaml (prod, app/core/auth.py читает /app/auth/roles.yaml).
# backend = virtual-пакет (НЕ в site-packages) → import app идёт из CWD=/app.
# packages/ ОБЯЗАТЕЛЕН в рантайме: editable .pth ссылается на /app/packages/scraper-kit/src.
COPY --from=builder --chown=app:app /app/.venv /app/.venv
COPY --from=builder --chown=app:app /app/packages /app/packages
COPY --from=builder --chown=app:app /app/backend/app /app/app
COPY --from=builder --chown=app:app /app/backend/scripts /app/scripts
# Version-файл фолбэка (app/core/version.py ищет VERSION, идя вверх от своего
# каталога — здесь она на 2 уровня выше /app/app/core/, т.е. ровно /app/VERSION).
# Build context = tradein-mvp/, поэтому VERSION резолвится с корня контекста.
COPY --chown=app:app VERSION VERSION
# Версия продукта + короткий git SHA + дата сборки — запечены как build-args
# в образ (см. .forgejo/workflows/deploy-tradein.yml, job build-backend).
# Пустые дефолты ЗДЕСЬ не читаются напрямую: app/core/version.py фолбэчит сам
# (VERSION-файл выше / "dev" / момент импорта модуля).
#
# НАМЕРЕННО в самом низу runner-стадии, ПОСЛЕ apt-get install и тяжёлых
# COPY --from=builder (.venv/packages/app выше) — BUILD_DATE меняется на
# КАЖДОМ деплое (текущее время сборки), а Docker-кэш инвалидирует ВСЕ слои
# ПОСЛЕ первого изменившегося ENV/ARG. Если бы этот блок стоял в начале
# стадии (как раньше), апдейт даты бил бы registry buildcache для apt-get +
# COPY .venv/packages/app КАЖДЫЙ раз — здесь инвалидирует только этот
# дешёвый хвост (ENV + USER + EXPOSE + CMD ниже).
ARG APP_VERSION=""
ARG BUILD_SHA=""
ARG BUILD_DATE=""
ENV APP_VERSION=$APP_VERSION \
BUILD_SHA=$BUILD_SHA \
BUILD_DATE=$BUILD_DATE
USER app
# HOME должен быть явным: Docker НЕ выставляет $HOME по USER, а некоторые
# платформенные библиотеки резолвят $HOME/.cache. Безвредно оставить.
ENV HOME=/home/app
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]