feat: финальная конфигурация production Docker для RosmorPort
Some checks failed
Build and Push PetClones-site / build-and-push (push) Failing after 21s
Some checks failed
Build and Push PetClones-site / build-and-push (push) Failing after 21s
Обновлен Dockerfile: - Исправлены права доступа пользователя appuser (создание перед COPY) - Правильный порядок операций (USER -> COPY -> mkdir) - Оптимизация для production (workers=1, timeout=120, max-requests=200) - collectstatic и удаление лишних файлов статики при build Обновлен docker-compose.prod.yml: - Переименован контейнер в petclones-site--backend - Production переменные окружения (DEBUG=False) - Volumes для media, database и nginx конфигов - Gunicorn с параметрами для production - Watchtower для автоматического обновления образов - Ограничение ресурсов (0.25 CPU, 512M RAM) - JSON logging с ротаци??бновлен Dockerfile: - Исправлены права доступа пользователя appuser (создание перед COPY?? Исправлены пр?? Правильный порядок операций (USER -> COPY -> mkdir) - Оптимизация для prod
This commit is contained in:
18
.env.example
18
.env.example
@@ -15,18 +15,6 @@ ADMIN_URL=hidden-admin-panel/
|
|||||||
# ========================================
|
# ========================================
|
||||||
DB_NAME=database/db.sqlite3
|
DB_NAME=database/db.sqlite3
|
||||||
|
|
||||||
# ========================================
|
# Настройки достпа к пакетам в репозитории, чтобы wathtower мог проверять их свежесть и скачивать
|
||||||
# Пути для файлов автоматически вычисляются в settings.py
|
REPO_USER=xxxxx
|
||||||
# на основе PROJECT_ROOT (корень проекта)
|
REPO_PASS=xxxxx
|
||||||
# ========================================
|
|
||||||
# STATIC_ROOT вычисляется как: PROJECT_ROOT / 'public' / 'static'
|
|
||||||
# MEDIA_ROOT вычисляется как: PROJECT_ROOT / 'public' / 'media'
|
|
||||||
# Настройки почты (опционально)
|
|
||||||
# ========================================
|
|
||||||
# EMAIL_HOST=smtp.gmail.com
|
|
||||||
# EMAIL_PORT=587
|
|
||||||
# EMAIL_HOST_USER=your-email@gmail.com
|
|
||||||
# EMAIL_HOST_PASSWORD=your-app-password
|
|
||||||
# EMAIL_USE_TLS=True
|
|
||||||
# EMAIL_FROM=noreply@example.com
|
|
||||||
|
|
||||||
|
|||||||
35
Dockerfile
35
Dockerfile
@@ -39,14 +39,29 @@ ENV PATH="/opt/venv/bin:$PATH"
|
|||||||
# Устанавливаем рабочую директорию
|
# Устанавливаем рабочую директорию
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Устанавливаем пользователя для запуска приложения (из соображений безопасности)
|
||||||
|
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
|
||||||
|
USER appuser
|
||||||
|
|
||||||
# Копируем виртуальное окружение из builder
|
# Копируем виртуальное окружение из builder
|
||||||
COPY --from=builder /opt/venv /opt/venv
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
|
||||||
# Копируем содержимое проекта
|
# Копируем содержимое проекта
|
||||||
COPY . .
|
COPY --chown=appuser:appuser . .
|
||||||
|
|
||||||
# Создаём необходимые директории
|
# Создаём директорию для собранной статики и даём права пользователю app
|
||||||
RUN mkdir -p /app/public/media /app/public/static /app/database /app/staticfiles
|
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)
|
# Собираем статику при сборке образа (для production)
|
||||||
# Это гарантирует что статика готова и не нужно запускать collectstatic при старте
|
# Это гарантирует что статика готова и не нужно запускать collectstatic при старте
|
||||||
@@ -68,21 +83,17 @@ RUN find /app/staticfiles/webfonts -type f \( -name "*.ttf" -o -name "*.eot" -o
|
|||||||
# bootstrap.css, all.css, fontawesome.css используем только .min версии
|
# 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 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
|
|
||||||
USER appuser
|
|
||||||
|
|
||||||
# Открываем порт
|
# Открываем порт
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# CMD - выполняет миграции и запускает Gunicorn
|
# CMD - выполняет миграции и запускает Gunicorn
|
||||||
# Миграции выполняются при каждом запуске для гибкости
|
# Миграции выполняются при каждом запуске для гибкости
|
||||||
# Статика уже собрана при сборке образа
|
# Статика уже собрана при сборке образа
|
||||||
# Параметры оптимизированы для dev с минимальной нагрузкой:
|
# Параметры оптимизированы для минимальной нагрузкой (ветер качает, но не падает):
|
||||||
# - bind 0.0.0.0:8000 (все интерфейсы контейнера, необходимо для Docker проброса портов)
|
# - bind 0.0.0.0:8000 (все интерфейсы контейнера, необходимо для Docker проброса портов)
|
||||||
# - workers=1 (один worker - достаточно для dev без нагрузок)
|
# - workers=1 (один worker - достаточно если не будет нагрузок)
|
||||||
# - timeout=30 (сокращенный таймаут - запросы должны быть быстрыми)
|
# - timeout=120 (сокращенный таймаут - запросы должны быть быстрыми)
|
||||||
# - max-requests=100 (перезагрузка воркера после 100 запросов - экономия памяти)
|
# - max-requests=200 (перезагрузка воркера после 200 запросов - экономия памяти)
|
||||||
# - access-logfile/error-logfile '-' (логи в stdout для docker)
|
# - 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"]
|
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"]
|
||||||
|
|
||||||
|
|||||||
@@ -12,118 +12,99 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|
||||||
# Имя контейнера
|
# Имя контейнера
|
||||||
container_name: rosmorport_web_prod
|
container_name: petclones-site--backend
|
||||||
|
|
||||||
# Переменные окружения для production
|
# Переменные окружения для production
|
||||||
environment:
|
environment:
|
||||||
- DOCKER_ENV=1
|
- DOCKER_ENV=1
|
||||||
- DEBUG=False
|
- DEBUG=False
|
||||||
- ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0,web,pet-clones.cocorico.ru
|
|
||||||
- DB_ENGINE=django.db.backends.postgresql
|
|
||||||
- DB_HOST=db
|
|
||||||
- DB_PORT=5432
|
|
||||||
- DB_NAME=${POSTGRES_DB:-rosmorport_db}
|
|
||||||
- DB_USER=${POSTGRES_USER:-postgres}
|
|
||||||
- DB_PASSWORD=${POSTGRES_PASSWORD:-postgres}
|
|
||||||
- PYTHONUNBUFFERED=1
|
- PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
# Тома для медиа, статики и БД
|
# Тома для медиа, статики и БД
|
||||||
volumes:
|
volumes:
|
||||||
- public_media:/app/public/media
|
# Volume для media (загруженные пользователями файлы)
|
||||||
- public_static:/app/public/static
|
- media:/app/public/media:rw
|
||||||
- database:/app/database
|
# Volume для базы данных (SQLite файл)
|
||||||
|
- database:/app/database:rw
|
||||||
|
# Volume для экспорта конфигов из контейнера на хост
|
||||||
|
# Контейнер копирует nginx конфиг при запуске для настройки reverse-proxy на хосте
|
||||||
|
- ./config/nginx:/tmp/nginx_configs:rw # контейнер пишет сюда конфиги
|
||||||
|
|
||||||
|
# Command: скрипт для копирования конфигов из контейнера на хост при запуске
|
||||||
|
# Встроенный entrypoint nginx:alpine (/docker-entrypoint.sh) запустит это как команду
|
||||||
|
command: >
|
||||||
|
sh -c "
|
||||||
|
echo '📋 Копирование внешнего nginx конфига на хост...' &&
|
||||||
|
cp /tmp/pet-clones--external-nginx.conf.source /tmp/nginx_configs/pet-clones--external-nginx.conf.sample &&
|
||||||
|
echo '✅ Пример nginx-конфига создан в ./config/nginx/pet-clones--external-nginx.conf.sample (свежий из контейнера)' &&
|
||||||
|
if [ ! -f /tmp/nginx_configs/pet-clones--external-nginx.conf ]; then
|
||||||
|
cp /tmp/pet-clones--external-nginx.conf.source /tmp/nginx_configs/pet-clones--external-nginx.conf &&
|
||||||
|
echo '✅ Боевой nginx-конфиг создан в ./config/nginx/pet-clones--external-nginx.conf (свежий из контейнера)'
|
||||||
|
else
|
||||||
|
echo '⏭️ Боевой nginx-конфиг оставлен без изменений.'
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
"
|
||||||
|
|
||||||
# Перенаправляем порты
|
# Перенаправляем порты
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "127.0.0.1:8040:8000"
|
||||||
|
|
||||||
# Зависимость от базы данных
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
# Политика перезапуска
|
# Политика перезапуска
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Метки для Watchtower (авто-обновление)
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.scope=petclones-site--scope"
|
||||||
|
|
||||||
# Ограничения ресурсов
|
# Ограничения ресурсов
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpus: '1'
|
cpus: '0.25'
|
||||||
memory: 512M
|
memory: 512M
|
||||||
reservations:
|
|
||||||
cpus: '0.5'
|
|
||||||
memory: 256M
|
|
||||||
|
|
||||||
# PostgreSQL база данных для production
|
# Логирование в JSON-файлы (для сбора логов через docker logs)
|
||||||
db:
|
logging:
|
||||||
# Используем официальный образ PostgreSQL
|
driver: "json-file"
|
||||||
image: postgres:16-alpine
|
options:
|
||||||
container_name: rosmorport_db_prod
|
max-size: "5m" # больше лимит в продакшене для логирования
|
||||||
|
max-file: "1" # храним 1 файл лога
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- petclones-site--network
|
||||||
|
|
||||||
|
# WATCHTOWER ДЛЯ АВТОМАТИЧЕСКОГО ОБНОВЛЕНИЯ ОБРАЗОВ ИЗ РЕЕСТРА
|
||||||
|
watchtower:
|
||||||
|
image: containrrr/watchtower
|
||||||
|
container_name: petclones-site--watchtower
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
# Переменные окружения
|
# Переменные окружения
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_DB=${POSTGRES_DB:-rosmorport_db}
|
- DOCKER_API_VERSION=1.44
|
||||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
# Берем учетные данные из .env файла
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
|
- REPO_USER=${REPO_USER}
|
||||||
|
- REPO_PASS=${REPO_PASS}
|
||||||
# Том для хранения данных БД
|
# Ограничиваем область видимости только этим проектом
|
||||||
volumes:
|
- WATCHTOWER_SCOPE=petclones-site--scope
|
||||||
- postgres_data:/var/lib/postgresql/data
|
# Если нужно указать реестр явно (обычно watchtower сам понимает из имени образа)
|
||||||
|
# - WATCHTOWER_REGISTRY_URL=git.cube2.ru
|
||||||
# Портов не открываем - доступ только изнутри контейнеров
|
command: --interval 1800 --cleanup # Проверять каждые 30 минут
|
||||||
# ports:
|
logging:
|
||||||
# - "5432:5432"
|
driver: "json-file"
|
||||||
|
options:
|
||||||
# Проверка здоровья сервиса
|
max-size: "1m"
|
||||||
healthcheck:
|
max-file: "1"
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
|
networks:
|
||||||
interval: 10s
|
- petclones-site--network
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
# Политика перезапуска
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
# Ограничения ресурсов
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: '1'
|
|
||||||
memory: 1G
|
|
||||||
reservations:
|
|
||||||
cpus: '0.5'
|
|
||||||
memory: 512M
|
|
||||||
|
|
||||||
# Nginx для reverse proxy (опционально)
|
|
||||||
# nginx:
|
|
||||||
# image: nginx:alpine
|
|
||||||
# container_name: rosmorport_nginx
|
|
||||||
# volumes:
|
|
||||||
# - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
||||||
# - django_staticfiles:/app/static:ro
|
|
||||||
# - django_mediafiles:/app/media:ro
|
|
||||||
# ports:
|
|
||||||
# - "80:80"
|
|
||||||
# - "443:443"
|
|
||||||
# depends_on:
|
|
||||||
# - web
|
|
||||||
# restart: unless-stopped
|
|
||||||
|
|
||||||
# Именованные тома для хранения данных
|
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
driver: local
|
|
||||||
public_media:
|
|
||||||
driver: local
|
|
||||||
public_static:
|
|
||||||
driver: local
|
|
||||||
database:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
# Сеть для сервисов
|
# Сеть для сервисов
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
name: rosmorport_network
|
name: petclones-site--network
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user