add: Production docker-compose.yml с nginx и watchtower + инструкция деплоя
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
This commit is contained in:
239
PRODUCTION_DEPLOY.md
Normal file
239
PRODUCTION_DEPLOY.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# Production Deployment Guide для Oknardia
|
||||
|
||||
## Структура на хосте
|
||||
|
||||
Структура директорий на production сервере должна быть:
|
||||
|
||||
```
|
||||
~/docker-app/oknardia-site/
|
||||
├── .env # Переменные окружения Django
|
||||
├── config/ # Конфиги
|
||||
│ └── nginx/
|
||||
│ └── oknardia-app--external-nginx.conf # Конфиг Nginx (шаблон)
|
||||
├── database/ # БД SQLite (создается автоматически)
|
||||
│ └── oknardia.sqlite3
|
||||
├── media/ # Медиа файлы, uploads, кеши
|
||||
│ ├── img_avatar/
|
||||
│ ├── img_seria/
|
||||
│ ├── _serv_sitemap/
|
||||
│ └── _error/ # Error pages (генерируются контейнером)
|
||||
└── docker-compose.prod.yml # Конфиг Docker
|
||||
```
|
||||
|
||||
## Установка на Production сервере
|
||||
|
||||
### 1. Создать директории и скопировать файлы
|
||||
|
||||
```bash
|
||||
# На хосте
|
||||
mkdir -p ~/docker-app/oknardia-site/{config/nginx,database,media}
|
||||
|
||||
# Скопировать docker-compose.prod.yml и .env из проекта
|
||||
cp docker-compose.prod.yml ~/docker-app/oknardia-site/
|
||||
cp .env ~/docker-app/oknardia-site/
|
||||
|
||||
# Скопировать конфиг nginx
|
||||
cp config/nginx/oknardia-app--external-nginx.conf ~/docker-app/oknardia-site/config/nginx/
|
||||
```
|
||||
|
||||
### 2. Настроить .env на сервере
|
||||
|
||||
Отредактировать `~/docker-app/oknardia-site/.env`:
|
||||
|
||||
```bash
|
||||
# Критично: должны быть правильные credentials для реестра Gitea
|
||||
REPO_USER=erjemin
|
||||
REPO_PASS=<сгенерированный токен из личного кабинета>
|
||||
|
||||
# Критично: переменная с путем проекта для sed в конфиге nginx
|
||||
export HOST_PROJECT_PATH=/home/default_user/projects/oknardia-site
|
||||
# (если путь другой, обновить эту переменную)
|
||||
|
||||
# Остальное можно скопировать из локального .env
|
||||
DEBUG=False
|
||||
DJANGO_SECRET_KEY=...
|
||||
```
|
||||
|
||||
### 3. Запустить контейнеры
|
||||
|
||||
```bash
|
||||
cd ~/docker-app/oknardia-site/
|
||||
|
||||
# Первый запуск (холодный старт)
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# Проверить логи
|
||||
docker compose -f docker-compose.prod.yml logs -f web
|
||||
|
||||
# Проверить статус контейнеров
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
```
|
||||
|
||||
### 4. Проверить что nginx конфиг был сгенерирован
|
||||
|
||||
После первого запуска контейнер должен:
|
||||
- Создать `/config/nginx/oknardia-app--external-nginx.conf` (боевой конфиг)
|
||||
- Создать `/config/nginx/oknardia-app--external-nginx.conf.example` (exemplo)
|
||||
|
||||
```bash
|
||||
ls -la ~/docker-app/oknardia-site/config/nginx/
|
||||
```
|
||||
|
||||
### 5. Настроить Nginx на хосте
|
||||
|
||||
На хосте установить Nginx и скопировать/ссылаться на конфиг из контейнера:
|
||||
|
||||
```bash
|
||||
# На хосте (например, Ubuntu 20.04)
|
||||
sudo systemctl install nginx
|
||||
|
||||
# Включить сгенерированный конфиг в основной конфиг Nginx
|
||||
# /etc/nginx/sites-available/oknardia или /etc/nginx/conf.d/oknardia.conf
|
||||
|
||||
# Пример:
|
||||
sudo ln -s /home/default_user/projects/oknardia-site/config/nginx/oknardia-app--external-nginx.conf \
|
||||
/etc/nginx/sites-enabled/oknardia
|
||||
|
||||
# Проверить и перезагрузить Nginx
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## Команды для управления
|
||||
|
||||
```bash
|
||||
cd ~/docker-app/oknardia-site/
|
||||
|
||||
# Запустить контейнеры (если они были остановлены)
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# Остановить контейнеры
|
||||
docker compose -f docker-compose.prod.yml down
|
||||
|
||||
# Перезагрузить контейнеры (удалить и создать заново)
|
||||
docker compose -f docker-compose.prod.yml down
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# Посмотреть логи
|
||||
docker compose -f docker-compose.prod.yml logs -f web
|
||||
docker compose -f docker-compose.prod.yml logs -f watchtower
|
||||
|
||||
# Выполнить команду внутри контейнера Django
|
||||
docker compose -f docker-compose.prod.yml exec web python manage.py shell
|
||||
|
||||
# Пересоздать пре-рендер кеши вручную
|
||||
docker compose -f docker-compose.prod.yml exec web python manage.py regenerate_seria_prerender
|
||||
```
|
||||
|
||||
## Что делает docker-compose.prod.yml
|
||||
|
||||
### Сервис `web` (Django + Gunicorn)
|
||||
|
||||
При старте контейнера:
|
||||
1. ✅ Применяет миграции БД (`migrate --noinput`)
|
||||
2. ✅ Собирает статику (`collectstatic --noinput`)
|
||||
3. ✅ Генерирует sitemap'ы (`generate_sitemaps`)
|
||||
4. ✅ Пересоздает пре-рендер кеши для серий (`regenerate_seria_prerender`)
|
||||
5. ✅ Пересчитывает рейтинги (`make_rating`)
|
||||
6. ✅ Копирует конфиг nginx с авто-заменой путей (через `sed`)
|
||||
7. ✅ Запускает Gunicorn на `127.0.0.1:8000`
|
||||
|
||||
### Сервис `watchtower` (авто-обновление)
|
||||
|
||||
- 👁️ Следит за реестром Gitea (проверка каждые 30 минут)
|
||||
- 🔄 Автоматически скачивает новый образ, если он есть
|
||||
- ♻️ По-graceful перезагружает контейнер web
|
||||
- 🗑️ Удаляет старые образы (WATCHTOWER_CLEANUP=true)
|
||||
|
||||
Watchtower использует метку на контейнере `web`:
|
||||
```yaml
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.scope=oknardia-scope"
|
||||
```
|
||||
|
||||
## Файлы, которые монтируются с хоста
|
||||
|
||||
| На хосте | В контейнере | Назначение |
|
||||
|----------|----------|-----------|
|
||||
| `./database/` | `/home/app/database/` | БД SQLite (КРИТИЧНО!) |
|
||||
| `./media/` | `/home/app/public/media/` | Медиа файлы, uploads |
|
||||
| `./config/` | `/nginx_configs_host/` | Конифиги (читаются и пишущутся контейнером) |
|
||||
|
||||
## Переменные окружения в docker-compose.prod.yml
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- DEBUG=False # Production: без debug
|
||||
- DJANGO_LOG_LEVEL=INFO # Минимум логов
|
||||
- ALLOW_MEDIA_SERVE=False # Nginx обслуживает медиа
|
||||
- HOST_PROJECT_PATH=... # Путь для sed-замены в конфиге nginx
|
||||
- REPO_USER=${REPO_USER} # Из .env (для Watchtower)
|
||||
- REPO_PASS=${REPO_PASS} # Из .env (для Watchtower)
|
||||
```
|
||||
|
||||
## Health Check
|
||||
|
||||
Контейнер имеет healthcheck, который проверяет доступность Django:
|
||||
- Проверка каждые 3 минуты
|
||||
- Таймаут: 12 секунд
|
||||
- Unhealthy после 3 неудачных попыток
|
||||
- Это критично для Watchtower (он ждет что контейнер станет healthy перед finalization)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ContainerError при запуске
|
||||
|
||||
Проверить логи:
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml logs web
|
||||
```
|
||||
|
||||
### БД не синхронизируется между перезагрузками
|
||||
|
||||
Убедиться что `./database/` правильно монтирует:
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml exec web ls -la /home/app/database/
|
||||
```
|
||||
|
||||
### Watchtower не обновляет контейнер
|
||||
|
||||
Проверить:
|
||||
- Есть ли интернет на сервере
|
||||
- Правильны ли REPO_USER и REPO_PASS в .env
|
||||
- Существует ли образ `oknardia:latest` в реестре
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml logs watchtower
|
||||
```
|
||||
|
||||
### Nginx конфиг не обновился
|
||||
|
||||
Конфиг копируется при старте контейнера. Если нужно пересоздать:
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml down
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
Потом проверить:
|
||||
```bash
|
||||
cat ~/docker-app/oknardia-site/config/nginx/oknardia-app--external-nginx.conf
|
||||
```
|
||||
|
||||
## Резервные копии
|
||||
|
||||
Важно регулярно бэкапить:
|
||||
- `./database/oknardia.sqlite3` - БД
|
||||
- `./media/` - Загруженные файлы
|
||||
|
||||
Пример cronjob для ежедневного бэкапа:
|
||||
```bash
|
||||
# /etc/cron.daily/backup-oknardia
|
||||
#!/bin/bash
|
||||
BACKUP_DIR="/backup/oknardia"
|
||||
APP_DIR="/home/default_user/projects/oknardia-site"
|
||||
|
||||
mkdir -p $BACKUP_DIR
|
||||
tar -czf $BACKUP_DIR/oknardia-$(date +%Y%m%d).tar.gz $APP_DIR
|
||||
find $BACKUP_DIR -name "oknardia-*.tar.gz" -mtime +30 -delete # Удалять старше 30 дней
|
||||
```
|
||||
|
||||
123
docker-compose.prod.yml
Normal file
123
docker-compose.prod.yml
Normal file
@@ -0,0 +1,123 @@
|
||||
# ==============================================================================
|
||||
# Docker Compose для PRODUCTION
|
||||
# Этот файл запускается на боевом сервере.
|
||||
# Вариант 1 (если переименовали в docker-compose.yml): docker compose up -d
|
||||
# Вариант 2 (если оставили имя): docker compose -f docker-compose.prod.yml up -d
|
||||
# ==============================================================================
|
||||
|
||||
services:
|
||||
# --- ОСНОВНОЙ СЕРВИС: DJANGO + GUNICORN + WHITENOISE ---
|
||||
web:
|
||||
# Имя контейнера для удобства
|
||||
container_name: oknardia-backend
|
||||
|
||||
# В production используем готовый, собранный образ из реестра (Gitea)
|
||||
image: git.cube2.ru/erjemin/oknardia:latest
|
||||
|
||||
# ПЕРЕЗАПУСК при сбое
|
||||
restart: always
|
||||
|
||||
# Метки для Watchtower (авто-обновление)
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.scope=oknardia-scope"
|
||||
|
||||
# КОМАНДА ЗАПУСКА (Production режим)
|
||||
# При старте контейнера:
|
||||
# 1. Применяем миграции
|
||||
# 2. Собираем статику
|
||||
# 3. Генерируем sitemap'ы
|
||||
# 4. Пересоздаём пре-рендер шаблоны серий
|
||||
# 5. Пересчитываем рейтинги
|
||||
# 6. Создаём папку конфигов nginx (если нет)
|
||||
# 7. Копируем конфиг nginx с авто-заменой путей через sed
|
||||
# 8. Инициализируем боевой конфиг (если нет, копируем из примера)
|
||||
# 9. Запускаем Gunicorn
|
||||
command: >
|
||||
sh -c "python manage.py migrate --noinput &&
|
||||
python manage.py collectstatic --noinput &&
|
||||
python manage.py generate_sitemaps &&
|
||||
python manage.py regenerate_seria_prerender &&
|
||||
python manage.py make_rating &&
|
||||
mkdir -p /nginx_configs_host/nginx &&
|
||||
sed \"s|/home/user/app/oknardia-site|$${HOST_PROJECT_PATH:-/home/default_user/projects/oknardia-site}|g\" /home/app/config/nginx/oknardia-app--external-nginx.conf > /nginx_configs_host/nginx/oknardia-app--external-nginx.conf.example &&
|
||||
if [ ! -f /nginx_configs_host/nginx/oknardia-app--external-nginx.conf ]; then
|
||||
cp /nginx_configs_host/nginx/oknardia-app--external-nginx.conf.example /nginx_configs_host/nginx/oknardia-app--external-nginx.conf;
|
||||
echo 'INIT: Created new nginx config with correct paths';
|
||||
fi &&
|
||||
python -m gunicorn --workers 4 --bind 0.0.0.0:8000 --timeout 120 oknardia.wsgi:application"
|
||||
|
||||
# Пробрасывание портов
|
||||
# Слушаем только на localhost хоста для безопасности
|
||||
ports:
|
||||
- "127.0.0.1:8060:8000"
|
||||
|
||||
# МОНТИРОВАНИЕ ТОМОВ (Volumes)
|
||||
volumes:
|
||||
# БД SQLite
|
||||
- ./database:/home/app/database
|
||||
|
||||
# Медиа файлы
|
||||
- ./media:/home/app/public/media
|
||||
|
||||
# Конфиги nginx
|
||||
- ./config:/nginx_configs_host
|
||||
|
||||
# Пользователь и права
|
||||
user: "0:0"
|
||||
|
||||
# ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ (Production)
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- DJANGO_SETTINGS_MODULE=oknardia.settings
|
||||
- PYTHONUNBUFFERED=1
|
||||
- DEBUG=False
|
||||
- DJANGO_LOG_LEVEL=INFO
|
||||
- ALLOW_MEDIA_SERVE=False
|
||||
- HOST_PROJECT_PATH=${HOST_PROJECT_PATH:-/home/default_user/projects/oknardia-site}
|
||||
|
||||
# ЗДОРОВЬЕ КОНТЕЙНЕРА (Healthcheck)
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()"]
|
||||
interval: 3m
|
||||
timeout: 12s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
|
||||
# ЛОГИРОВАНИЕ (Ротация)
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "5"
|
||||
|
||||
# РЕСУРСЫ
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 1G
|
||||
mem_limit: 1g
|
||||
|
||||
# --- WATCHTOWER: АВТО-ОБНОВЛЕНИЕ ОБРАЗОВ ---
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: oknardia_watchtower
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- REPO_USER=${REPO_USER}
|
||||
- REPO_PASS=${REPO_PASS}
|
||||
- WATCHTOWER_SCOPE=oknardia-scope
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- DOCKER_API_VERSION=1.44
|
||||
- WATCHTOWER_WAIT_ON_TIMEOUT=60
|
||||
- WATCHTOWER_LIFECYCLE_HOOKS=true
|
||||
command: --interval 1800 --cleanup
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
Reference in New Issue
Block a user