diff --git a/.dockerignore b/.dockerignore index 57185f2..1bf2cee 100644 --- a/.dockerignore +++ b/.dockerignore @@ -66,6 +66,52 @@ my_anwer.txt requare_dev_prod.txt requare_dev_w_home.txt +# Оптимизация статики - исключаем лишние файлы для компактного контейнера + +# Source maps (нужны только для разработки, не для production) +public/static/**/*.map +staticfiles/**/*.map + +# RTL версии Bootstrap (если не используется для арабских/персидских языков) +public/static/css/bootstrap*.rtl.* +public/static/css/v*.rtl.* +staticfiles/css/bootstrap*.rtl.* +staticfiles/css/v*.rtl.* + +# TTF шрифты - используем только woff2 (меньше размер, лучше поддержка в браузерах) +public/static/webfonts/*.ttf +public/static/webfonts/*.eot +public/static/webfonts/*.svg +staticfiles/webfonts/*.ttf +staticfiles/webfonts/*.eot +staticfiles/webfonts/*.svg + +# Обычные (неминифицированные) версии CSS для bootstrap - используем только min версии +# (но оставляем rosmorport.css - наш проектный CSS) +# bootstrap.css, bootstrap-grid.css, bootstrap-utilities.css, etc +public/static/css/bootstrap.css +public/static/css/bootstrap-grid.css +public/static/css/bootstrap-utilities.css +public/static/css/bootstrap-reboot.css +public/static/css/v*.css +public/static/css/svg-with-js.css +public/static/css/fontawesome.css +public/static/css/regular.css +public/static/css/solid.css +public/static/css/brands.css +public/static/css/all.css +staticfiles/css/bootstrap.css +staticfiles/css/bootstrap-grid.css +staticfiles/css/bootstrap-utilities.css +staticfiles/css/bootstrap-reboot.css +staticfiles/css/v*.css +staticfiles/css/svg-with-js.css +staticfiles/css/fontawesome.css +staticfiles/css/regular.css +staticfiles/css/solid.css +staticfiles/css/brands.css +staticfiles/css/all.css + # Прочее config/ .editorconfig diff --git a/Dockerfile b/Dockerfile index e05d7b8..b64233e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,10 +17,15 @@ 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 -ENV PATH="/opt/venv/bin:$PATH" -RUN poetry install --no-interaction --no-ansi + +# Устанавливаем зависимости в виртуальное окружение +RUN /opt/venv/bin/pip install --no-cache-dir -r requirements.txt # Второй этап: runtime - финальный образ FROM python:3.12-slim @@ -28,6 +33,8 @@ FROM python:3.12-slim # Переводим в режим без буферизации для вывода логов ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 +# Установка PATH для виртуального окружения перед копированием +ENV PATH="/opt/venv/bin:$PATH" # Устанавливаем рабочую директорию WORKDIR /app @@ -35,14 +42,31 @@ WORKDIR /app # Копируем виртуальное окружение из builder COPY --from=builder /opt/venv /opt/venv -# Добавляем путь к виртуальному окружению -ENV PATH="/opt/venv/bin:$PATH" - # Копируем содержимое проекта COPY . . # Создаём необходимые директории -RUN mkdir -p /app/public/media /app/public/static /app/database +RUN mkdir -p /app/public/media /app/public/static /app/database /app/staticfiles + +# Собираем статику при сборке образа (для 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 # Устанавливаем пользователя для запуска приложения (из соображений безопасности) RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app @@ -51,7 +75,14 @@ USER appuser # Открываем порт EXPOSE 8000 -# CMD - выполняет миграции, собирает статику и запускает Gunicorn -# Использует sh для выполнения нескольких команд последовательно -CMD ["sh", "-c", "cd /app/rosmorport_tsts && echo '>>> Applying database migrations...' && python manage.py migrate --noinput && echo '>>> Collecting static files...' && python manage.py collectstatic --noinput --clear && echo '>>> Starting Gunicorn...' && gunicorn --bind 0.0.0.0:8000 --workers 4 --worker-class sync --worker-tmp-dir /dev/shm --max-requests 1000 --timeout 60 --access-logfile - --error-logfile - rosmorport_tsts.wsgi:application"] +# CMD - выполняет миграции и запускает Gunicorn +# Миграции выполняются при каждом запуске для гибкости +# Статика уже собрана при сборке образа +# Параметры оптимизированы для dev с минимальной нагрузкой: +# - bind 0.0.0.0:8000 (все интерфейсы контейнера, необходимо для Docker проброса портов) +# - workers=1 (один worker - достаточно для dev без нагрузок) +# - timeout=30 (сокращенный таймаут - запросы должны быть быстрыми) +# - max-requests=100 (перезагрузка воркера после 100 запросов - экономия памяти) +# - 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 100 --timeout 30 --access-logfile - --error-logfile - rosmorport_tsts.wsgi:application"] diff --git a/docker-compose.yml b/docker-compose.yml index c501b8f..ec51234 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,7 @@ # docker-compose.yml для локальной разработки проекта rosmorport_tsts -version: '3.9' +# Использование: docker-compose up + +# version: '3.9' services: # Django приложение @@ -10,60 +12,27 @@ services: dockerfile: Dockerfile # Имя контейнера - container_name: rosmorport_web - + container_name: rosmorpor-tst-site--backend + # Переменные окружения для разработки + env_file: + - .env environment: - DOCKER_ENV=1 + - DJANGO_LOG_LEVEL=DEBUG - DEBUG=True - - ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0,web - - DB_ENGINE=django.db.backends.sqlite3 - - DB_NAME=/app/db.sqlite3 - PYTHONUNBUFFERED=1 # Монтируем текущую директорию для разработки volumes: - .:/app - - ./public/static:/app/public/static - ./public/media:/app/public/media - ./database:/app/database # Перенаправляем порты ports: - - "8000:8000" + - "127.0.0.1:8040:8000" - # Команда для запуска в режиме разработки - command: > - sh -c "python rosmorport_tsts/manage.py migrate && - python rosmorport_tsts/manage.py collectstatic --noinput && - python rosmorport_tsts/manage.py runserver 0.0.0.0:8000" - - # Зависимости (если будут другие сервисы) - # depends_on: - # - db - - # Сохраняем контейнер в запущенном состоянии при ошибках - stdin_open: true - tty: true - - # Опционально: PostgreSQL база данных для продакшена - # db: - # image: postgres:16-alpine - # container_name: rosmorport_db - # environment: - # - POSTGRES_DB=rosmorport_db - # - POSTGRES_USER=postgres - # - POSTGRES_PASSWORD=postgres - # volumes: - # - postgres_data:/var/lib/postgresql/data - # ports: - # - "5432:5432" - # healthcheck: - # test: ["CMD-SHELL", "pg_isready -U postgres"] - # interval: 10s - # timeout: 5s - # retries: 5 - # Именованные тома для хранения данных volumes: django_staticfiles: diff --git a/rosmorport_tsts/rosmorport_tsts/settings.py b/rosmorport_tsts/rosmorport_tsts/settings.py index e9cc8a4..f04e9f8 100644 --- a/rosmorport_tsts/rosmorport_tsts/settings.py +++ b/rosmorport_tsts/rosmorport_tsts/settings.py @@ -110,6 +110,12 @@ TEMPLATES = [ WSGI_APPLICATION = 'rosmorport_tsts.wsgi.application' +# CSRF Configuration +# CSRF_TRUSTED_ORIGINS используется для Docker, Nginx и других reverse proxy +# Содержит список разрешенных источников для CSRF защиты (разделенные запятой) +csrf_trusted_origins = get_env('CSRF_TRUSTED_ORIGINS', 'http://127.0.0.1:8000,http://localhost:8000') +CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in csrf_trusted_origins.split(',')] + # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases @@ -123,6 +129,12 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': str(db_path), + # Таймауты для SQLite - оптимизированы для быстрых операций без нагрузок + 'OPTIONS': { + 'timeout': 5, # Таймаут ожидания блокировки БД (в секундах) + }, + # Параметры пула подключений (не критичны для SQLite, но для совместимости) + 'CONN_MAX_AGE': 60, # Время жизни подключения (60 сек) } }