# Dockerfile для Django приложения rosmorport_tsts # Многоэтапная сборка для оптимизации размера образа # Первый этап: builder - установка зависимостей FROM python:3.12-slim AS builder # Переводим в режим без буферизации для вывода логов ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 # Устанавливаем poetry RUN pip install --no-cache-dir poetry==1.8.3 # Устанавливаем рабочую директорию WORKDIR /app # Копируем файлы с информацией о зависимостях COPY pyproject.toml poetry.lock* ./ # Экспортируем зависимости из poetry в requirements.txt # Это более надежный способ в Docker, чем использование виртуального окружения poetry RUN poetry export -f requirements.txt --output requirements.txt --no-interaction # Создаем виртуальное окружение в стандартном месте RUN python -m venv /opt/venv # Устанавливаем зависимости в виртуальное окружение RUN /opt/venv/bin/pip install --no-cache-dir -r requirements.txt # Второй этап: runtime - финальный образ FROM python:3.12-slim # Переводим в режим без буферизации для вывода логов ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 # Установка PATH для виртуального окружения перед копированием ENV PATH="/opt/venv/bin:$PATH" # Устанавливаем рабочую директорию WORKDIR /app # Устанавливаем пользователя для запуска приложения (из соображений безопасности) RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app USER appuser # Копируем виртуальное окружение из builder COPY --from=builder /opt/venv /opt/venv # Копируем содержимое проекта COPY --chown=appuser:appuser . . # Создаём директорию для собранной статики и даём права пользователю app RUN mkdir -p /app/staticfiles && chown -R appuser:appuser /app/staticfiles # Создаём директорию для media RUN mkdir -p /app/public/media && chown -R appuser:appuser /app/public/media # Создаём директорию для БД и даём права пользователю app # Это важно когда БД монтируется как том с хоста RUN mkdir -p /app/database && chown -R appuser:appuser /app/database # Копируем внешний nginx конфиг для экспорта на хост (через volume) # Это нужно для настройки reverse-proxy на хосте COPY config/nginx/pet-clones--external-nginx.conf /tmp/pet-clones--external-nginx.conf.source # Собираем статику при сборке образа (для production) # Это гарантирует что статика готова и не нужно запускать collectstatic при старте # PATH уже установлен в переменных окружения выше, поэтому Django должен быть найден RUN cd /app/rosmorport_tsts && \ python manage.py collectstatic --noinput --clear --no-input # Оптимизация размера контейнера: удаляем лишние файлы статики # Source maps нужны только для разработки RUN find /app/staticfiles -name "*.map" -delete # Удаляем RTL версии Bootstrap (если проект не поддерживает RTL) RUN find /app/staticfiles -name "*rtl*" -type f -delete # Удаляем TTF и EOT шрифты (используем только woff2 - меньше размер) RUN find /app/staticfiles/webfonts -type f \( -name "*.ttf" -o -name "*.eot" -o -name "*.svg" \) -delete # Удаляем неминифицированные версии CSS (кроме нашего собственного rosmorport.css) # bootstrap.css, all.css, fontawesome.css используем только .min версии RUN find /app/staticfiles/css -maxdepth 1 -name "*.css" -not -name "*.min.css" -not -name "rosmorport.css" -delete # Открываем порт EXPOSE 8000 # CMD - выполняет миграции и запускает Gunicorn # Миграции выполняются при каждом запуске для гибкости # Статика уже собрана при сборке образа # Параметры оптимизированы для минимальной нагрузкой (ветер качает, но не падает): # - bind 0.0.0.0:8000 (все интерфейсы контейнера, необходимо для Docker проброса портов) # - workers=1 (один worker - достаточно если не будет нагрузок) # - timeout=120 (сокращенный таймаут - запросы должны быть быстрыми) # - max-requests=200 (перезагрузка воркера после 200 запросов - экономия памяти) # - access-logfile/error-logfile '-' (логи в stdout для docker) CMD ["sh", "-c", "cd /app/rosmorport_tsts && echo '>>> Applying database migrations...' && python manage.py migrate --noinput && echo '>>> Starting Gunicorn...' && gunicorn --bind 0.0.0.0:8000 --workers 1 --worker-class sync --worker-tmp-dir /dev/shm --max-requests 200 --timeout 120 --access-logfile - --error-logfile - rosmorport_tsts.wsgi:application"]