Добавил разделение баз данных. Ну и первая попытка настроить деплой
Some checks failed
Auto-Deploy-prodman / deploy (push) Failing after 1s
Some checks failed
Auto-Deploy-prodman / deploy (push) Failing after 1s
This commit is contained in:
10
.env
Normal file
10
.env
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Настройки базы данных
|
||||||
|
DB_NAME=prodman_db
|
||||||
|
DB_USER=prodman_user
|
||||||
|
DB_PASS=prodman_password_zwE45t!
|
||||||
|
|
||||||
|
# Настройки Django
|
||||||
|
ENV_TYPE=server
|
||||||
|
DB_HOST=db
|
||||||
|
# todo потом установить домен для продакшена
|
||||||
|
ALLOWED_HOSTS=yourdomain.com,123.123.123.123,web
|
||||||
15
.gitea/workflows/deploy.yaml
Normal file
15
.gitea/workflows/deploy.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: Auto-Deploy-prodman
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: host-shell # Твоя новая метка!
|
||||||
|
steps:
|
||||||
|
- name: Shell Deploy
|
||||||
|
run: |
|
||||||
|
cd /home/ack/projects/prodman
|
||||||
|
git pull origin main
|
||||||
|
docker compose up -d --build
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -30,7 +30,7 @@ staticfiles/ # Собранные статические файлы (collects
|
|||||||
*.pot
|
*.pot
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
# .env
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
|
|||||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
gcc libpq-dev && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Копируем скрипт входа
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
|
||||||
|
# Команда по умолчанию
|
||||||
|
CMD ["gunicorn", "core.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
|
||||||
@@ -13,8 +13,8 @@ class BaseOperation(PolymorphicModel):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['order']
|
ordering = ['order']
|
||||||
verbose_name = "Операция"
|
verbose_name = "Технологическая операция"
|
||||||
verbose_name_plural = "Операции"
|
verbose_name_plural = "Технологический маршрут"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.order}. {self._meta.verbose_name}"
|
return f"{self.order}. {self._meta.verbose_name}"
|
||||||
@@ -35,6 +35,8 @@ class LaserCutSheet(BaseOperation):
|
|||||||
pierces = models.IntegerField("Количество проколов", default=1)
|
pierces = models.IntegerField("Количество проколов", default=1)
|
||||||
dxf_file = models.FileField("DXF файл", upload_to='dxf_files/%Y/%m', null=True, blank=True)
|
dxf_file = models.FileField("DXF файл", upload_to='dxf_files/%Y/%m', null=True, blank=True)
|
||||||
|
|
||||||
|
#todo: добавить использование азота
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self.cut_length < 1:
|
if self.cut_length < 1:
|
||||||
raise ValidationError("Длина реза должна быть больше 0!")
|
raise ValidationError("Длина реза должна быть больше 0!")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/6.0/ref/settings/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
@@ -22,10 +23,19 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure-5(p6^by%ax10=(ev#ltdb8#f4@mq4&9gqnjvr9dboc=7t_&sbf'
|
SECRET_KEY = 'django-insecure-5(p6^by%ax10=(ev#ltdb8#f4@mq4&9gqnjvr9dboc=7t_&sbf'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# читаем переменную окружения
|
||||||
DEBUG = True
|
ENV_TYPE = os.getenv('ENV_TYPE', 'local')
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
# Настройки безопасности
|
||||||
|
# DEBUG будет True везде, кроме сервера
|
||||||
|
DEBUG = ENV_TYPE != 'server'
|
||||||
|
|
||||||
|
if not DEBUG:
|
||||||
|
# На сервере список хостов должен быть ограничен
|
||||||
|
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
|
||||||
|
else:
|
||||||
|
# Для разработки разрешаем всё
|
||||||
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
@@ -57,7 +67,9 @@ ROOT_URLCONF = 'core.urls'
|
|||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [BASE_DIR / 'templates'],
|
'DIRS': [
|
||||||
|
os.path.join(BASE_DIR, 'templates'),
|
||||||
|
],
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
@@ -71,16 +83,42 @@ TEMPLATES = [
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'core.wsgi.application'
|
WSGI_APPLICATION = 'core.wsgi.application'
|
||||||
|
|
||||||
|
print(f"DEBUG: Current ENV_TYPE is {ENV_TYPE}")
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
|
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
|
||||||
|
|
||||||
DATABASES = {
|
if ENV_TYPE == 'server':
|
||||||
'default': {
|
# Для Docker на удаленном сервере (максимальная защита через .env)
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
DATABASES = {
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
|
'NAME': os.getenv('DB_NAME'),
|
||||||
|
'USER': os.getenv('DB_USER'),
|
||||||
|
'PASSWORD': os.getenv('DB_PASS'),
|
||||||
|
'HOST': os.getenv('DB_HOST', 'db'),
|
||||||
|
'PORT': '5432',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elif ENV_TYPE == 'dev':
|
||||||
|
# Настройки для локальной разработки с внешней БД
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
|
'NAME': 'prodman_dev_db',
|
||||||
|
'USER': 'dev_user',
|
||||||
|
'PASSWORD': 'dev_password',
|
||||||
|
'HOST': '192.168.1.90', # локальный сервер БД
|
||||||
|
'PORT': '5432',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Режим "на коленке"
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
@@ -117,4 +155,9 @@ USE_TZ = True
|
|||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/6.0/howto/static-files/
|
# https://docs.djangoproject.com/en/6.0/howto/static-files/
|
||||||
|
|
||||||
|
# --- Статика и Медиа ---
|
||||||
STATIC_URL = 'static/'
|
STATIC_URL = 'static/'
|
||||||
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
|
||||||
|
MEDIA_URL = 'media/'
|
||||||
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|||||||
53
docker-compose.yml
Normal file
53
docker-compose.yml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: prodman
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${DB_NAME}
|
||||||
|
- POSTGRES_USER=${DB_USER}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASS}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
# Загружаем переменные окружения в settings.py
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
# Пока не убираем, вопрос возникает о дбхосте
|
||||||
|
|
||||||
|
# environment:
|
||||||
|
# - ENV_TYPE={ENV_TYPE}
|
||||||
|
# - DB_NAME={DB_NAME}
|
||||||
|
# - DB_USER={DB_USER}
|
||||||
|
# - DB_PASS={DB_PASS}
|
||||||
|
# - DB_HOST=db
|
||||||
|
volumes:
|
||||||
|
- staticfiles:/app/staticfiles # Сюда статику
|
||||||
|
- mediafiles:/app/media # Сюда медиа
|
||||||
|
# - .:/app
|
||||||
|
expose:
|
||||||
|
- "8000"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.25-alpine
|
||||||
|
volumes:
|
||||||
|
# Подключаем конфиг и статику с медиа в режиме только для чтения (т.к. nginx смотрит в интернет и может быть подвергнута атаке)
|
||||||
|
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
- staticfiles:/app/staticfiles:ro
|
||||||
|
- mediafiles:/app/media:ro
|
||||||
|
ports:
|
||||||
|
- "8081:80"
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
staticfiles:
|
||||||
|
mediafiles:
|
||||||
13
entrypoint.sh
Normal file
13
entrypoint.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Собираем статику
|
||||||
|
echo "Collecting static files..."
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
# Применяем миграции базы данных
|
||||||
|
echo "Applying database migrations..."
|
||||||
|
python manage.py migrate --noinput
|
||||||
|
|
||||||
|
# Запускаем основную команду (Gunicorn)
|
||||||
|
echo "Starting Gunicorn..."
|
||||||
|
exec "$@"
|
||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user