gendesign/ops/crontab-beget.cron
bot-backend 0111b32cb2
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(ops): у волта Obsidian появился автоматический бэкап
Site Finder закрывает backup.sh, МЕРУ — backup-tradein-db.sh, Forgejo —
backup-forgejo.sh. CouchDB не закрывал никто: автоматического бэкапа волта не
существовало вообще, единственной копией был ручной месячный прогон на машине
владельца. При этом в волте вся накопленная база знаний проекта — решения,
разборы инцидентов, ограничения, — и восстановить её из кода нельзя.

Контейнер на время снимка останавливается. Файлы CouchDB пишутся append-only,
но копия работающего узла может застать запись между обновлением данных и
обновлением заголовка базы, а .shards/ и _dbs.couch — рассогласованными между
собой; документация прямо требует снимать file-level копию с остановленного
узла. Данных около 85 МБ, простой измерен и составляет примерно минуту, окно
ночное, а LiveSync к обрывам связи устойчив по своей природе.

Оставить волт лежать — отказ хуже отсутствия бэкапа, поэтому старт висит на
trap EXIT и отрабатывает при любом выходе, включая ошибку tar и нехватку
места. После подъёма проверяется, что /_up отвечает, иначе notify().

S3 обязателен, как в backup-forgejo.sh и в backup.sh после #3085: без ключей
скрипт падает ДО остановки контейнера. Ронять волт ради копии, которой некуда
уехать, незачем.

Отдельный ключ для волта не требуется. Если COUCHDB_S3_* не заданы, берутся
S3_* из конфига основного бэкапа — того же ключа, которым уже выгружается
Site Finder, но под своим префиксом couchdb/. Требовать узкий ключ как условие
запуска значило бы оставить волт без бэкапа до того дня, когда до ключа дойдут
руки; завести его никто не мешает, файл-образец для этого есть.

Фолбэк читается в ПОДОБОЛОЧКЕ, наружу выносятся ровно четыре значения. Прямой
source был бы тихой диверсией: конфиг основного бэкапа задаёт свои
LOCAL_BACKUP_DIR, KEEP и SENTINEL_FILE, они затёрли бы вычисленные для волта.
Архивы легли бы в чужой каталог, а write_sentinel обновил бы сентинел
ОСНОВНОГО бэкапа — его сторож свежести зеленел бы по чужому прогону, и
пропущенный дамп базы перестал бы замечаться.

Владелец архивов выравнивается внутри контейнера: читать том надо от root,
поэтому наружу файлы выходили root:root, в отличие от соседних серий. Ротацию
это не ломало, но ставило каталог в зависимость от отсутствия sticky-бита.

ops/*.cron добавлен в paths deploy-infra.yml: эта строка была только в
deploy.yml, и после разъезда хостов правка crontab-beget.cron доезжала бы
лишь до продового хоста — то есть не туда, где живёт волт.

Проверено на боевом Beget, дважды подряд:
- без S3-настроек — код возврата 1, контейнер не тронут (Up 12 hours);
- полный прогон — контейнер остановлен, снят снимок 53 219 001 байт (15
  файлов) и конфиг 788 байт (3 файла), контейнер поднят и healthy, оба архива
  выгружены, сентинел записан, весь прогон 103 с;
- изоляция подоболочки прогнана на подставном конфиге: S3-значения
  подхватываются, LOCAL_BACKUP_DIR / SENTINEL_FILE / KEEP не затираются;
- объекты в бакете подтверждены НЕЗАВИСИМЫМ читающим ключом:
  couchdb/couchdb-data_*.tar.gz 50.8 MiB и couchdb/couchdb-config_*.tar.gz.

Refs #3057, #3085
2026-08-25 08:37:02 +03:00

60 lines
5.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# crontab ОСТАЮЩЕГОСЯ хоста (Beget, 46.173.16.127) — после переезда 30.08.
#
# Устанавливать НЕ РАНЬШЕ, чем стек уедет на Selectel:
# crontab /opt/gendesign/ops/crontab-beget.cron
# crontab -l # сверить
#
# ЗАЧЕМ ЭТОТ ФАЙЛ. Сегодняшний crontab Beget'а обслуживает ОБА контура сразу:
# и остающийся (Forgejo), и уезжающий (tradein/gendesign). После переезда пять
# записей начнут ходить в контейнеры, которых на этом хосте больше нет —
# `docker exec tradein-backend ...` будет падать каждую ночь. Само по себе это
# ещё полбеды; беда в том, что вместе с ними перестанут обновляться sentinel'ы
# бэкапов, сторож это честно заметит — и упрётся в то, что канал оповещения
# не настроен (#2203: TELEGRAM_* нет ни в одном env-файле). То есть бэкапы
# пропадут молча.
#
# Разделение на два файла — чтобы этот переход был явным действием, а не
# «забыли поправить crontab».
# ── Forgejo: остаётся здесь ─────────────────────────────────────────────────
# Конфиг лежит не в /etc/default (туда нет доступа без root), а в
# /opt/gendesign/secrets — путь передаётся переменной.
15 4 * * * FORGEJO_BACKUP_ENV_FILE=/opt/gendesign/secrets/forgejo-backup.env bash /opt/gendesign/ops/backup-forgejo.sh >> /opt/gendesign/logs/backup-forgejo.log 2>&1
# Сторож пропущенных прогонов для forgejo-бэкапа. Порог 26ч.
0 * * * * bash /opt/gendesign/ops/check-backup-staleness.sh /opt/gendesign/backups/forgejo/.last_success 26 "forgejo backup" >> /opt/gendesign/logs/backup-staleness.log 2>&1
# ── Бэкап волта Obsidian (CouchDB) ──────────────────────────────────────────
# Волт остаётся на этом хосте вместе с Forgejo и GlitchTip, поэтому запись
# живёт здесь, а не в crontab-poincare. До #3057 у CouchDB не было
# автоматического бэкапа вообще — единственной копией был ручной месячный
# прогон на машине владельца.
# Скрипт ОСТАНАВЛИВАЕТ CouchDB на время снятия снимка (секунды, данных ~85 МБ):
# file-level копия работающего узла может оказаться рассогласованной. Время —
# 04:45, между forgejo-бэкапом (04:15) и недельной уборкой докера (04:00 вс),
# чтобы три задачи не дрались за диск и сеть одновременно.
45 4 * * * bash /opt/gendesign/ops/backup-couchdb.sh >> /opt/gendesign/logs/backup-couchdb.log 2>&1
# Сторож пропущенных прогонов для бэкапа волта. Порог 26ч — как у остальных:
# сутки плюс запас на сдвиг прогона.
0 * * * * bash /opt/gendesign/ops/check-backup-staleness.sh /opt/gendesign/backups/couchdb/.last_success 26 "couchdb backup" >> /opt/gendesign/logs/backup-staleness.log 2>&1
# ── Уборка докера ───────────────────────────────────────────────────────────
# Остаётся здесь, потому что здесь остаются CI-раннеры (#2881) — именно их
# тома и растут. На Selectel нужна СВОЯ такая же запись (см. crontab-poincare).
0 4 * * 0 bash /opt/gendesign/ops/docker-prune.sh >> /tmp/gendesign-docker-prune.log 2>&1
# ── ЧТО ОТСЮДА УБРАНО И ПОЧЕМУ ──────────────────────────────────────────────
# Все записи ниже переехали в ops/crontab-poincare.cron, потому что обращаются
# к контейнерам и данным, которых на Beget после переезда не будет:
#
# 30 4 * * * backup-tradein-db.sh -> dump из tradein-postgres
# 30 3 * * * ops/backup.sh -> dump из gendesign-postgres
# 0 5 * * * backfill_houses_dadata -> docker exec tradein-backend
# 30 5 * * * geocode_deals_from_houses -> docker exec tradein-backend
# 45 5 * * * geocode_deals_nominatim -> docker exec tradein-backend
# 0 * * * * staleness: backups/.last_success (main-бэкап уехал)
# 0 * * * * staleness: backups/tradein/.last_success (tradein-бэкап уехал)
#
# ⚠️ Оставить их здесь = пять падающих задач в сутки И потерянные бэкапы
# обоих продуктовых кластеров.