From 0111b32cb22bdece72574cb072a338a5f4e4c602 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Tue, 25 Aug 2026 08:37:02 +0300 Subject: [PATCH] =?UTF-8?q?feat(ops):=20=D1=83=20=D0=B2=D0=BE=D0=BB=D1=82?= =?UTF-8?q?=D0=B0=20Obsidian=20=D0=BF=D0=BE=D1=8F=D0=B2=D0=B8=D0=BB=D1=81?= =?UTF-8?q?=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B1=D1=8D=D0=BA=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .forgejo/workflows/deploy-infra.yml | 6 + ops/backup-couchdb.sh | 249 +++++++++++++++++++ ops/crontab-beget.cron | 15 ++ ops/gendesign-backup-couchdb.default.example | 55 ++++ 4 files changed, 325 insertions(+) create mode 100644 ops/backup-couchdb.sh create mode 100644 ops/gendesign-backup-couchdb.default.example diff --git a/.forgejo/workflows/deploy-infra.yml b/.forgejo/workflows/deploy-infra.yml index 2322ad7f..004a50d8 100644 --- a/.forgejo/workflows/deploy-infra.yml +++ b/.forgejo/workflows/deploy-infra.yml @@ -53,6 +53,12 @@ on: # Ровно то, что исполняется НА ОСТАЮЩЕМСЯ хосте. Намеренно НЕ включены # backend/** и frontend/** — их образы туда не едут. - "ops/*.sh" + # ops/*.cron — эталоны crontab. Деплой их не исполняет, но после + # разъезда хостов (#3057) правка crontab-beget.cron иначе доезжала бы + # только до продового хоста: строка ops/*.cron есть лишь в deploy.yml. + # Одиночная звёздочка не пересекает `/`, поэтому это именно файлы в + # корне ops/, как и ops/*.sh рядом. + - "ops/*.cron" - "Caddyfile" - "caddy/**" - "docker-compose.prod.yml" diff --git a/ops/backup-couchdb.sh b/ops/backup-couchdb.sh new file mode 100644 index 00000000..3530936d --- /dev/null +++ b/ops/backup-couchdb.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +# Backup CouchDB (волт Obsidian, LiveSync) в S3. +# +# ЗАЧЕМ. До этого скрипта у волта не было автоматического бэкапа ВООБЩЕ: +# ops/backup.sh закрывает Site Finder, backup-tradein-db.sh — МЕРУ, +# backup-forgejo.sh — Forgejo, а CouchDB не закрывал никто. При этом в волте +# лежит вся накопленная база знаний проекта — решения, разборы инцидентов, +# ограничения, — и восстановить её из кода нельзя. Единственной копией был +# ручной месячный прогон на машине владельца. +# +# ПОЧЕМУ КОНТЕЙНЕР ОСТАНАВЛИВАЕТСЯ. Файлы CouchDB пишутся append-only, но +# снимок работающего узла может застать запись между обновлением данных и +# обновлением заголовка базы, а .shards/ и _dbs.couch — рассогласованными между +# собой. Документация CouchDB прямо говорит: file-level копия делается на +# остановленном узле. Поэтому здесь stop -> tar -> start, а не tar на живом. +# Простой — секунды (данных ~85 МБ), окно ночное, и LiveSync к обрывам связи +# устойчив по своей природе: клиенты досинхронизируются сами. +# +# ГАРАНТИЯ ПОДЪЁМА. Остановленный и не поднятый обратно CouchDB — отказ хуже +# отсутствия бэкапа, поэтому старт висит на trap EXIT: он отработает при любом +# выходе, включая ошибку tar, нехватку места и прерывание с клавиатуры. +# Отдельно проверяется, что контейнер после старта действительно отвечает; +# если нет — notify(). +# +# S3 ОБЯЗАТЕЛЕН. Как в backup-forgejo.sh и (после #3085) в backup.sh: без ключей +# скрипт падает, а не делает молча локальную копию. Смысл бэкапа — копия ВНЕ +# машины; локальная копия рядом с оригиналом не переживает потерю хоста. +# +# ЧТО КЛАДЁТСЯ. Два тома целиком: данные (базы, шарды, индексы) и конфиг +# (local.d — админ, порты, CORS). Конфиг без данных бесполезен, данные без +# конфига поднимаются, но требуют повторного bootstrap — держим оба. +# +# ВОССТАНОВЛЕНИЕ. Том обязан быть ПУСТ перед распаковкой: если развернуть +# снимок поверх живого каталога, останутся файлы, которых в снимке уже нет, и +# CouchDB не соберёт шарды. Порядок — остановить контейнер, очистить том, +# распаковать в него архив, повторить для тома конфига, поднять контейнер. +# Проверять восстановимость надо на ОТДЕЛЬНОМ томе, а не на боевом. +# +# Конфиг: /etc/default/gendesign-backup-couchdb +# (см. ops/gendesign-backup-couchdb.default.example) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=./lib-backup.sh +source "$SCRIPT_DIR/lib-backup.sh" + +# --- config (env-overridable) --- +COUCHDB_CONTAINER="${COUCHDB_CONTAINER:-gendesign-couchdb}" +COUCHDB_DATA_VOLUME="${COUCHDB_DATA_VOLUME:-gendesign-obsidian_couchdb_data}" +COUCHDB_CONFIG_VOLUME="${COUCHDB_CONFIG_VOLUME:-gendesign-obsidian_couchdb_config}" + +LOCAL_BACKUP_DIR="${LOCAL_BACKUP_DIR:-/opt/gendesign/backups/couchdb}" +KEEP="${KEEP:-7}" + +# Порог — про ОБЪЁМ, а не про «нашлись ли файлы»: пустой tar.gz весит около +# сотни байт, и без порога такой «успешный» бэкап неотличим от настоящего. +MIN_DATA_BYTES="${MIN_DATA_BYTES:-1048576}" # 1 МБ: волт заведомо больше +MIN_CONFIG_BYTES="${MIN_CONFIG_BYTES:-256}" + +SENTINEL_FILE="${SENTINEL_FILE:-${LOCAL_BACKUP_DIR}/.last_success}" +START_TIMEOUT="${START_TIMEOUT:-60}" + +COUCHDB_BACKUP_ENV_FILE="${COUCHDB_BACKUP_ENV_FILE:-/etc/default/gendesign-backup-couchdb}" +# shellcheck source=/dev/null +[[ -f "$COUCHDB_BACKUP_ENV_FILE" ]] && source "$COUCHDB_BACKUP_ENV_FILE" + +COUCHDB_S3_ENDPOINT="${COUCHDB_S3_ENDPOINT:-}" +COUCHDB_S3_BUCKET="${COUCHDB_S3_BUCKET:-}" +COUCHDB_S3_PREFIX="${COUCHDB_S3_PREFIX:-couchdb/}" +COUCHDB_S3_ACCESS_KEY="${COUCHDB_S3_ACCESS_KEY:-}" +COUCHDB_S3_SECRET_KEY="${COUCHDB_S3_SECRET_KEY:-}" + +# Фолбэк на конфиг основного бэкапа. Отдельный ключ для волта — правильнее +# (узкая область, как у forgejo), но требовать его как условие запуска значит +# оставить волт вообще без бэкапа до того дня, когда до ключа дойдут руки. +# Поэтому: заданы COUCHDB_S3_* — берём их; не заданы — берём S3_* оттуда, где +# они уже настроены и проверены. Префикс при этом всё равно свой (couchdb/), +# так что чужие серии в бакете не перемешиваются. +MAIN_BACKUP_ENV_FILE="${MAIN_BACKUP_ENV_FILE:-/etc/default/gendesign-backup}" +if [[ -z "$COUCHDB_S3_ENDPOINT" && -z "$COUCHDB_S3_ACCESS_KEY" && -f "$MAIN_BACKUP_ENV_FILE" ]]; then + # source В ПОДОБОЛОЧКЕ, наружу выносим ровно четыре значения. + # Прямой `source` здесь был бы тихой диверсией: конфиг основного бэкапа + # задаёт свои LOCAL_BACKUP_DIR, KEEP и SENTINEL_FILE, и они затёрли бы уже + # вычисленные выше значения для волта. Архивы легли бы в чужой каталог, а + # write_sentinel в конце обновил бы сентинел ОСНОВНОГО бэкапа — его сторож + # свежести зеленел бы по чужому прогону, то есть пропущенный дамп базы + # перестал бы замечаться вовсе. + eval "$( + # shellcheck source=/dev/null + source "$MAIN_BACKUP_ENV_FILE" >/dev/null 2>&1 || true + printf 'COUCHDB_S3_ENDPOINT=%q\n' "${S3_ENDPOINT:-}" + printf 'COUCHDB_S3_BUCKET=%q\n' "${S3_BUCKET:-}" + printf 'COUCHDB_S3_ACCESS_KEY=%q\n' "${S3_ACCESS_KEY:-}" + printf 'COUCHDB_S3_SECRET_KEY=%q\n' "${S3_SECRET_KEY:-}" + )" + [[ -n "$COUCHDB_S3_ACCESS_KEY" ]] && \ + log "S3: отдельный ключ для волта не задан — беру настройки из ${MAIN_BACKUP_ENV_FILE}, префикс ${COUCHDB_S3_PREFIX}" +fi + +# --- guard 0: S3 обязателен, и проверяется ДО всякой остановки контейнера --- +# Порядок важен: незачем ронять волт ради бэкапа, которому некуда уехать. +if [[ -z "$COUCHDB_S3_ENDPOINT" || -z "$COUCHDB_S3_BUCKET" || -z "$COUCHDB_S3_ACCESS_KEY" || -z "$COUCHDB_S3_SECRET_KEY" ]]; then + log "ERROR: бэкап CouchDB НЕ НАСТРОЕН." >&2 + log "ERROR: не заданы COUCHDB_S3_ENDPOINT / COUCHDB_S3_BUCKET / COUCHDB_S3_ACCESS_KEY / COUCHDB_S3_SECRET_KEY." >&2 + log "ERROR: заполни ${COUCHDB_BACKUP_ENV_FILE} (образец — ops/gendesign-backup-couchdb.default.example)" >&2 + log "ERROR: либо настрой S3_* в ${MAIN_BACKUP_ENV_FILE:-/etc/default/gendesign-backup} — оттуда берётся фолбэк." >&2 + log "ERROR: локальная копия рядом с оригиналом смысла не имеет — не делаю её и контейнер не трогаю." >&2 + exit 1 +fi + +# --- guard 1: контейнер и оба тома существуют --- +if ! docker inspect "$COUCHDB_CONTAINER" >/dev/null 2>&1; then + log "ERROR: контейнер ${COUCHDB_CONTAINER} не найден — переопредели COUCHDB_CONTAINER." >&2 + exit 1 +fi +for v in "$COUCHDB_DATA_VOLUME" "$COUCHDB_CONFIG_VOLUME"; do + if ! docker volume inspect "$v" >/dev/null 2>&1; then + log "ERROR: том ${v} не найден — переопредели COUCHDB_DATA_VOLUME / COUCHDB_CONFIG_VOLUME." >&2 + exit 1 + fi +done + +mkdir -p "$LOCAL_BACKUP_DIR" +TS="$(date -u +%Y%m%d_%H%M%S)" +data_out="${LOCAL_BACKUP_DIR}/couchdb-data_${TS}.tar.gz" +config_out="${LOCAL_BACKUP_DIR}/couchdb-config_${TS}.tar.gz" + +# --- гарантия подъёма: старт висит на EXIT, а не на успешном пути --- +COUCHDB_WAS_STOPPED=0 +restart_couchdb() { + local rc=$? + if [[ "$COUCHDB_WAS_STOPPED" == "1" ]]; then + log "Поднимаю ${COUCHDB_CONTAINER} обратно." + if ! docker start "$COUCHDB_CONTAINER" >/dev/null 2>&1; then + log "CRITICAL: не удалось запустить ${COUCHDB_CONTAINER} — волт лежит." >&2 + notify "CouchDB backup: контейнер ${COUCHDB_CONTAINER} ОСТАНОВЛЕН и не поднялся. Волт недоступен, нужно вмешательство." + return "$rc" + fi + local up=0 + for _ in $(seq 1 "$START_TIMEOUT"); do + if docker exec "$COUCHDB_CONTAINER" curl -fsS http://localhost:5984/_up >/dev/null 2>&1; then + up=1 + break + fi + sleep 1 + done + if [[ "$up" == "1" ]]; then + log "CouchDB отвечает." + else + log "CRITICAL: ${COUCHDB_CONTAINER} запущен, но /_up молчит ${START_TIMEOUT}с." >&2 + notify "CouchDB backup: контейнер поднят, но /_up не отвечает ${START_TIMEOUT}с. Проверь волт." + fi + fi + return "$rc" +} +trap restart_couchdb EXIT + +log "Останавливаю ${COUCHDB_CONTAINER} для снятия консистентного снимка." +docker stop "$COUCHDB_CONTAINER" >/dev/null +COUCHDB_WAS_STOPPED=1 + +# tar идёт в одноразовом контейнере: том примонтирован read-only, писать он +# может только в каталог бэкапов. +# +# Про владельца. Читать файлы тома надо от root (внутри они принадлежат uid +# CouchDB), поэтому контейнер запускается от root — и архив наружу выходит +# root:root, в отличие от остальных серий в этом каталоге. Само по себе это +# ротацию не ломает (удаление зависит от прав КАТАЛОГА, а он наш), но ставит +# каталог в зависимость от того, что никто не включит на нём sticky-бит, и +# ломает ручную работу с файлами из-под непривилегированного пользователя. +# Поэтому chown делаем тут же, внутри контейнера, где root ещё есть. +HOST_UID="$(id -u)" +HOST_GID="$(id -g)" +tar_volume() { + local volume="$1" out="$2" name + name="$(basename "$out")" + docker run --rm \ + -v "${volume}":/src:ro \ + -v "${LOCAL_BACKUP_DIR}":/out \ + alpine:3 \ + sh -c "tar czf /out/${name} -C /src . && chown ${HOST_UID}:${HOST_GID} /out/${name}" +} + +log "Снимок данных: ${COUCHDB_DATA_VOLUME}" +tar_volume "$COUCHDB_DATA_VOLUME" "$data_out" +log "Снимок конфига: ${COUCHDB_CONFIG_VOLUME}" +tar_volume "$COUCHDB_CONFIG_VOLUME" "$config_out" + +# Контейнер поднимается СРАЗУ после копирования, до проверок и выгрузки: +# держать волт лежачим на время верификации архивов и заливки в S3 незачем. +log "Поднимаю ${COUCHDB_CONTAINER} — копирование закончено." +docker start "$COUCHDB_CONTAINER" >/dev/null +COUCHDB_WAS_STOPPED=0 +for _ in $(seq 1 "$START_TIMEOUT"); do + docker exec "$COUCHDB_CONTAINER" curl -fsS http://localhost:5984/_up >/dev/null 2>&1 && break + sleep 1 +done + +# --- проверки целостности --- +check_archive() { + local f="$1" floor="$2" what="$3" + local bytes + bytes=$(stat -c %s "$f" 2>/dev/null || echo 0) + if (( bytes < floor )); then + log "ERROR: ${what} — всего ${bytes} байт (< ${floor}), снимок пустой или битый." >&2 + notify "CouchDB backup: ${what} — ${bytes} байт, ниже порога ${floor}. Бэкап НЕ засчитан." + exit 1 + fi + if ! tar -tzf "$f" >/dev/null 2>&1; then + log "ERROR: ${what} не читается как tar.gz." >&2 + notify "CouchDB backup: архив ${what} повреждён, tar -tzf не прошёл. Бэкап НЕ засчитан." + exit 1 + fi + log "${what} OK: $(basename "$f") (${bytes} байт, файлов: $(tar -tzf "$f" | wc -l))" +} +check_archive "$data_out" "$MIN_DATA_BYTES" "снимок данных" +check_archive "$config_out" "$MIN_CONFIG_BYTES" "снимок конфига" + +# --- выгрузка в S3 (обязательна — см. guard 0) --- +for f in "$data_out" "$config_out"; do + key="${COUCHDB_S3_PREFIX%/}/$(basename "$f")" + log "Выгружаю в s3://${COUCHDB_S3_BUCKET}/${key}" + # AWS_CA_BUNDLE — та же поправка, что в backup.sh и backup-forgejo.sh: + # у aws-cli v2 свой вшитый набор корней, и корня Selectel в нём нет. + docker run --rm \ + -e AWS_ACCESS_KEY_ID="$COUCHDB_S3_ACCESS_KEY" \ + -e AWS_SECRET_ACCESS_KEY="$COUCHDB_S3_SECRET_KEY" \ + -e AWS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \ + -v "$LOCAL_BACKUP_DIR":/backup:ro \ + amazon/aws-cli:latest \ + --endpoint-url "$COUCHDB_S3_ENDPOINT" \ + s3 cp --no-progress "/backup/$(basename "$f")" "s3://${COUCHDB_S3_BUCKET}/${key}" +done +log "Выгрузка в S3 прошла." + +# --- локальная ротация --- +for pattern in "couchdb-data_" "couchdb-config_"; do + # shellcheck disable=SC2012 + ls -1t "${LOCAL_BACKUP_DIR}/${pattern}"*.tar.gz 2>/dev/null \ + | tail -n +"$((KEEP + 1))" \ + | xargs -r rm -f +done + +log "Бэкап CouchDB готов. Локальных копий оставлено: до ${KEEP} на каждый том." + +# Сентинел пишется ТОЛЬКО после выгрузки: сторож свежести обязан зеленеть по +# факту копии вне машины, а не по факту того, что скрипт дошёл до конца. +write_sentinel "$SENTINEL_FILE" diff --git a/ops/crontab-beget.cron b/ops/crontab-beget.cron index 4fa69fa5..16639595 100644 --- a/ops/crontab-beget.cron +++ b/ops/crontab-beget.cron @@ -24,6 +24,21 @@ # Сторож пропущенных прогонов для 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). diff --git a/ops/gendesign-backup-couchdb.default.example b/ops/gendesign-backup-couchdb.default.example new file mode 100644 index 00000000..81bccbcd --- /dev/null +++ b/ops/gendesign-backup-couchdb.default.example @@ -0,0 +1,55 @@ +# Образец /etc/default/gendesign-backup-couchdb +# +# Читается ops/backup-couchdb.sh. Файл содержит ключ S3 — держать 0600 и +# владельцем того пользователя, под которым стоит крон-задача. +# +# Установка: +# sudo install -m 0600 -o gendesign -g gendesign \ +# ops/gendesign-backup-couchdb.default.example /etc/default/gendesign-backup-couchdb +# sudo -e /etc/default/gendesign-backup-couchdb # подставить реальные ключи +# +# ЭТОТ ФАЙЛ НЕОБЯЗАТЕЛЕН. Если COUCHDB_S3_ENDPOINT и COUCHDB_S3_ACCESS_KEY не +# заданы, скрипт берёт S3_* из /etc/default/gendesign-backup — того же ключа, +# которым уже выгружается основной бэкап, но под своим префиксом couchdb/. +# Заводить файл стоит, когда для волта появится ОТДЕЛЬНЫЙ узкий ключ (как у +# forgejo): своя область доступа лучше общей, просто не ценой отсутствия +# бэкапа вовсе. +# +# Если не настроено ни здесь, ни там — скрипт откажется работать и НЕ станет +# останавливать CouchDB: бэкап без выгрузки за пределы машины смысла не имеет. + +# --- S3 (либо здесь, либо фолбэк на /etc/default/gendesign-backup) ---------- +COUCHDB_S3_ENDPOINT=https://s3.ru-1.storage.selcloud.ru +COUCHDB_S3_BUCKET=gendsgn-backups +COUCHDB_S3_PREFIX=couchdb/ +COUCHDB_S3_ACCESS_KEY= +COUCHDB_S3_SECRET_KEY= + +# --- что копируем (значения по умолчанию совпадают с боевыми) --------------- +# Имена берутся из docker-compose.obsidian.yml, проект gendesign-obsidian. +#COUCHDB_CONTAINER=gendesign-couchdb +#COUCHDB_DATA_VOLUME=gendesign-obsidian_couchdb_data +#COUCHDB_CONFIG_VOLUME=gendesign-obsidian_couchdb_config + +# --- локальное хранение ----------------------------------------------------- +#LOCAL_BACKUP_DIR=/opt/gendesign/backups/couchdb +#KEEP=7 + +# --- пороги целостности ----------------------------------------------------- +# Про объём, а не про наличие файла: пустой архив весит около сотни байт и без +# порога неотличим от настоящего бэкапа. Поднимать, если волт заметно вырос. +#MIN_DATA_BYTES=1048576 +#MIN_CONFIG_BYTES=256 + +# Сколько секунд ждать ответа /_up после подъёма контейнера. +#START_TIMEOUT=60 + +# --- оповещения ------------------------------------------------------------- +# Дублировать сюда ничего не надо: notify() из ops/lib-backup.sh, не найдя +# TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID в окружении, сам читает +# /etc/default/gendesign-backup. То есть канал общий с остальными бэкапами. +# Переопределяй только если этому бэкапу нужен ОТДЕЛЬНЫЙ адресат: +#TELEGRAM_BOT_TOKEN= +#TELEGRAM_CHAT_ID= +# Либо укажи другой файл, откуда notify() возьмёт настройки канала: +#BACKUP_ENV_FILE=/etc/default/gendesign-backup