mod: update production docker deployment
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 12s

This commit is contained in:
2026-04-14 16:28:12 +03:00
parent cb28acfaf2
commit 5d7470ac7d
4 changed files with 373 additions and 6 deletions

148
docker-compose.prod.yml Normal file
View File

@@ -0,0 +1,148 @@
# ==============================================================================
# Docker Compose для PRODUCTION
# Этот файл запускается на боевом сервере.
# Вариант 1 (если переименовали в docker-compose.yml): docker compose up -d
# Вариант 2 (если оставили имя): docker compose -f docker-compose.prod.yml up -d
# ==============================================================================
# В новой версии Docker не нужно
# version: '3.8'
services:
# --- ОCНОВНОЙ СЕРВИС: DJANGO + GUNICORN + WHITENOISE ---
web:
# Имя контейнера
container_name: cadpoint-backend
# 1. ОБРАЗ
# В продакшене мы используем готовый, собранный образ из реестра (Gitea)
image: git.cube2.ru/erjemin/2021-cadpoint-ru:latest
# Если образа в gitae нет, то перенести весь код в прод и можно собирать локально:
# build: .
restart: always
# 2. Метки для Watchtower (авто-обновление)
labels:
- "com.centurylinklabs.watchtower.scope=cadpoint-scope"
# 3. КОМАНДА ЗАПУСКА (Замена entrypoint.sh)
# Выполняем цепочку команд внутри контейнера при запуске:
# a. Миграции
# b. Collectstatic
# с. Создаем папку nginx в примонтированном томе конфигов (если нет)
# d. Копирование конфига Nginx с авто-заменой путей через sed (замену реального пути на хосте получаем
# через переменную окружения HOST_PROJECT_PATH)
# e. Инициализация боевого конфига (если нет)
# f. Создаем папку для ошибок и копируем туда HTML error pages и их ассеты (там их увидит Nginx хоста)
# — иконки, SVG-иллюстрации и under_reconstruction тоже должны лежать рядом, чтобы Nginx мог их отдать
# g. Запуск Gunicorn
command: >
sh -c "python manage.py migrate --noinput &&
python manage.py collectstatic --noinput --clear &&
mkdir -p /nginx_configs_host/nginx &&
sed \"s|/home/user/app/cadpoint-site|${HOST_PROJECT_PATH:-/home/default_user/projects/cadpoint-site}|g\" /nginx_configs_host/nginx/cadpoint-app--external-nginx.conf > /nginx_configs_host/nginx/nginx_cadpoint.conf.example &&
if [ ! -f /nginx_configs_host/nginx/cadpoint-app--external-nginx.conf ]; then
cp /nginx_configs_host/nginx/nginx_cadpoint.conf.example /nginx_configs_host/nginx/cadpoint-app--external-nginx.conf;
echo 'INIT: Created new nginx config with correct paths';
fi &&
ERROR_DIR=/home/app/web/public/media/_error &&
mkdir -p "$$ERROR_DIR/svgs" "$$ERROR_DIR/img" &&
for code in 400 401 403 404 413 429 500 502 503 504; do
cp /home/app/web/cadpoint/templates/$${code}.html "$$ERROR_DIR/$${code}.html";
done &&
cp /home/app/web/cadpoint/templates/under_reconstruction.html "$$ERROR_DIR/under_reconstruction.html" &&
cp /home/app/web/public/static/svgs/favicon.svg "$$ERROR_DIR/svgs/favicon.svg" &&
cp /home/app/web/public/static/svgs/xxx-error.svg "$$ERROR_DIR/svgs/xxx-error.svg" &&
cp /home/app/web/public/static/svgs/404-error.svg "$$ERROR_DIR/svgs/404-error.svg" &&
cp /home/app/web/public/static/svgs/500-error.svg "$$ERROR_DIR/svgs/500-error.svg" &&
cp /home/app/web/public/static/svgs/cappoint_under_reconstruction.svg "$$ERROR_DIR/svgs/cappoint_under_reconstruction.svg" &&
cp /home/app/web/public/static/img/favicon.png "$$ERROR_DIR/img/favicon.png" &&
cp /home/app/web/public/static/img/favicon.ico "$$ERROR_DIR/img/favicon.ico" &&
gunicorn --workers 2 --bind 0.0.0.0:8000 cadpoint.wsgi:application"
# 4. Проброс портов (Внешний Nginx -> localhost:8050)
ports:
# Слушаем только на localhost хоста, чтобы закрыть прямой доступ из интернета к Gunicorn
- "127.0.0.1:8050:8000"
# 5. Тома (Volumes)
volumes:
# База данных
# Монтируем папку database с хоста в папку с базой внутри контейнера.
# Путь в контейнере: /home/app/web/database (так как Django ищет базу в BASE_DIR.parent/database)
- ./database:/home/app/web/database
# Медиа, служебные error-pages и их ассеты лежат в папке `media` на хосте.
- ./media:/home/app/web/public/media
# Конфиги (Монтируем папку ./config с хоста в /nginx_configs_host внутри контейнера)
# Это нужно, чтобы скрипт запуска мог положить туда .example конфиг и прочитать боевой конфиг.
- ./config:/nginx_configs_host
# 6. Пользователь и права
user: "1000:1000"
# Когда нужна отладка процессов внутри контейнера, можно временно раскомментировать эту строку и запустить контейнер с правами root.
# cap_add:
# - SYS_PTRACE
# 7. Переменные окружения
env_file:
- .env
environment:
- DJANGO_SETTINGS_MODULE=cadpoint.settings
- PYTHONUNBUFFERED=1
# Передаем переменную с путем на хосте внутрь контейнера, чтобы sed мог её использовать
- HOST_PROJECT_PATH=${HOST_PROJECT_PATH:-/home/default_user/projects/cadpoint-site}
# 8. Проверка здоровья контейнера (Healthcheck)
# Docker будет периодически проверять статус контейнера. Это критично для Watchtower!
# Если контейнер объявлен "unhealthy", Watchtower сначала остановит старый образ, потом запустит новый.
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()"]
interval: 3m # Проверка каждые 3 минуты
timeout: 12s # Таймаут ответа - 12 секунды
start_period: 20s # Даем 20 секунд на стартап перед первой проверкой
retries: 3 # Unhealthy после 3 неудачных попыток
# 9. Логирование (Ротация)
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 10. Ресурсы
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
mem_limit: 512m
# --- WATCHTOWER: АВТО-ОБНОВЛЕНИЕ ОБРАЗОВ ---
# Следит за реестром Gitea и обновляет контейнер web, если появился новый image
watchtower:
image: containrrr/watchtower
container_name: cadpoint_watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
# Токен/Логин для вашего приватного реестра (нужно добавить в .env!)
# REPO_USER и REPO_PASS должны быть в .env файле на сервере
- REPO_USER=${REPO_USER}
- REPO_PASS=${REPO_PASS}
- WATCHTOWER_SCOPE=cadpoint-scope
- WATCHTOWER_CLEANUP=true # Удалять старые образы после обновления
- DOCKER_API_VERSION=1.44
# Дополнительные опции для правильной работы с healthcheck
- WATCHTOWER_WAIT_ON_TIMEOUT=60 # Ждем 60 сек пока контейнер станет healthy перед финализацией
- WATCHTOWER_LIFECYCLE_HOOKS=true # Включаем lifecycle hooks для graceful shutdown
command: --interval 1800 --cleanup # Проверять каждые 30 минут
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"