From 2eb6636ad15324c04e9de286ece0b15e2db41b7b Mon Sep 17 00:00:00 2001 From: erjemin Date: Tue, 14 Apr 2026 13:46:32 +0300 Subject: [PATCH] mod: add docker dev setup --- Dockerfile | 90 ++++++++++++++++++++++++++++++++++++++++ docker-compose.local.yml | 65 +++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.local.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..283767c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,90 @@ +# ================================================= +# STAGE 1: Builder - Установка зависимостей +# ================================================= +FROM python:3.12-slim AS builder + +# Устанавливаем переменные окружения +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV PIP_DEFAULT_TIMEOUT=100 + +# Устанавливаем Poetry +RUN pip install --no-cache-dir --default-timeout=100 --retries 10 poetry poetry-plugin-export + +# Создаем рабочую директорию +WORKDIR /app + +# Копируем только файлы зависимостей для кэширования этого слоя +COPY pyproject.toml poetry.lock /app/ + +# Экспортируем lock-файл в requirements.txt и ставим зависимости через pip. +# Это обычно быстрее и проще для Docker, чем полноценная установка через Poetry. +RUN poetry export --format requirements.txt --without-hashes --with dev --output /tmp/requirements.txt \ + && pip install --no-cache-dir --default-timeout=100 --retries 10 -r /tmp/requirements.txt + + +# ================================================= +# STAGE 2: Final - Создание чистого и безопасного образа +# ================================================= +FROM python:3.12-slim AS stage-final + +# Устанавливаем переменные окружения +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV DJANGO_SETTINGS_MODULE=cadpoint.settings + + +# Создаем пользователя без прав root для безопасности +# RUN addgroup --system app && adduser --system --ingroup app app + +# Создаем рабочую директорию +WORKDIR /home/app/web + +# Копируем установленные Python-пакеты из builder-стадии +COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages + +# Копируем исходный код проекта и устанавливаем правильного владельца +# ИЗМЕНЕНИЕ: app:app -> 1000:1000 +COPY --chown=1000:1000 . . + +# Создаём директорию для конфигов nginx и даём права пользователю app +# Это выполняется ещё от root, поэтому проблем с permissions не будет. +RUN mkdir -p /nginx_configs_host/nginx && chown -R 1000:1000 /nginx_configs_host + +# Создаём директорию для собранной статики и даём права пользователю app. +# `STATIC_ROOT` в settings.py живёт внутри `public`. +RUN mkdir -p /home/app/web/public/staticfiles && chown -R 1000:1000 /home/app/web/public + +# Создаём директорию для ошибок (404, 500) и даём права пользователю app +RUN mkdir -p /home/app/web/public/media/_error && chown -R 1000:1000 /home/app/web/public/media + +# Создаём директорию для БД и даём права пользователю app +# Это важно когда БД монтируется как том с хоста +RUN mkdir -p /home/app/web/database && chown -R 1000:1000 /home/app/web/database + +# Переключаемся на пользователя без прав root +USER 1000 + + +# Собираем статику +# Используем dummy ключ, так как .env файла нет на этапе сборки +RUN SECRET_KEY=dummy python cadpoint/manage.py collectstatic --noinput --clear + +# Открываем порт +EXPOSE 8000 + +# Проверка здоровья контейнера +# Docker будет периодически проверять, жив ли контейнер, отправляя GET запрос к главной странице. +# Параметры: +# --interval=30s - проверка каждые 30 секунд +# --timeout=3s - ожидаем ответ максимум 3 секунды +# --start-period=10s - даем контейнеру 10 секунд на запуск перед первой проверкой +# --retries=3 - объявляем контейнер unhealthy после 3 неудачных попыток +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()" || exit 1 + +# Переходим в директорию с manage.py для корректного запуска gunicorn +WORKDIR /home/app/web/cadpoint + +# Команда запуска (два воркера для лучшей производительности, можно увеличить до число ядер на хосте) +CMD ["python", "-m", "gunicorn", "--workers", "2", "--bind", "0.0.0.0:8000", "cadpoint.wsgi:application"] diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..d4ce512 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,65 @@ +# ============================================================================== +# Docker Compose для РАЗРАБОТКИ (Local Development) +# Этот файл содержит настройки для локальной работы (live reload, debug). +# Запуск: docker compose -f docker-compose.local up --build +# ============================================================================== + +services: + web: + # Имя контейнера для удобства + container_name: cadpoint-backend-dev + + # Сборка из текущей директории + build: . + + # Проброс портов (чтобы сайт был доступен на localhost:8055) + ports: + - "8055:8000" + + # 1. КОМАНДА ЗАПУСКА (Dev режим) + # Используем --reload для авто-перезагрузки при изменении кода. + # Уменьшаем число воркеров до 1 (ресурсы dev-машины можно не экономит, но одного достаточно). + # Убираем collectstatic (в dev Django сам может отдавать статику или она нам не так важна сжатой) + # Но миграции оставляем, чтобы база была актуальной. + command: > + sh -c "python manage.py migrate --noinput && + gunicorn --workers 1 --bind 0.0.0.0:8000 --reload cadpoint.wsgi:application" + + # 2. МОНТИРОВАНИЕ КОДА (Live Reload) + # Подключаем локальные папки внутрь контейнера, чтобы Gunicorn видел изменения без пересборки образа. + volumes: + # Монтируем основной код проекта. + # Так как web, templates и manage.py лежат внутри cadpoint/, одного этого маунта достаточно. + - ./cadpoint:/home/app/web/cadpoint + + # Монтируем всю папку public (Static + Media) + # Это нужно, чтобы: + # 1. Изменения в CSS/JS (public/static) сразу были видны (Live Reload). + # 2. Загруженные картинки (public/media) сохранялись на диске. + - ./public:/home/app/web/public + + # Монтируем базу данных (чтобы данные сохранялись при пересоздании контейнера) + # Используем ту же папку database, что и на проде, для единообразия. + # ВАЖНО: Django ищет базу в BASE_DIR.parent / 'database/db.sqlite3' + # В контейнере BASE_DIR=/home/app/web/cadpoint, значит путь к базе: /home/app/web/database/db.sqlite3 + - ./database:/home/app/web/database + + # 3. ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ + env_file: + # файл с переменными окружения для разработки + - .env + environment: + # на всякий случай, принудительно включаем DEBUG и DEBUG-уровень логов (вдруг в .env что-то не так) + - DEBUG=True + - DJANGO_LOG_LEVEL=DEBUG + # В dev нам не нужно ограничивать буферизацию так строго, но не помешает. + + # 4. РЕСУРСЫ (Без лимитов для разработки) + # Удаляем секцию ограничений, чтобы локально использовать все доступные ресурсы хоста. + # deploy: + # resources: + # limits: + # cpus: ... + # memory: ... + # mem_limit: ... +