Документация: сверка README и deploy/*.md с кодом

- README: test без порта на хосте (только через домен, Secure-cookie), прод из реестра
  (build-push + docker compose up -d), лимиты перебора и регистраций, dev_admin.py в списке
  dev-кода, структура репозитория, раздел о бэкапах, отличия test от prod; отмечены
  известные проблемы (#69, #71, #72, #73).
- deploy/README.md: три сервиса (app + tunnel + backup), источники ключа туннеля для Pi,
  test и dev-туннеля, слот 9000 у временного прода.
- deploy/pi/README.md: контейнер backup, fail-fast по секретам, ADMIN_PASSWORD только при
  первом создании админа (#73), порядок обновления.
- deploy/vps/README.md: туннель-контейнер вместо autossh, сниппет (edge), единые имена
  файлов в примере сборки сертификатов, дописывать authorized_keys через >>.
- deploy/backup/README.md: первый бэкап на новом Pi, выбор снимка с данными при
  восстановлении (#74), метка keep, --no-pre-restore, служебные команды, причины unhealthy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
This commit is contained in:
2026-09-14 20:06:54 +03:00
co-authored by Claude Opus 5
parent 7579ca2d35
commit 63fd90e017
5 changed files with 206 additions and 98 deletions
+31 -14
View File
@@ -55,8 +55,8 @@
4. удаляет старые снимки по правилам хранения;
5. проверяет, что репозитории целы.
Раз в неделю (воскресенье, 05:30) дополнительно читает часть сохранённых данных и убеждается,
что последний снимок действительно восстанавливается.
Раз в неделю (воскресенье, 05:30) дополнительно читает часть сохранённых данных (10 %) и
убеждается, что БД из последнего снимка извлекается и проходит проверку целостности.
**Словарь**
@@ -646,7 +646,7 @@
| `Игроков` / `Партий` | сколько игроков и партий было в БД в этот момент — по ним легко найти «до поломки» |
| `Размер` | полный объём данных снимка |
| `Прирост` | сколько места снимок реально добавил в репозиторий |
| `Метки` | `scheduled` — по расписанию, `manual` — вручную, `pre-restore` — страховочный, прочие — имя, данное вручную |
| `Метки` | `scheduled` — по расписанию, `manual` — вручную, `pre-restore` — страховочный, `keep` + имя — именованный снимок (`run --tag имя`) |
Если локальный репозиторий повреждён или пуст, смотрите копию на VPS:
`docker compose exec backup fs-backup list vps`.
@@ -737,30 +737,44 @@
```
3. Дождитесь, пока приложение создаст пустую БД (`docker compose ps` → `app` `(healthy)`).
В журнале бэкапа это нормально (`docker compose logs backup`):
Контейнер `backup` стартует одновременно с `app` и сразу пробует сделать первый бэкап. В его
журнале (`docker compose logs backup`) нормально увидеть одно из двух:
```
В БД нет ни игроков, ни партий, а последний снимок в репозитории vps — с данными.
Похоже на новый или очищенный сервер: бэкап НЕ сделан, чтобы пустые данные не вытеснили историю.
```
- если `backup` успел раньше, чем `app` создал БД:
Это защита: пустой новый Pi не перезапишет историю на VPS.
```
ОШИБКА: БД /fs-db/forbidden_stars.db не найдена — приложение ещё ни разу не запускалось?
Первый бэкап не удался — следующая попытка по расписанию.
```
4. Посмотрите снимки на VPS и выберите нужный (обычно самый свежий):
- если БД уже была:
```
В БД нет ни игроков, ни партий, а последний снимок в репозитории vps — с данными.
Похоже на новый или очищенный сервер: бэкап НЕ сделан, чтобы пустые данные не вытеснили историю.
```
Это защита: пустой новый Pi не перезапишет историю на VPS.
4. Посмотрите снимки на VPS и выберите нужный (обычно самый свежий **с данными**):
```bash
docker compose exec backup fs-backup list vps
```
5. Восстановите:
Проверьте, что у выбранного снимка в столбцах `Игроков`/`Партий` числа, а не `0` и не `?`.
Защита выше не распознаёт БД без таблиц: если первый бэкап попал ровно в момент создания
БД, в списке может появиться свежий снимок с `?` (задача #74). Такой снимок не выбирайте.
5. Восстановите, подставив ID из `list vps`:
```bash
docker compose stop app
docker compose exec backup fs-backup restore latest --repo vps --yes
docker compose exec backup fs-backup restore <ID> --repo vps --yes
docker compose start app
```
Вместо `latest` можно указать ID из `list vps`.
Если самый свежий снимок в `list vps` — с данными, вместо ID можно написать `latest`.
6. Проверьте сайт. Затем сделайте снимок вручную, чтобы локальная копия появилась сразу:
@@ -852,7 +866,7 @@ docker compose logs --tail 100 backup
| `снимок '…' не найден в репозитории` | опечатка в ID или снимок в другом репозитории | `fs-backup list` и `fs-backup list vps` |
| `service "backup" is not running` | контейнер не запущен | `docker compose up -d backup` |
| `permission denied while trying to connect to the Docker daemon socket` | пользователь Pi не в группе `docker` | `sudo usermod -aG docker $USER`, перезайти по SSH |
| `docker compose ps` → `backup` `unhealthy` | последний успешный бэкап старше `BACKUP_MAX_AGE_HOURS` | `docker compose exec backup fs-backup health` покажет причину, дальше по таблице |
| `docker compose ps` → `backup` `unhealthy` | последний успешный бэкап старше `BACKUP_MAX_AGE_HOURS`, успешных бэкапов ещё не было или не задан `BACKUP_PASSWORD` | `docker compose exec backup fs-backup health` покажет причину, дальше по таблице |
**Про `recover`.** Команда сама определяет, на каком этапе оборвалось восстановление:
- если замена успела пройти во всех томах — дочищает промежуточные папки, восстановленные
@@ -907,8 +921,11 @@ docker volume rm <имя тома>
| `export <ID\|latest> [--repo …]` | снимок в tar в stdout: `docker compose exec -T backup fs-backup export latest > fs.tar` |
| `restic <local\|vps> <аргументы>` | любая команда restic с настройками контейнера, например `restic vps stats` |
| `help` | краткая справка |
| `init`, `info`, `health`, `has-snapshots` | служебные: создать репозитории, данные снимка для скриптов ПК, healthcheck, проверка «есть ли снимки» при старте |
Без `--yes` команды `restore` и `import` только показывают, что собираются сделать.
Флаг `--no-pre-restore` у `restore`/`import` пропускает страховочный снимок — используйте,
только если текущие данные точно не нужны.
### Скрипт ПК