Files
traefik-selectel/swarm-report/traefik-selectel-dns-2026-09-21.md
vasyanskandClaude Sonnet 5 273cd54415
Build / Tests (push) Successful in 13s
Build / Build image (push) Failing after 15s
Build / Notify on failure (push) Failing after 0s
feat: traefik-selectel-dns — A-записи Selectel по роутам Traefik + CI сборка образа
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 21:50:07 +07:00

5.6 KiB
Raw Permalink Blame History

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).