warm: self-heal wedged dnsmasq, run after deploy, shared state dir
All checks were successful
Deploy DNS Configuration / deploy (push) Successful in 1h15m4s
All checks were successful
Deploy DNS Configuration / deploy (push) Successful in 1h15m4s
dnsmasq adds IPs to an nft set only on a fresh upstream reply; a cache hit never refreshes the set. On Archie the :5350 instance also wedged: TCP child processes first, then the main process, logged 'nftset ... netlink: Error: cache initialization failed: Protocol error' on every add and stopped filling bbrkn_v4/v6 until restarted. warm-nftset.sh now counts those errors for the main PID during the run (journalctl _PID=) and, if any, restarts the service and warms again; exit 1 if it still fails. The state dir defaults to /var/lib/bbrkn so the root cron job and the deploy share one lock (LOCK_WAIT lets deploy wait). deploy-to-gateway.sh runs the warmer right after flushing the sets, since clients keep old IPs cached and would bypass the tunnel until the next fresh resolve. A warm failure only warns; it does not roll back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR7zpSsdX28T4Kn6v4jPSS
This commit is contained in:
parent
a5ee057c59
commit
8598a1a48f
4 changed files with 107 additions and 18 deletions
23
README.md
23
README.md
|
|
@ -174,6 +174,7 @@ CACHE_TTL_DAYS=0 make generate
|
|||
6. Сбрасывает nft-сеты `bbrkn_v4`/`bbrkn_v6` (устаревшие IP иначе висят до timeout 24 ч).
|
||||
7. Health check: базовый DNS через pihole `:53` + end-to-end проверка nftset-захвата (резолв bbrkn-домена через `:5350` → сет наполнился).
|
||||
8. При ошибке на шагах 5–7 — **автоматически откатывается**: восстанавливает оба бэкапа и перезапускает оба инстанса со старой конфигурацией.
|
||||
9. После успешного деплоя запускает `warm-nftset.sh` — сеты только что очищены, а клиенты держат старые IP в кэше. Ошибка прогрева деплой не откатывает (только `WARN`).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -183,6 +184,10 @@ CACHE_TTL_DAYS=0 make generate
|
|||
|
||||
`scripts/warm-nftset.sh` закрывает эту дыру: заново резолвит **все** домены из задеплоенного `90-nftset.conf` (база + связанные субдомены) **напрямую** через `dig @127.0.0.1 -p 5350`, минуя кэш FTL, — каждый запрос гарантированно доходит до тегирующего инстанса.
|
||||
|
||||
> **У `:5350` должен быть выключен кэш** (`cache-size=0` в `/etc/dnsmasq.conf` на шлюзе). dnsmasq добавляет IP в сет **только при свежем ответе upstream** — ответ из собственного кэша сет не обновляет. Кэширует pihole перед ним.
|
||||
|
||||
**Самовосстановление.** dnsmasq иногда «клинит» на записи в сеты: основной процесс на каждую попытку пишет в журнал `nftset inet filter bbrkn_v4 netlink: Error: cache initialization failed: Protocol error` и больше ничего в сеты не добавляет до рестарта (наблюдалось под нагрузкой; начинается с дочерних TCP-процессов). Скрипт после прогона считает такие ошибки у основного процесса (`journalctl _PID=…`); если они есть — `systemctl restart $HOST_DNSMASQ_SVC` и повторный прогрев. Если не помогло — `exit 1` и `FAIL` в логе.
|
||||
|
||||
> **Запускать только на шлюзе.** Инстанс `:5350` слушает `listen-address=127.0.0.1` и с других хостов LAN недоступен. Список доменов берётся из задеплоенного конфига, так что скрипт всегда работает с актуальным после последнего деплоя списком.
|
||||
|
||||
```bash
|
||||
|
|
@ -190,11 +195,14 @@ CACHE_TTL_DAYS=0 make generate
|
|||
make warm
|
||||
./scripts/warm-nftset.sh
|
||||
|
||||
# ежечасно по cron (пользователь на шлюзе, sudo без пароля для nft)
|
||||
crontab -e
|
||||
17 * * * * /path/to/bbrkn/scripts/warm-nftset.sh >/dev/null 2>&1
|
||||
# ежечасно по cron — так стоит на Archie:
|
||||
install -m 0755 scripts/warm-nftset.sh /usr/local/sbin/bbrkn-warm
|
||||
cat /etc/cron.d/bbrkn-warm
|
||||
17 * * * * root /usr/local/sbin/bbrkn-warm >/dev/null 2>&1
|
||||
```
|
||||
|
||||
Копия в `/usr/local/sbin` **не обновляется деплоем** — после правок скрипта переустановить вручную. Деплой (CI) запускает скрипт из репо, `STATE_DIR` у них общий, поэтому lock тоже общий.
|
||||
|
||||
### Переменные окружения
|
||||
|
||||
| Переменная | По умолчанию | Описание |
|
||||
|
|
@ -204,8 +212,11 @@ crontab -e
|
|||
| `PARALLEL` | `8` | Одновременных запросов к `:5350` |
|
||||
| `DIG_TIMEOUT` / `DIG_TRIES` | `3` / `2` | Таймаут и число попыток на домен |
|
||||
| `WARM_PING` | `0` | `1` — дополнительно пинговать первый A-адрес (только для отладки) |
|
||||
| `STATE_DIR` | `~/.local/state/bbrkn` | Лог `warm.log` и lock-файл |
|
||||
| `STATE_DIR` | `/var/lib/bbrkn` | Лог `warm.log` и lock-файл (общие для cron и деплоя) |
|
||||
| `LOG_MAX_BYTES` | `4194304` | Порог ротации лога в `warm.log.1` |
|
||||
| `LOCK_WAIT` | `0` | Секунд ждать идущий прогон (`0` — сразу выйти с `SKIP`; деплой ждёт `WARM_LOCK_WAIT=300`) |
|
||||
| `HOST_DNSMASQ_SVC` | `dnsmasq` | systemd-сервис `:5350` — для детектора заклинивания и рестарта |
|
||||
| `SELF_HEAL` | `1` | `0` — только сообщать о заклинивании, не перезапускать dnsmasq |
|
||||
|
||||
Параллельные запуски блокируются через `flock` — медленный прогон не наложится на следующий по cron.
|
||||
|
||||
|
|
@ -213,11 +224,11 @@ crontab -e
|
|||
|
||||
```
|
||||
2026-08-05T20:46:57+03:00 START domains=1059 conf=/etc/dnsmasq.d/90-nftset.conf v4=526 v6=305
|
||||
2026-08-05T20:48:44+03:00 DONE ok=1036 noping=0 dnsfail=23 v4=526->2203 v6=305->1440
|
||||
2026-08-05T20:48:44+03:00 DONE ok=1036 noping=0 dnsfail=23 nftset_errors=0 healed=0 v4=526->2203 v6=305->1440
|
||||
2026-08-05T20:48:44+03:00 dnsfail: azureedge.net cdn-telegram.org kinozal.tv ...
|
||||
```
|
||||
|
||||
`v4=X->Y` — число элементов в сете до и после прогона (считается через `sudo -n nft list set`; без прав sudo вместо числа будет `?`, на сам прогрев это не влияет). Элементов больше, чем доменов — у CDN на один домен приходится несколько адресов. Домены в `dnsfail` не резолвятся вообще (мёртвые записи, NXDOMAIN) — кандидаты на удаление из `domains.txt`.
|
||||
`v4=X->Y` — число элементов в сете до и после прогона (считается через `nft list set`; не под root — через `sudo -n`, без прав будет `0`, на сам прогрев это не влияет). `nftset_errors` — ошибки записи в сет у основного процесса dnsmasq, `healed=1` — был рестарт. Элементов больше, чем доменов — у CDN на один домен приходится несколько адресов. Домены в `dnsfail` не резолвятся вообще (мёртвые записи, NXDOMAIN) — кандидаты на удаление из `domains.txt`.
|
||||
|
||||
> `WARM_PING=1` на шлюзе почти всегда даёт `noping`: пакеты, рождённые на самом шлюзе, идут через `OUTPUT` и не проходят цепочку `prerouting_mangle`, то есть уходят в WAN без метки. Это диагностический режим, не показатель проблемы.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue