# traefik-selectel-dns — отчёт (2026-09-21) ## Что сделано Go-демон `traefik-selectel-dns` (модуль `github.com/realmanual/traefik-selectel`, Go 1.27.1, единственная зависимость — `gopkg.in/yaml.v3`): - `internal/hostparse` — разбор `Host(...)` (несколько аргументов, `||`, `&&`, кавычки, отрицания `!Host`/`!(...)`, `HostRegexp`/`HostSNI` не считаются), валидация DNS-имён, сопоставление зон (longest match). - `internal/traefik` — клиент `GET /api/http/routers` с пагинацией (`page`/`per_page`, `X-Next-Page`). - `internal/selectel` — Keystone-токен (кэш в памяти, обновление за 10 минут до `expires_at`), DNS API v2 (зоны с кэшем id, rrset list/create/PATCH/delete), повтор при 401 со сбросом токена, 404 на delete = успех. - `internal/reconciler` — create/update/skip-foreign/skip-CNAME/delete-grace/safe-guard, dry-run, цикл с debounce по событиям Docker. - `internal/dockerevents` — raw HTTP `/events` по unix-сокету или tcp (без docker SDK), переподключение с backoff, недоступность не фатальна. - `internal/config` (YAML strict + env `TSD_*` + секреты `*_FILE`), `internal/httpx` (ретраи 429/5xx с backoff и Retry-After), `internal/health` (`/healthz`, флаг `-healthcheck`). - Dockerfile (multi-stage, distroless static nonroot 65532), `.dockerignore`, `deploy/` (compose, traefik.yml, config, dynamic/, whoami-пример), README. Проверено: `go vet ./...` — чисто; `go test -race ./...` — 79 тестов проходят; `docker build` собирается, образ запускается (`-version`), USER 65532; `docker compose config -q` валиден. ## Сверка с документацией - DNS API v2: base URL `https://api.selectel.ru/domains/v2` (docs.selectel.ru/api/urls), `X-Auth-Token` (по исходникам lego selectelv2), пути `/zones`, `/zones/{id}/rrset[/{rrset_id}]`, тело `{name,type,ttl,records:[{content,disabled}],comment}`, PATCH — `ttl`, `records`, `comment`; имена — FQDN с точкой. - Токен: `POST https://cloud.api.selcloud.ru/identity/v3/auth/tokens`, токен в заголовке `X-Subject-Token`, срок 24 ч. - Переменные lego `selectelv2`: `SELECTELV2_USERNAME/PASSWORD/ACCOUNT_ID/PROJECT_ID` (+`_FILE`) — сверено через context7 (/go-acme/lego). ## Принятые решения / отступления - Роутеры со статусом `warning` не создают записи, но считаются «присутствующими» (не запускают grace-удаление) — чтобы временный warning не удалил запись. - Список rrset читается целиком (все типы) и фильтруется на клиенте: формат query-параметра `rrset_types` в доке не уточнён; так же позволяет обнаружить CNAME-конфликт. - Зона ищется по `filter` + точное сравнение имени на клиенте (семантика filter не описана). - Traefik API: вместо `api.insecure: true` — роутер `api@internal` на entrypoint `traefik` с `ipAllowList` подсети control, т.к. Traefik также сидит в сети proxy с пользовательскими контейнерами. Docker events демон получает через `docker-socket-proxy`, а не прямой сокет. - Добавлены сверх ТЗ: `dryRun`, `-healthcheck`, детекция CNAME-конфликта. ## Риски - Остаточный: подсеть `172.30.250.0/24` дублируется в compose и dynamic/api-internal.yml — при расхождении демон получит 403. - Docker socket, смонтированный в Traefik (штатно для Docker provider) — root-эквивалент; в примере ro-монтирование не ограничивает API. - POST при 5xx может повториться (возможен дубль) — reconcile идемпотентен, но при дубле API вернёт ошибку до следующего цикла. - Метка владения — exact-match комментария (до 255 символов ок). - Образы `traefik:v3`, `docker-socket-proxy:latest`, `golang:1.27-alpine`, distroless — не закреплены по digest; в проде закрепить. - Имя образа `ghcr.io/realmanual/traefik-selectel-dns` в compose — заглушка. ## Не проверено - Реальный Selectel API (нет кредов): формат ответа Keystone (`expires_at`; при ошибке разбора берётся 1 час), точное поведение `filter` у зон, поведение POST на дубликат, признак конца пагинации (используется `len(result) < limit`), значение `managed_by` у записей, созданных через API. - Реальный Traefik (структура роутеров, пагинация, статус `warning`), реальное Docker events, выпуск сертификатов и wildcard `tls.domains` — не запускалось, деплой не выполнялся. - Не проверялись права сервисного пользователя Selectel (минимальная роль на DNS).