mod: двухэтапная сборка для более компактного образа
This commit is contained in:
@@ -45,3 +45,8 @@ jobs:
|
|||||||
# Используем теги, сгенерированные шагом meta (v1.0.0 и latest)
|
# Используем теги, сгенерированные шагом meta (v1.0.0 и latest)
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
# ДОБАВЛЕНО:
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
# И это для медленного интернета:
|
||||||
|
timeout: 900 # 15 минут на всю сборку
|
||||||
|
|||||||
99
Dockerfile
99
Dockerfile
@@ -1,60 +1,71 @@
|
|||||||
# --- Stage 1: Сборка фронтенда (CodeMirror) ---
|
# -----------------------------------------------------------------------------
|
||||||
FROM node:20-slim as frontend-builder
|
# --- Этап 1: Сборщик (Builder) ---
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Используем официальный, но компактный образ Python как "строительную площадку".
|
||||||
|
# На этом этапе мы установим все зависимости, а потом скопируем только результат.
|
||||||
|
FROM python:3.13-slim as builder
|
||||||
|
|
||||||
WORKDIR /app/frontend
|
# Устанавливаем переменные окружения для Poetry
|
||||||
|
|
||||||
# Копируем файлы зависимостей
|
|
||||||
COPY frontend-assembly/package.json frontend-assembly/package-lock.json ./
|
|
||||||
|
|
||||||
# Устанавливаем зависимости (включая devDependencies для сборки)
|
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
# Копируем исходники
|
|
||||||
COPY frontend-assembly/ ./
|
|
||||||
|
|
||||||
# Собираем бандл через npm script
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
|
|
||||||
# --- Stage 2: Сборка бэкенда (Django) ---
|
|
||||||
FROM python:3.13-slim
|
|
||||||
|
|
||||||
# Настройки Python
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
# Эти настройки говорят Poetry создать виртуальное окружение прямо в папке проекта (/app/.venv)
|
||||||
|
ENV POETRY_NO_INTERACTION=1 \
|
||||||
|
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
||||||
|
POETRY_VIRTUALENVS_CREATE=1 \
|
||||||
|
POETRY_CACHE_DIR=/tmp/poetry_cache
|
||||||
|
|
||||||
|
# Устанавливаем саму Poetry
|
||||||
|
RUN pip install poetry
|
||||||
|
|
||||||
|
# Устанавливаем рабочую директорию внутри контейнера
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Установка Poetry
|
# Копируем только файлы зависимостей.
|
||||||
RUN pip install --no-cache-dir poetry
|
# Docker кэширует этот слой. Если эти файлы не меняются, Docker не будет
|
||||||
|
# переустанавливать все зависимости при каждой сборке.
|
||||||
|
COPY poetry.lock pyproject.toml ./
|
||||||
|
|
||||||
# Копируем файлы зависимостей
|
# Устанавливаем зависимости с помощью Poetry.
|
||||||
COPY pyproject.toml poetry.lock* /app/
|
# --no-root: не устанавливать сам проект (etpgrf-site) как пакет.
|
||||||
|
# --only main: устанавливать только основные зависимости (не dev).
|
||||||
|
RUN poetry install --no-interaction --no-ansi --no-root --only main
|
||||||
|
|
||||||
# Настройка Poetry: не создавать venv и установка зависимостей (без dev-зависимостей для продакшена)
|
# Очищаем кеш Poetry, чтобы он не попал в финальный образ.
|
||||||
RUN poetry config virtualenvs.create false \
|
RUN poetry cache clear --all -n
|
||||||
&& poetry install --no-interaction --no-ansi --no-root --only main
|
|
||||||
|
|
||||||
# Создаем непривилегированного пользователя
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# --- Этап 2: Финальный образ ---
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Начинаем с такого же чистого и легкого образа Python.
|
||||||
|
FROM python:3.13-slim
|
||||||
|
|
||||||
|
# Устанавливаем рабочую директорию
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Создаем непривилегированного пользователя для запуска приложения
|
||||||
RUN useradd -m -r appuser
|
RUN useradd -m -r appuser
|
||||||
|
# Устанавливаем владельца рабочей директории
|
||||||
# Копируем код проекта
|
|
||||||
COPY . /app/
|
|
||||||
|
|
||||||
# Создаем папку для данных и статики, чтобы у appuser были права
|
|
||||||
RUN mkdir -p /app/data /app/public/static_collected
|
|
||||||
|
|
||||||
# Копируем собранный фронтенд из первого стейджа
|
|
||||||
COPY --from=frontend-builder /app/frontend/dist/editor.js /app/public/static/codemirror/editor.js
|
|
||||||
|
|
||||||
# Меняем владельца папки
|
|
||||||
RUN chown -R appuser:appuser /app
|
RUN chown -R appuser:appuser /app
|
||||||
|
|
||||||
# Переключаемся на пользователя
|
# Копируем готовое виртуальное окружение из сборщика
|
||||||
|
COPY --from=builder /app/.venv ./.venv
|
||||||
|
|
||||||
|
# Устанавливаем PATH, чтобы использовать python из .venv
|
||||||
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
|
|
||||||
|
# Копируем весь код нашего приложения в рабочую директорию.
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Устанавливаем владельца для скопированных файлов
|
||||||
|
RUN chown -R appuser:appuser /app
|
||||||
|
|
||||||
|
# Переключаемся на непривилегированного пользователя
|
||||||
USER appuser
|
USER appuser
|
||||||
|
|
||||||
# Порт
|
# Сообщаем Docker, что наше приложение будет работать на порту 8000.
|
||||||
|
# Это нужно для `docker-compose`.
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# Команда запуска через Gunicorn
|
# ENTRYPOINT и CMD не указываем, так как команда запуска
|
||||||
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--chdir", "/app/etpgrf_site", "etpgrf_site.wsgi"]
|
# будет передана из docker-compose.prod.yml (docker-compose.yml).
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ services:
|
|||||||
etpgrf-backend:
|
etpgrf-backend:
|
||||||
# Используем готовый образ из Gitea Registry
|
# Используем готовый образ из Gitea Registry
|
||||||
image: git.cube2.ru/erjemin/2026-etpgrf-site:latest
|
image: git.cube2.ru/erjemin/2026-etpgrf-site:latest
|
||||||
|
# Если нужно, собрать образ из локального Dockerfile, а не скачивать готовый
|
||||||
|
# build: .
|
||||||
# Перезапускать всегда (если упал или сервер перезагрузился)
|
# Перезапускать всегда (если упал или сервер перезагрузился)
|
||||||
restart: always
|
restart: always
|
||||||
# Метка для Watchtower, чтобы он обновлял только этот контейнер
|
# Метка для Watchtower, чтобы он обновлял только этот контейнер
|
||||||
@@ -84,7 +86,6 @@ services:
|
|||||||
|
|
||||||
# Внешний порт. Если у тебя на хосте уже есть Nginx (прокси),
|
# Внешний порт. Если у тебя на хосте уже есть Nginx (прокси),
|
||||||
# то можно пробросить на 127.0.0.1:8000 или использовать внутреннюю сеть.
|
# то можно пробросить на 127.0.0.1:8000 или использовать внутреннюю сеть.
|
||||||
# Но пока оставим так:
|
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8080:80" # Используем 8080, чтобы не конфликтовать с Portainer (8000) или основным Nginx (80)
|
- "127.0.0.1:8080:80" # Используем 8080, чтобы не конфликтовать с Portainer (8000) или основным Nginx (80)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user