From 4b6a0f9c96edee44de74fe713a112b2219091aad Mon Sep 17 00:00:00 2001 From: ack Date: Sun, 19 Apr 2026 09:46:18 +0300 Subject: [PATCH] Initial commit: setup deploy workflow --- .gitea/workflows/deploy.yaml | 25 +++++++++++++++ .gitignore | 2 ++ Dockerfile | 41 ++++++++++++++++++++++++ docker-compose.yml | 62 ++++++++++++++++++++++++++++++++++++ entrypoint.sh | 15 +++++++++ main.py | 0 nginx/default.conf | 57 +++++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+) create mode 100644 .gitea/workflows/deploy.yaml create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 entrypoint.sh create mode 100644 main.py create mode 100644 nginx/default.conf diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..5f8c445 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,25 @@ +name: Deploy timelaps +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + deploy: + runs-on: LabOnDeb + steps: + - name: Shell Deploy + run: | + # 1. Создаем папку, если её нет + mkdir -p /home/ack/projects/timelaps + cd /home/ack/projects/timelaps + + # 2. Обновляем код напрямую через git (без checkout action) + if [ -d ".git" ]; then + git pull origin main + else + git clone https://gitea.tertelius.space/ack/timelaps.git . + fi + + # 3. Запускаем сборку + docker compose up -d --build \ No newline at end of file diff --git a/.gitignore b/.gitignore index 36b13f1..e8063da 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,5 @@ cython_debug/ # PyPI configuration file .pypirc +#vscode files +.vscode/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f5af2c0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# Используем "легкую" версию Python на базе Debian Bookworm. +# slim — это баланс между размером образа и наличием нужных утилит. +FROM python:3.12-slim + +# Указываем рабочую папку внутри контейнера. Все последующие команды будут выполняться в ней. +WORKDIR /app + +# Настройки окружения: +# 1. Запрещаем Python писать файлы .pyc (байткод) на диск, чтобы не мусорить. +ENV PYTHONDONTWRITEBYTECODE=1 +# 2. Отключаем буферизацию логов. Так ты сразу увидишь ошибки в `docker logs`, а не будешь их ждать. +ENV PYTHONUNBUFFERED=1 + +# Ставим системные зависимости: +# apt-get update — обновляем списки пакетов. +# gcc и libpq-dev — необходимы для сборки библиотеки psycopg2 (драйвер для Postgres). +# rm -rf /var/lib/apt/lists/* — удаляем кэш установщика, чтобы уменьшить размер образа. +RUN apt-get update && apt-get install -y --no-install-recommends \ + ffmpeg \ + && rm -rf /var/lib/apt/lists/* + +# Сначала копируем только список зависимостей. +# Это нужно для "кэширования слоев": если ты не менял библиотеки, Docker не будет переустанавливать их заново при сборке. +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Теперь копируем весь остальной код проекта в контейнер. +COPY . . + +# Даем права на выполнение нашему скрипту запуска. +# Без этого контейнер может упасть с ошибкой "Permission denied". +RUN chmod +x /app/entrypoint.sh + +# ENTRYPOINT — это команда, которая выполняется ВСЕГДА при старте. +# Наш скрипт подготовит базу (миграции) и соберет статику. +ENTRYPOINT ["/app/entrypoint.sh"] + +# CMD — это основная команда процесса. +# Запускаем Gunicorn, привязываем его к порту 8000 и ставим 3 рабочих процесса для скорости. +CMD ["gunicorn", "core.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3", "--timeout", "120"] +# Увеличиваем tineout до 120 секунд. Сборка видео может занять больше времени, чем 60 секунд. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0246ef2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,62 @@ +name: prodman # Имя проекта, которое будет префиксом для всех контейнеров и сетей + +services: + # --- БАЗА ДАННЫХ --- + # db: + # image: postgres:15-alpine # Легкий образ Postgres на базе Alpine Linux + # restart: unless-stopped # Перезапускать всегда, кроме случаев, когда ты сам его выключил + # environment: + # # Данные тянутся из твоего файла .env + # - POSTGRES_DB=${DB_NAME} + # - POSTGRES_USER=${DB_USER} + # - POSTGRES_PASSWORD=${DB_PASS} + # volumes: + # # Храним базу в именованном томе, чтобы данные не пропали при удалении контейнера + # - postgres_data:/var/lib/postgresql/data + + # --- ПРИЛОЖЕНИЕ (DJANGO) --- + web: + build: . # Собирает образ из Dockerfile в текущей папке + restart: unless-stopped + environment: + - ENV_TYPE=server + env_file: + - .env # Прокидывает все секреты и настройки внутрь Python + volumes: + # Общие папки для статики и картинок. Сюда Django их складывает. + - staticfiles:/app/staticfiles + - mediafiles:/app/media + expose: + - "8000" # Открывает порт ТОЛЬКО внутри сети Docker для Nginx + + # --- ВЕБ-СЕРВЕР (ФАСАД) --- + nginx: + image: nginx:1.25-alpine + restart: unless-stopped + volumes: + # Основной конфиг маршрутизации + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + # Читаем статику и медиа, которые подготовил контейнер 'web' + # :ro (read-only) — защита: даже если Nginx взломают, файлы не удалят + - staticfiles:/app/staticfiles:ro + - mediafiles:/app/media:ro + ports: + - "80:80" # Единственная "дырка" в мир: порт 80 сервера -> порт 80 контейнера + depends_on: + - web # Nginx запустится только после Django + +# Описание "жестких дисков" (Volumes), которые живут дольше контейнеров +volumes: + postgres_data: # Для данных БД + staticfiles: # Для CSS, JS и картинок интерфейса (collectstatic) + mediafiles: # Для загруженных тобой чертежей и фото + +# Подключение NFS-шары напрямую в Docker + nfs_motioneye: + driver: local + driver_opts: + type: nfs + # IP адрес твоего NAS или сервера, где лежит шара + o: addr=192.168.1.138,rw,nolock,soft + # Путь к папке на самом NFS сервере + device: ":/VideoStreaming" \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..c9c5a38 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Собираем статику в папку, которую увидит Nginx +echo "Collecting static files..." +python manage.py collectstatic --noinput + +# Миграции +echo "Applying database migrations..." +python manage.py migrate --noinput + +# Создаем админа (из переменных .env) +python manage.py createsuperuser --no-input || true + +echo "Starting Gunicorn..." +exec "$@" \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..e69de29 diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 0000000..1c79295 --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,57 @@ +# Описываем группу серверов, куда Nginx будет перекидывать запросы. +# 'web' — это имя сервиса из нашего docker-compose.yml. +upstream django_app { + server web:8000; +} + +server { + # Слушаем стандартный 80-й порт (HTTP). + listen 80; + + # Список имен, на которые будет откликаться сервер. + # Если зайти по другому IP, Nginx может выдать ошибку. + server_name shiftflow.tertelius.space 192.168.1.108 localhost; + + # Увеличиваем лимит загрузки (по умолчанию в Nginx всего 1МБ). + # 100М — чтобы ты мог спокойно грузить тяжелые чертежи или фото станков. + client_max_body_size 100M; + + # Включаем Gzip-сжатие. Nginx будет сжимать текстовые файлы перед отправкой, + # что ускорит загрузку интерфейса, особенно на слабом интернете. + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml; + + # Главный блок: всё, что не статика, летит в Django. + location / { + proxy_pass http://django_app; + + # Передаем оригинальный домен/IP (нужно для ALLOWED_HOSTS в Django). + proxy_set_header Host $host; + # Передаем реальный IP пользователя (чтобы в логах видеть, кто зашел). + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # Передаем протокол (http или https). + # КРИТИЧНО для CSRF защиты, чтобы Django не ругался при входе в админку. + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_redirect off; + } + + # Раздача статики (CSS, JS, картинки интерфейса). + # Nginx сам лезет в папку, не беспокоя Django — это очень быстро. + location /static/ { + # Путь ВНУТРИ контейнера Nginx (куда мы примонтировали волюм). + alias /app/staticfiles/; + # Заставляем браузер кэшировать стили на 30 дней, чтобы не качать их каждый раз. + expires 30d; + add_header Cache-Control "public, no-transform"; + } + + # Раздача медиа-файлов (чертежи, фото продукции). + location /media/ { + alias /app/media/; + expires 30d; + add_header Cache-Control "public, no-transform"; + } +} \ No newline at end of file