8 Commits

Author SHA1 Message Date
erjemin 74406ef1b3 fix: образ 2020-dq:latest 2026-07-06 12:54:21 +03:00
erjemin 9cce6817cf back: вернул выбор случайности через "?" на SQLite
Build and Push Docker Image / build-and-push (push) Successful in 27s
2026-07-06 12:52:20 +03:00
erjemin ed7c106930 fix: Убрал дублирование CMD из Dockerfile - теперь полный котроль через compose
Build and Push Docker Image / build-and-push (push) Successful in 32s
2026-07-06 12:37:25 +03:00
erjemin 3551dfc242 fix: убрал healthcheck 2026-07-06 12:32:59 +03:00
erjemin 7b5718b0f6 Merge remote-tracking branch 'origin/2026-rework' into 2026-rework
# Conflicts:
#	docker-compose.prod.yml
2026-07-06 12:30:07 +03:00
erjemin d588087b2c fix: убрал healthcheck 2026-07-06 12:29:43 +03:00
erjemin 17d45d1c05 fix: медленный '?'-запрос в базе заменили на рандом по ip (должно не тормозить в проде) + таймауты
Build and Push Docker Image / build-and-push (push) Successful in 1m13s
2026-07-05 21:29:35 +03:00
erjemin e55ea68d05 ---: minor 2026-03-25 14:32:14 +03:00
4 changed files with 39 additions and 37 deletions
+4 -4
View File
@@ -98,11 +98,11 @@ EXPOSE 8000
# --timeout=3s - ожидаем ответ максимум 3 секунды # --timeout=3s - ожидаем ответ максимум 3 секунды
# --start-period=10s - даем контейнеру 10 секунд на запуск перед первой проверкой # --start-period=10s - даем контейнеру 10 секунд на запуск перед первой проверкой
# --retries=3 - объявляем контейнер unhealthy после 3 неудачных попыток # --retries=3 - объявляем контейнер unhealthy после 3 неудачных попыток
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ # HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()" || exit 1 # CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()" || exit 1
# Переходим в директорию с manage.py для корректного запуска gunicorn # Переходим в директорию с manage.py для корректного запуска gunicorn
WORKDIR /home/app/web/dicquo WORKDIR /home/app/web/dicquo
# Команда запуска # Команда запуска (не обязательная, так как в docker-compose.yml указана своя команда)
CMD ["gunicorn", "--workers", "3", "--bind", "0.0.0.0:8000", "dicquo.wsgi:application"] # CMD ["gunicorn", "--workers", "3", "--bind", "0.0.0.0:8010", "dicquo.wsgi:application"]
+1 -1
View File
@@ -29,7 +29,7 @@ upstream dq-django {
# 2. Конфигурируем сервер # 2. Конфигурируем сервер
server { server {
server_name dq.cube2.ru dq2.cube2.ru; # Основное доменное имя server_name dq.cube2.ru; # Основное доменное имя
# Слушаем 80 порт (Certbot потом добавит сюда редирект на 443 и настройки SSL) # Слушаем 80 порт (Certbot потом добавит сюда редирект на 443 и настройки SSL)
listen 80; listen 80;
+1 -1
View File
@@ -123,7 +123,7 @@ class CommonContextMixin:
# Вариант: Очистить seen_ids, чтобы в следующий раз (на некст странице) список был пуст? # Вариант: Очистить seen_ids, чтобы в следующий раз (на некст странице) список был пуст?
# Или просто выбрать любую КРОМЕ текущей? # Или просто выбрать любую КРОМЕ текущей?
dq_next = queryset.exclude(id=dq.id).order_by('?').first() dq_next = queryset.exclude(id__in=seen_ids).order_by('?').first()
# Если мы действительно прошли весь цикл по тегу, логично сбросить seen_ids, # Если мы действительно прошли весь цикл по тегу, логично сбросить seen_ids,
# чтобы пользователь мог заново проходить этот список случайно, а не "застревать" на последних. # чтобы пользователь мог заново проходить этот список случайно, а не "застревать" на последних.
+33 -31
View File
@@ -1,4 +1,3 @@
% cat docker-compose.yaml
# ============================================================================== # ==============================================================================
# Docker Compose для PRODUCTION # Docker Compose для PRODUCTION
# Этот файл запускается на боевом сервере. # Этот файл запускается на боевом сервере.
@@ -17,6 +16,7 @@ services:
# 1. ОБРАЗ # 1. ОБРАЗ
# В продакшене мы используем готовый, собранный образ из реестра (Gitea) # В продакшене мы используем готовый, собранный образ из реестра (Gitea)
# image: git.cube2.ru/erjemin/2020-dq:v1.0.7
image: git.cube2.ru/erjemin/2020-dq:latest image: git.cube2.ru/erjemin/2020-dq:latest
# Если образа в gitae нет, то перенести весь код в прод и можно собирать локально: # Если образа в gitae нет, то перенести весь код в прод и можно собирать локально:
# build: . # build: .
@@ -29,14 +29,13 @@ services:
# 3. КОМАНДА ЗАПУСКА (Замена entrypoint.sh) # 3. КОМАНДА ЗАПУСКА (Замена entrypoint.sh)
# Выполняем цепочку команд внутри контейнера при запуске: # Выполняем цепочку команд внутри контейнера при запуске:
# a. Миграции # 1. Миграции
# b. Collectstatic # 2. Collectstatic
# с. Создаем папку nginx в примонтированном томе конфигов (если нет) # 3. Создаем папку nginx в примонтированном томе конфигов (если нет)
# d. Копирование конфига Nginx с авто-заменой путей через sed (замену реального пути на хосте получаем # 4. Копирование конфига Nginx с авто-заменой путей через sed (замену реального пути на хосте получаем через переменную окружения HOST_PROJECT_PATH)
# через переменную окружения HOST_PROJECT_PATH) # 5. Инициализация боевого конфига (если нет)
# e. Инициализация боевого конфига (если нет) # 6. Создаем папку для ошибок и копируем туда статические страницы 404/500
# f. Создаем папку для ошибок и копируем туда статические страницы 404/500 (там их увидит Nginx хоста) # 7. Запуск Gunicorn
# g. Запуск Gunicorn
command: > command: >
sh -c "python manage.py migrate --noinput && sh -c "python manage.py migrate --noinput &&
python manage.py collectstatic --noinput && python manage.py collectstatic --noinput &&
@@ -49,12 +48,12 @@ services:
mkdir -p /app/public/media/errors && mkdir -p /app/public/media/errors &&
cp /home/app/web/dicquo/templates/static_404.html /app/public/media/errors/404.html && cp /home/app/web/dicquo/templates/static_404.html /app/public/media/errors/404.html &&
cp /home/app/web/dicquo/templates/static_500.html /app/public/media/errors/500.html && cp /home/app/web/dicquo/templates/static_500.html /app/public/media/errors/500.html &&
gunicorn --workers 3 --bind 0.0.0.0:8000 dicquo.wsgi:application" gunicorn --workers 2 --timeout 120 --bind 0.0.0.0:8010 dicquo.wsgi:application"
# 4. Проброс портов (Внешний Nginx -> localhost:8010) # 4. Проброс портов (Внешний Nginx -> localhost:8010)
ports: ports:
# Слушаем только на localhost хоста, чтобы закрыть прямой доступ из интернета к Gunicorn # Слушаем только на localhost хоста, чтобы закрыть прямой доступ из интернета к Gunicorn
- "127.0.0.1:8010:8000" - "127.0.0.1:8010:8010"
# 5. Тома (Volumes) # 5. Тома (Volumes)
volumes: volumes:
@@ -70,14 +69,16 @@ services:
# Это нужно, чтобы скрипт запуска мог положить туда .example конфиг и прочитать боевой конфиг. # Это нужно, чтобы скрипт запуска мог положить туда .example конфиг и прочитать боевой конфиг.
- ./config:/nginx_configs_host - ./config:/nginx_configs_host
# 6. Пользователь и права # 6.
user: "1000:1000" user: "1000:1000"
# Когда нужна отладка процессов внутри контейнера, можно временно раскомментировать эту строку и запустить контейнер с правами root. # Для отладки
# cap_add: cap_add:
# - SYS_PTRACE - SYS_PTRACE
# 7. Переменные окружения
# 6. Переменные окружения
env_file: env_file:
- .env - .env
environment: environment:
@@ -86,30 +87,31 @@ services:
# Передаем переменную с путем на хосте внутрь контейнера, чтобы sed мог её использовать # Передаем переменную с путем на хосте внутрь контейнера, чтобы sed мог её использовать
- HOST_PROJECT_PATH=${HOST_PROJECT_PATH:-/home/default_user/projects/dq-site} - HOST_PROJECT_PATH=${HOST_PROJECT_PATH:-/home/default_user/projects/dq-site}
# 8. Проверка здоровья контейнера (Healthcheck) # 7. Проверка здоровья контейнера (Healthcheck)
# Docker будет периодически проверять статус контейнера. Это критично для Watchtower! # Docker будет периодически проверять статус контейнера. Это критично для Watchtower!
# Если контейнер объявлен "unhealthy", Watchtower сначала остановит старый образ, потом запустит новый. # Если контейнер объявлен "unhealthy", Watchtower сначала остановит старый образ, потом запустит новый.
healthcheck: # healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()"] # # test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8010/').read()"]
interval: 30s # Проверка каждые 30 секунд # test: ["CMD", "test", "-f", "/home/app/web/dicquo/gunicorn.ctl"]
timeout: 3s # Таймаут ответа - 3 секунды # interval: 300s # Проверка каждые 300 секунд
start_period: 10s # Даем 10 секунд на стартап перед первой проверкой # timeout: 30s # Таймаут ответа - 30 секунды
retries: 3 # Unhealthy после 3 неудачных попыток # start_period: 80s # Даем 30 секунд на стартап перед первой проверкой
# retries: 3 # Unhealthy после 3 неудачных попыток
# 9. Логирование (Ротация) # 8. Логирование (Ротация)
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
max-size: "10m" max-size: "10m"
max-file: "3" max-file: "2"
# 10. Ресурсы # 9. Ресурсы
deploy: deploy:
resources: resources:
limits: limits:
cpus: '0.40' cpus: '0.50'
memory: 256M memory: 380M
mem_limit: 256m mem_limit: 380M
# --- WATCHTOWER: АВТО-ОБНОВЛЕНИЕ ОБРАЗОВ --- # --- WATCHTOWER: АВТО-ОБНОВЛЕНИЕ ОБРАЗОВ ---
# Следит за реестром Gitea и обновляет контейнер web, если появился новый image # Следит за реестром Gitea и обновляет контейнер web, если появился новый image
@@ -134,5 +136,5 @@ services:
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
max-size: "10m" max-size: "1m"
max-file: "3" max-file: "1"