Collector daemon, FastAPI server (addresses, diff, collect, sources), SQLite storage with change journal, Docker Compose deployment, tests, documentation and project rules. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7.7 KiB
План: контейнер для приложения (Dockerfile и compose)
Context
Сейчас приложение ставится вручную: venv, два systemd/OpenRC-сервиса, ручное управление пользователем и правами. Контейнеры используются только для тестов (Dockerfile.test). Цель: запускать API и демон-сборщик одной командой docker compose up -d, с данными на томе, без root и с проверками состояния. Формат данных и API не меняются.
Решение пользователя: порт 8000 публикуется наружу без TLS (как сейчас). Риск: токен X-API-Key идёт по HTTP открытым текстом, защита только файрволом; это фиксируется в README, TLS - отдельная доработка.
Артефакты по правилам проекта (создаются при реализации)
docs/plan-app-container.md- копия этого плана (первым шагом)docs/summary-app-container.md- итоги (в конце)- обновить
README.md(раздел про Docker Compose, миграция существующих данных)
Архитектура
Один образ, два сервиса compose (api, collector) с общим томом ripe_data, смонтированным в /data. Сервисы по-прежнему общаются только файлами (config.json, data.json, fqdn_data.json, status.json, *.lock).
Изменения
1. Код: настраиваемый каталог данных (минимальная правка)
cidr_collector.py: добавитьDATA_DIR = os.environ.get("RIPE_DATA_DIR", BASE_DIR); путиCONFIG_FILE,DATA_FILE,FQDN_DATA_FILE,STATUS_FILEстроятся отDATA_DIR. Без переменной поведение прежнее (systemd/venv-установки не ломаются).collector_daemon.py:LOCK_FILEстроится отcc.DATA_DIR(сейчасcc.BASE_DIR).- Тесты не меняются (они подменяют атрибуты модуля).
2. Dockerfile (новый)
- База
python:3.11-slim; зависимости отдельным слоем изrequirements.txt(pip install --no-cache-dir). - Копируются только рабочие файлы:
api_server.py,cidr_collector.py,collector_daemon.py,formatters.py,storage.py,healthcheck.py. - Пользователь
ripe(uid 10001),/dataсоздаётся и принадлежит ему (именованный том при первом создании наследует владельца). ENV RIPE_DATA_DIR=/data PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1,VOLUME /data.CMDв exec-форме (сигналы доходят до процесса): по умолчаниюuvicorn api_server:app --host 0.0.0.0 --port 8000; сборщик переопределяет команду в compose.
3. healthcheck.py (новый, маленький)
python healthcheck.py api- GEThttp://127.0.0.1:8000/health, успех при HTTP 200.python healthcheck.py collector- читаетstatus.json(cc.STATUS_FILE), успех, еслиupdated_atмоложеcc.STATUS_STALE_AFTER(переиспользуем константы и логику heartbeat).
4. docker-compose.yml (новый)
api:build: .,ports: "8000:8000",env_file: .env(RIPE_API_TOKEN),healthcheck(api),restart: unless-stopped.collector: тот же образ,command: ["python", "collector_daemon.py"],healthcheck(collector),stop_grace_period: 60s(идущий сбор успевает завершиться по SIGTERM), токен не передаётся.- Оба:
volumes: ripe_data:/data,environment: TZ=${TZ:-UTC}(расписание cron считается в этом поясе; в README отметить), усиление изоляции:read_only: true,tmpfs: /tmp,cap_drop: [ALL],security_opt: [no-new-privileges:true], ротация логовjson-file(max-size: 10m,max-file: 3). volumes: ripe_data:..env.exampleсRIPE_API_TOKEN=change-meиTZ=UTC;.envв.gitignoreи.dockerignore. Если токен не задан,POSTостаётся отключённым (503) - поведение fail closed сохраняется.
5. Документация и миграция (README.md)
- Раздел «Docker Compose»:
cp .env.example .env, генерация токена,docker compose up -d,docker compose ps, логи, обновление (docker compose build && docker compose up -d). - Миграция существующих данных в том: копирование
config.json,data.json,fqdn_data.jsonво временный контейнер сchown 10001. - Предупреждения: порт 8000 без TLS - токен виден в сети, ограничить файрволом или поставить proxy; часовой пояс
TZ;google.comв текущих данных не входит в конфигурацию и будет стареть по TTL. - Уточнить: systemd/OpenRC-установка остаётся рабочей альтернативой;
Dockerfile.testиспользуется только для тестов. .dockerignore: добавить.env.
6. Тесты
Новых автотестов не добавляем (минимум по правилам проекта): healthcheck.py и сборка проверяются в контейнерном сценарии ниже; 13 существующих тестов продолжают проходить (и в Dockerfile.test).
Критичные файлы
Новые: Dockerfile, docker-compose.yml, healthcheck.py, .env.example. Правки: cidr_collector.py (пути), collector_daemon.py (LOCK_FILE), README.md, .gitignore, .dockerignore.
Проверка
docker build -f Dockerfile.test ...и запуск: 13 passed (регрессия после правки путей).docker compose build && docker compose up -dс тестовым.envна копии данных (проект в каталоге scratchpad, реальные данные не трогаем); порт можно временно сменить переменной, чтобы не конфликтовать.docker compose ps: оба сервисаhealthyне позднее чем через ~1 минуту.curl /health:collector_alive: true;POST /asnsс токеном (201), без токена (401);GET /addresses?format=nftablesотдаёт конфиг.- Данные переживают
docker compose down && up -d(том), файлы в томе принадлежат uid 10001;docker compose exec api id- не root; запись вне/dataневозможна (read-only rootfs). docker compose stop collectorзавершается штатно (меньшеstop_grace_period), остановка демона делает/healthdegradedчерез ~2 минуты.- Миграция: скопировать реальные
config.json/data.json/fqdn_data.json(копии) в том по инструкции README, убедиться, что API видит те же адреса. - По окончании убрать тестовые контейнеры, тома и образы, созданные при проверке.