Record the production deployment on port 18000
Plan and summary of the containerized deployment (six ASNs, three FQDNs, token in .env, published on all interfaces, backups on the volume) and the updated analysis. The .env file stays out of git. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
50ed8102bc
commit
7e3b4526f3
3 files changed
+66
-5
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Состояние после 17 доработок (план и итоги каждой лежат в `docs/`): надёжность и безопасность, тесты в контейнере, форматы вывода, разделение процессов, управление ASN/FQDN через API, контейнер приложения, SQLite, `POST /collect`, `GET /addresses/diff`, репозиторий git, закрепление версий, резервные копии и автовосстановление, защита ввода и данных, защита от пустой выдачи, исправления ревью 5-10, защита от пустых копий, наблюдаемость. Предыдущая версия этого файла описывала состояние после восьми доработок. Отчёт ревью: `review-2026-09-21.md` (находки 1-11 закрыты).
|
Состояние после 17 доработок (план и итоги каждой лежат в `docs/`): надёжность и безопасность, тесты в контейнере, форматы вывода, разделение процессов, управление ASN/FQDN через API, контейнер приложения, SQLite, `POST /collect`, `GET /addresses/diff`, репозиторий git, закрепление версий, резервные копии и автовосстановление, защита ввода и данных, защита от пустой выдачи, исправления ревью 5-10, защита от пустых копий, наблюдаемость. Предыдущая версия этого файла описывала состояние после восьми доработок. Отчёт ревью: `review-2026-09-21.md` (находки 1-11 закрыты).
|
||||||
|
|
||||||
Тестовый запуск на копиях боевых файлов с реальным ASN 62041 выполнен и описан в `summary-real-data-run.md`.
|
Тестовый запуск на копиях боевых файлов с реальным ASN 62041 описан в `summary-real-data-run.md`; **боевое развёртывание в контейнерах на порту 18000 выполнено 2026-09-21** (`summary-production-deploy.md`, работает по расписанию).
|
||||||
|
|
||||||
Проект: 7 модулей Python, 1719 строк (`db.py` 544, `cidr_collector.py` 386, `api_server.py` 381, `collector_daemon.py` 191, `formatters.py` 115, `storage.py` 70, `healthcheck.py` 32), 30 тестов (27 функций, 5 файлов и `conftest.py`), 37 документов в `docs/` (17 планов, 17 итогов, 2 анализа, ревью), 9 коммитов, ветка `main` синхронизирована с `origin` (`artstore.rxmsk.ru`).
|
Проект: 7 модулей Python, 1719 строк (`db.py` 544, `cidr_collector.py` 386, `api_server.py` 381, `collector_daemon.py` 191, `formatters.py` 115, `storage.py` 70, `healthcheck.py` 32), 30 тестов (27 функций, 5 файлов и `conftest.py`), 37 документов в `docs/` (17 планов, 17 итогов, 2 анализа, ревью), 9 коммитов, ветка `main` синхронизирована с `origin` (`artstore.rxmsk.ru`).
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
| Защита от пустой выдачи | Потеря базы без копий или восстановление из пустой копии при настроенных источниках: метка `db_recreated.json`, `503` на `/addresses` и `/addresses/diff` до нового сбора; пустая база не копируется. |
|
| Защита от пустой выдачи | Потеря базы без копий или восстановление из пустой копии при настроенных источниках: метка `db_recreated.json`, `503` на `/addresses` и `/addresses/diff` до нового сбора; пустая база не копируется. |
|
||||||
| Данные DNS и внешний источник | Фильтр глобальных адресов (`allow_non_global_ips`), повторы запросов к RIPEstat с `sourceapp` и потолком `Retry-After`. |
|
| Данные DNS и внешний источник | Фильтр глобальных адресов (`allow_non_global_ips`), повторы запросов к RIPEstat с `sourceapp` и потолком `Retry-After`. |
|
||||||
| Наблюдаемость | Состояние каждого источника (таблица `source_status`), блок `sources` и `degraded` в `/health`, `GET /sources`, итоговая строка запуска в логе. |
|
| Наблюдаемость | Состояние каждого источника (таблица `source_status`), блок `sources` и `degraded` в `/health`, `GET /sources`, итоговая строка запуска в логе. |
|
||||||
|
| Боевое развёртывание | Compose на `192.168.5.9:18000` (доступ открыт для всех, токен в `.env`), шесть ASN и три FQDN, миграция боевых файлов без потерь, плановый запуск проверен; копии на томе (`summary-production-deploy.md`). |
|
||||||
| Ревью и граф знаний | Отчёт ревью (11 находок, все закрыты), граф `graphify-out/` (вне git и образа). |
|
| Ревью и граф знаний | Отчёт ревью (11 находок, все закрыты), граф `graphify-out/` (вне git и образа). |
|
||||||
| Тесты | 30 проверок, запуск в контейнере, изоляция файлов состояния (`conftest.py`). |
|
| Тесты | 30 проверок, запуск в контейнере, изоляция файлов состояния (`conftest.py`). |
|
||||||
|
|
||||||
@@ -39,7 +40,6 @@
|
|||||||
|
|
||||||
| Направление | Статус |
|
| Направление | Статус |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Боевое развёртывание с полной конфигурацией | Не начато; тестовый запуск на копиях боевых файлов с AS62041 выполнен (`summary-real-data-run.md`) |
|
|
||||||
| Уведомления (webhook, Telegram) | Не начато; основа (журнал, `/health`, `/sources`) есть |
|
| Уведомления (webhook, Telegram) | Не начато; основа (журнал, `/health`, `/sources`) есть |
|
||||||
| Метрики Prometheus (`/metrics`) | Исключены из плана решением пользователя; при необходимости - отдельная доработка |
|
| Метрики Prometheus (`/metrics`) | Исключены из плана решением пользователя; при необходимости - отдельная доработка |
|
||||||
| Ограничение частоты `POST /collect` | Не начато |
|
| Ограничение частоты `POST /collect` | Не начато |
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
| 6 | Один общий токен, без ротации и аудита. | Не закрыт |
|
| 6 | Один общий токен, без ротации и аудита. | Не закрыт |
|
||||||
| 7 | Тестов минимум, что соответствует правилам проекта. | Осознанно |
|
| 7 | Тестов минимум, что соответствует правилам проекта. | Осознанно |
|
||||||
| 8 | `POST /collect` без ограничения частоты: повторные запросы во время сбора пропускаются, но защиты от нагрузки на RIPE нет (при этом запросы к RIPEstat теперь идут с повторами). | Не закрыт |
|
| 8 | `POST /collect` без ограничения частоты: повторные запросы во время сбора пропускаются, но защиты от нагрузки на RIPE нет (при этом запросы к RIPEstat теперь идут с повторами). | Не закрыт |
|
||||||
| 9 | Журнал diff и состояние источников проверены на копиях боевых файлов и одном реальном ASN (база 45 КБ, ответы 6-9 мс); поведение при шести ASN, по расписанию и во времени (TTL, рост журнала) не наблюдалось. | Частично закрыт |
|
| 9 | Журнал diff и состояние источников: на боевом развёртывании с шестью ASN и расписанием база и ответы малы (десятки КБ, миллисекунды); поведение во времени (сутки и более, TTL, рост журнала) ещё предстоит наблюдать. | Частично закрыт |
|
||||||
| 10 | Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. | Не закрыт (описан в README) |
|
| 10 | Копии базы лежат на том же томе, что и база: защита от порчи файла, но не от потери тома. | Не закрыт (описан в README) |
|
||||||
| 11 | Нет активных оповещений: о сбое источников можно узнать только опросом `/health` или из лога. | Не закрыт |
|
| 11 | Нет активных оповещений: о сбое источников можно узнать только опросом `/health` или из лога. | Не закрыт |
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
| # | Наблюдение | Состояние |
|
| # | Наблюдение | Состояние |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | **Боевое развёртывание не выполнено.** Миграция боевых файлов проверена в изолированном стенде на их копиях (`summary-real-data-run.md`: без потерь, сбор AS62041 и восстановление на реальных данных работают). В каталоге проекта нет `ripe.db`; `data.json` (6 ASN) и `fqdn_data.json` (4 имени) остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию сразу до схемы версии 3: `last_seen` старых записей станет равным времени миграции, журнал diff и состояние источников начнутся пустыми (клиентам стартовать с `X-Changes-Cursor`), первые запуски сбора создадут состояние источников. | Частично закрыто |
|
| 1 | ~~Боевое развёртывание не выполнено.~~ **Выполнено 2026-09-21** (`summary-production-deploy.md`); ниже - исходное описание. Миграция боевых файлов проверена в изолированном стенде на их копиях (`summary-real-data-run.md`: без потерь, сбор AS62041 и восстановление на реальных данных работают). В каталоге проекта нет `ripe.db`; `data.json` (6 ASN) и `fqdn_data.json` (4 имени) остались в старом формате; всё проверено только на копиях. Первый запуск на боевых данных выполнит миграцию сразу до схемы версии 3: `last_seen` старых записей станет равным времени миграции, журнал diff и состояние источников начнутся пустыми (клиентам стартовать с `X-Changes-Cursor`), первые запуски сбора создадут состояние источников. | Закрыто |
|
||||||
| 2 | ~~`/health` не видит сбоев источников.~~ Сбои учитываются по каждому источнику, порог `source_failure_threshold` (по умолчанию 3): при суточном расписании FQDN это три дня до `degraded`. | Закрыто |
|
| 2 | ~~`/health` не видит сбоев источников.~~ Сбои учитываются по каждому источнику, порог `source_failure_threshold` (по умолчанию 3): при суточном расписании FQDN это три дня до `degraded`. | Закрыто |
|
||||||
| 3 | **Безымянные образы Docker: 21 на хосте.** Часть - от пересборок тестового образа `ripe-tests` при разработке, на хосте есть и чужие (`docker image prune` затронет все). | Ухудшилось (было 3) |
|
| 3 | **Безымянные образы Docker: 21 на хосте.** Часть - от пересборок тестового образа `ripe-tests` при разработке, на хосте есть и чужие (`docker image prune` затронет все). | Ухудшилось (было 3) |
|
||||||
| 4 | **Повреждённый `config.json`** переименовывается при чтении; первый успешный `POST /asns` после этого создаст файл без остальных источников, расписания и `ttl_days`. | Без изменений |
|
| 4 | **Повреждённый `config.json`** переименовывается при чтении; первый успешный `POST /asns` после этого создаст файл без остальных источников, расписания и `ttl_days`. | Без изменений |
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
## Рекомендуемый порядок
|
## Рекомендуемый порядок
|
||||||
|
|
||||||
1. **Боевое развёртывание с полной конфигурацией (главный шаг; тестовый запуск с AS62041 пройден).** Перед запуском: копия `config.json`, `data.json`, `fqdn_data.json` вне каталога проекта и вне тома (миграция переименует оригиналы в `*.migrated-*`, но копия на случай ошибки обязательна). Затем `docker compose up -d` с переносом файлов в том (порядок в README), проверка `/health`, `/sources`, `/addresses` и `/addresses/diff`, первый ручной сбор через `POST /collect`, оценка размера базы и журнала, выбор порога `source_failure_threshold`. Нужен отдельный план с откатом.
|
1. ~~Боевое развёртывание~~ **выполнено** (порт 18000, шесть ASN); далее - наблюдение: 03:00 плановый сбор FQDN, 04:30 первая плановая копия, суточный просмотр `/health` и `/sources`. Исходный порядок запуска: копия `config.json`, `data.json`, `fqdn_data.json` вне каталога проекта и вне тома (миграция переименует оригиналы в `*.migrated-*`, но копия на случай ошибки обязательна). Затем `docker compose up -d` с переносом файлов в том (порядок в README), проверка `/health`, `/sources`, `/addresses` и `/addresses/diff`, первый ручной сбор через `POST /collect`, оценка размера базы и журнала, выбор порога `source_failure_threshold`. Нужен отдельный план с откатом.
|
||||||
2. **Обновить граф** (`/graphify . --update`, документы выгружать целиком) и при желании поставить хук после коммита.
|
2. **Обновить граф** (`/graphify . --update`, документы выгружать целиком) и при желании поставить хук после коммита.
|
||||||
3. **Уведомления** (webhook, Telegram) на основе журнала и состояния источников: закрывает риск 11.
|
3. **Уведомления** (webhook, Telegram) на основе журнала и состояния источников: закрывает риск 11.
|
||||||
4. **Архитектурный рефакторинг:** `settings.py` (пути и умолчания), разделение `db.py` и `api_server.py`; снимает наблюдения 10-11.
|
4. **Архитектурный рефакторинг:** `settings.py` (пути и умолчания), разделение `db.py` и `api_server.py`; снимает наблюдения 10-11.
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# План: боевое развёртывание в контейнерах (порт 18000)
|
||||||
|
|
||||||
|
Источник: `docs/analysis-2026-09-21.md` (рекомендуемый порядок, п. 1), `docs/summary-real-data-run.md` (тестовый запуск с AS62041 пройден).
|
||||||
|
|
||||||
|
## Решения пользователя
|
||||||
|
- Токен записывается в переменные окружения проекта (`.env`, вне git).
|
||||||
|
- Развёртывание в контейнерах на порту **18000** (если свободен; проверено: свободен).
|
||||||
|
- Доступ открыт для всех: порт публикуется на всех интерфейсах хоста (доверенный контур; TLS нет - риск 5 анализа принят).
|
||||||
|
- Резервные копии остаются на томе `/data/backups`, отдельно не выносятся (риск 10 принят).
|
||||||
|
|
||||||
|
## Параметры
|
||||||
|
- Проект Compose по умолчанию (`ripe_cidr_collector`), образ `ripe-cidr-collector`, том `ripe_cidr_collector_ripe_data`, перезапуск `unless-stopped` (Docker на хосте включён при загрузке).
|
||||||
|
- `.env` (права 600): `RIPE_API_TOKEN` (случайный, 64 hex-символа), `API_PORT=18000`, `TZ=Europe/Moscow` (часовой пояс хоста; расписания `*/15` для ASN, `0 3 * * *` для FQDN и `30 4 * * *` для копий считаются по нему).
|
||||||
|
- Данные: в том копируются **копии** реальных `config.json` (шесть ASN и три FQDN), `data.json`, `fqdn_data.json`; исходные файлы проекта не меняются (сверка контрольных сумм). Миграция в SQLite выполняется при первом обращении.
|
||||||
|
|
||||||
|
## Шаги
|
||||||
|
1. Проверка предпосылок, контрольные суммы исходных файлов.
|
||||||
|
2. Токен и `.env`; сборка образа; перенос копий файлов в том; `docker compose up -d`.
|
||||||
|
3. Проверка: сервисы `healthy`, миграция без потерь (24 префикса, 4 значения FQDN), часовой пояс контейнеров.
|
||||||
|
4. Первый сбор по всем источникам (`POST /collect`): `/sources`, `/health`, `/addresses`, diff; источник AS11917 (в данных февраля был пуст).
|
||||||
|
5. Доступ извне: запрос по адресу хоста (не `127.0.0.1`), запись без токена отклоняется (401), с токеном проходит.
|
||||||
|
6. Наблюдение штатного расписания (ближайший квартал часа для ASN), если ожидание короткое.
|
||||||
|
7. Итоги `docs/summary-production-deploy.md`, обновление анализа, сверка сумм исходных файлов.
|
||||||
|
|
||||||
|
## Риски и откат
|
||||||
|
- Токен передаётся по HTTP открытым текстом, порт доступен всем в сети: принято (доверенный контур).
|
||||||
|
- Копии на том же томе: защита от порчи файла, не от потери тома: принято.
|
||||||
|
- Откат: `docker compose down` (данные остаются в томе) или `docker compose down -v` (с удалением тома); исходные файлы проекта не затрагиваются.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Итоги: боевое развёртывание в контейнерах (порт 18000)
|
||||||
|
|
||||||
|
План: `docs/plan-production-deploy.md`. Предшествовал тестовый запуск `docs/summary-real-data-run.md`.
|
||||||
|
|
||||||
|
## Параметры развёртывания
|
||||||
|
- **Адрес:** `http://192.168.5.9:18000` (порт опубликован на всех интерфейсах хоста, доступ открыт для всех в доверенном контуре, TLS нет; риск 5 принят). Файрвол на хосте входящий трафик не фильтрует (`INPUT ACCEPT`).
|
||||||
|
- **Токен:** `RIPE_API_TOKEN` (64 hex-символа, сгенерирован) записан в `/opt/lvraid/claude/ripe_cidr_collector/.env` (права 600, файл в `.gitignore`); там же `API_PORT=18000` и `TZ=Europe/Moscow` (часовой пояс хоста: расписания считаются по московскому времени). Смена токена: изменить `.env` и выполнить `docker compose up -d`.
|
||||||
|
- **Контейнеры:** проект Compose по умолчанию (`ripe_cidr_collector`), сервисы `api` и `collector`, образ `ripe-cidr-collector`, том `ripe_cidr_collector_ripe_data`, перезапуск `unless-stopped` (Docker на хосте включён при загрузке).
|
||||||
|
- **Данные:** в том скопированы копии реальных `config.json` (6 ASN: 62014, 62041, 59930, 44907, 211157, 11917; 3 FQDN), `data.json`, `fqdn_data.json`; исходные файлы проекта не менялись (контрольные суммы совпали).
|
||||||
|
- **Расписание:** ASN `*/15 * * * *`, FQDN `0 3 * * *`, копия базы `30 4 * * *` (по умолчанию), копии на том же томе (`/data/backups`, 7 штук), отдельно не выносятся (риск 10 принят).
|
||||||
|
|
||||||
|
## Результаты проверки
|
||||||
|
| Проверка | Итог |
|
||||||
|
|---|---|
|
||||||
|
| Сервисы | `api` и `collector` `healthy`, порт `0.0.0.0:18000`, часовой пояс контейнеров MSK. |
|
||||||
|
| Миграция | Схема версии 3, 24 префикса и 4 значения FQDN (28 строк) без потерь, оригиналы в томе переименованы, журнал пуст. |
|
||||||
|
| Первый сбор (`POST /collect`, реальные RIPEstat и DNS) | 6 ASN из 6 успешно, 3 FQDN из 3 успешно; `+18` префиксов и `+3` строки IP; сбоев нет. |
|
||||||
|
| Состояние источников | `/sources`: у всех источников 0 сбоев; AS11917 отвечает без префиксов (`addresses: 0`, успех), как и в данных февраля. |
|
||||||
|
| Diff | С момента миграции 19 добавлений, 0 удалений; все старые значения подтверждены RIPE. AS62014 теперь анонсирует и прежние префиксы, и их более специфичные части (`91.108.16.0/23`, `91.108.18.0/23`, `91.108.56.0/24`, `91.108.57.0/24`): для потребителей есть смысл использовать `aggregate=true`. |
|
||||||
|
| Доступ извне | По адресу хоста: `/health` 200, `/addresses` 45 значений; запись без токена и с неверным токеном - 401. |
|
||||||
|
| Штатное расписание | Плановый запуск ASN в 11:45:00: 6 из 6, `+0/-0`, ошибок нет; следующий 12:00. |
|
||||||
|
| Логи | Ошибок и трейсбеков нет. |
|
||||||
|
|
||||||
|
## Что наблюдать
|
||||||
|
- **Завтра 03:00:** первый плановый сбор FQDN; **04:30:** первая плановая копия базы (`/health` -> `jobs.backup`, каталог `/data/backups`).
|
||||||
|
- `GET /health` (`status`, `sources.*.failing`) и `GET /sources`; порог сбоев `source_failure_threshold` = 3.
|
||||||
|
- `google.com` (адрес из старого файла, в конфигурации его нет) истечёт по TTL через 90 дней.
|
||||||
|
- Размер базы и журнала (после миграции: десятки КБ).
|
||||||
|
|
||||||
|
## Замечания
|
||||||
|
- Токен хранится открытым текстом в `.env` на хосте и передаётся по HTTP (доверенный контур, риск 5); один общий токен без ротации и аудита (риск 6).
|
||||||
|
- Копии на том же томе не защищают от потери тома (риск 10).
|
||||||
|
- Управление: `docker compose ps`, `docker compose logs -f collector`, `docker compose down` (данные остаются в томе), `docker compose up -d`; обновление после изменений кода: `docker compose build && docker compose up -d`.
|
||||||
Reference in new issue
Block a user