Files
sqlite-backup-s3/README.md
T
vasyansk f166f95b44
docker-build / Build image (push) Successful in 11s
Add configurable retries for locked SQLite backups
Add SQLITE_TIMEOUT, BACKUP_RETRIES, and BACKUP_RETRY_DELAY
environment variables to handle "database is locked" errors during
backup. Retry the sqlite3 .backup command with configurable timeouts
and delays, and clean up any WAL/SHM files that may interfere with
subsequent attempts. Bump version to 1.2.2.
2026-09-01 12:15:38 +07:00

104 lines
4.7 KiB
Markdown
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.
# бекапирование sqlite в minio
```yaml
services:
sqlite_backup:
image: git.realmanual.ru/pub/sqlite-backup-s3
container_name: sqlite_backup
restart: always
volumes:
- ./var/lib/data/:/data
environment:
- DB_FILE
- CRONTAB
- DELETE_AFTER
- KEEP_LAST
- TZ
- SQLITE_TIMEOUT
- BACKUP_RETRIES
- BACKUP_RETRY_DELAY
- MINIO_PATH
- MINIO_ACCOUNT_ID
- MINIO_APPLICATION_KEY
- MINIO_ENDPOINT
- MINIO_LOCATION
- HEALTHCHECK_URL
- HEALTHCHECK_UUID
```
пример .env
```bash
DB_FILE=/data/db.sqlite
CRONTAB="00 06 * * *"
DELETE_AFTER=10
KEEP_LAST=10
TZ=Asia/Novosibirsk
SQLITE_TIMEOUT=60000
BACKUP_RETRIES=5
BACKUP_RETRY_DELAY=30
MINIO_PATH=myminio://sqlite/master/
MINIO_ACCOUNT_ID=account
MINIO_APPLICATION_KEY=key
MINIO_ENDPOINT=https://s3.domain.ru
MINIO_LOCATION=ru-nsk
# необязательно: пинг в healthchecks.io (в т.ч. self-hosted)
HEALTHCHECK_URL=https://hc.domain.ru/ping
HEALTHCHECK_UUID=00000000-0000-0000-0000-000000000000
```
1. myminio - системно! не менять
2. проверьте настройки локации, не должно быть пусто
3. DELETE_AFTER - в днях
4. KEEP_LAST - минимальное число копий, которые сохраняются всегда
## Ротация
Удаление старых бекапов работает по двум условиям одновременно:
1. бекап старше `DELETE_AFTER` дней
2. и при этом не входит в `KEEP_LAST` самых свежих копий
То есть последние `KEEP_LAST` бекапов не удаляются никогда, даже если они старше `DELETE_AFTER` дней. Это защищает от потери всех копий, если контейнер долго стоял и новые бекапы не создавались.
`KEEP_LAST` по умолчанию `10`, если переменная не задана.
## Заблокированная база
Если базу пишет живой процесс (grafana, или не добитый старый под), `sqlite3 .backup` падает с `Error: database is locked`.
Бекап это переживает: соединение открывается с `.timeout SQLITE_TIMEOUT` (мс) — sqlite ждёт освобождения блокировки вместо мгновенной ошибки. Если за это время писатель не отпустил базу, попытка повторяется `BACKUP_RETRIES` раз с паузой `BACKUP_RETRY_DELAY` секунд.
| Переменная | Default | Что делает |
|---|---|---|
| `SQLITE_TIMEOUT` | `60000` | сколько мс ждать блокировку в рамках одной попытки |
| `BACKUP_RETRIES` | `5` | сколько попыток снять дамп |
| `BACKUP_RETRY_DELAY` | `30` | пауза между попытками, сек |
Максимальное время ожидания с дефолтами: `60s * 5 + 30s * 4 = 7 минут`. После этого — `exit 1` и пинг `/fail`.
Если база залочена *постоянно* — это не про бекап, а про то, что старый под не умер. Ретраи только прикрывают короткие окна.
## Healthchecks
Если `HEALTHCHECK_URL` пуст — пинги не отправляются, бекап работает как обычно.
Итоговый адрес: `${HEALTHCHECK_URL}/${HEALTHCHECK_UUID}`
| Момент | Запрос |
|---|---|
| старт бекапа | `.../${HEALTHCHECK_UUID}/start` |
| дамп снят, проверен `PRAGMA integrity_check`, запакован, залит в s3, размер в s3 сверен с локальным, старое удалено | `.../${HEALTHCHECK_UUID}` |
| любая ошибка на любом шаге | `.../${HEALTHCHECK_UUID}/fail` |
Для self-hosted инстанса `HEALTHCHECK_URL` — это адрес его ping-эндпоинта, например `https://hc.domain.ru/ping`.
## Как передаётся окружение в cron
`crond` из busybox запускает джобы с пустым окружением, поэтому `entrypoint.sh`
сохраняет env контейнера в `/tmp/container.env` (права 600), а cron-запись
вызывает `/scripts/backup.sh --from-cron`, который его подгружает.
Ручной запуск (`docker exec ... /scripts/backup.sh`) использует то окружение,
с которым его вызвали.