Files
traefik-selectel/README.md
T
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

6.2 KiB
Raw Blame History

traefik-selectel-dns

Демон, который создаёт A-записи в Selectel DNS (API v2) для хостов из роутеров Traefik. Сертификаты выписывает сам Traefik (встроенный dnsChallenge.provider: selectelv2) — кода для этого не нужно.

Почему не плагин Traefik

Плагин (Yaegi) работает внутри цепочки обработки запросов: он не видит создание/удаление роутов и не должен хранить токен с правом записи в DNS. Отдельный демон читает Traefik API (/api/http/routers), поэтому одинаково покрывает Docker labels и file-provider.

Как работает

  1. Раз в interval (и сразу после событий Docker) читает GET /api/http/routers.
  2. Из rule берёт все Host(...) у роутеров со статусом enabled (HostRegexp, !Host(...) игнорируются, *.x пропускаются с warning).
  3. Хосты, попадающие в zones из конфига (равны зоне или её поддомен; при вложенных зонах — самая длинная), получают A-запись ip/ttl.
  4. Записи, созданные демоном, помечаются comment: managed-by=traefik-selectel-dns. Меняются/удаляются только они. Существующая A-запись без метки (и имя с CNAME) не трогается — только warning.
  5. Удаление выключено по умолчанию. При delete.enabled: true запись удаляется после того, как роут отсутствует непрерывно delete.gracePeriod (состояние в памяти; после рестарта отсчёт начинается заново). Роутеры со статусом warning считаются присутствующими. При ошибке Traefik API или пустом списке (после непустого) цикл пропускается и ничего не удаляется.

Настройка

Пример полного стенда: deploy/ (docker-compose.example.yml, traefik.example.yml, config.example.yaml, dynamic/).

  1. Создайте в Selectel сервисного пользователя с минимальной ролью на DNS проекта.
  2. Положите креды в файлы секретов (deploy/secrets/*, не коммитить) — см. комментарий в compose.
  3. Поправьте zones, ip, traefik.apiURL в config.example.yaml; wildcard tls.domains — в traefik.example.yml.
  4. Для первого запуска включите dryRun: true и проверьте логи.

Сборка: docker build -t traefik-selectel-dns . (distroless, non-root, HEALTHCHECK через -healthcheck).

Конфигурация

YAML (-config или TSD_CONFIG), неизвестные поля — ошибка. Переопределение через env:

YAML env По умолчанию
zones TSD_ZONES (через запятую) обязательно
ip TSD_IP обязательно, IPv4
ttl TSD_TTL 300 (60..604800)
interval TSD_INTERVAL 30s
dryRun TSD_DRY_RUN false
traefik.apiURL / .timeout TSD_TRAEFIK_API_URL / TSD_TRAEFIK_TIMEOUT http://traefik:8080 / 10s
docker.enabled / .host TSD_DOCKER_ENABLED / TSD_DOCKER_HOST true / unix:///var/run/docker.sock (tcp:// тоже)
delete.enabled / .gracePeriod TSD_DELETE_ENABLED / TSD_DELETE_GRACE_PERIOD false / 10m
selectel.baseURL / .authURL / .timeout TSD_SELECTEL_BASE_URL / _AUTH_URL / _TIMEOUT api.selectel.ru/domains/v2, cloud.api.selcloud.ru/identity/v3, 30s
listen TSD_LISTEN :9090 (/healthz)
logLevel / logFormat TSD_LOG_LEVEL / TSD_LOG_FORMAT info / json

Секреты — только env (каждая поддерживает суффикс _FILE; одновременно обе — ошибка): SELECTEL_USERNAME, SELECTEL_PASSWORD, SELECTEL_ACCOUNT_ID, SELECTEL_PROJECT_ID. Для Traefik (lego) те же значения передаются как SELECTELV2_USERNAME_FILE, SELECTELV2_PASSWORD_FILE, SELECTELV2_ACCOUNT_ID_FILE, SELECTELV2_PROJECT_ID_FILE.

Безопасность

  • Секреты не попадают в конфиг, образ и логи; IAM-токен (Keystone) кэшируется в памяти и обновляется заранее.
  • Traefik API не публикуется наружу и ограничен ipAllowList подсетью сети control; пользовательские контейнеры в неё не подключать.
  • Docker socket = root на хосте. Демону нужны только события, поэтому в примере используется docker-socket-proxy (EVENTS=1), а не прямой сокет. Без Docker events демон работает по опросу.
  • Чужие записи не перезаписываются; удаление выключено по умолчанию.

Ограничения

  • Только A-записи, один фиксированный IPv4 для всех хостов; AAAA нет.
  • Только Host(...) с ASCII-именами (IDN — в punycode); HostRegexp и wildcard-хосты не поддерживаются.
  • Метка владения — exact-match комментария; если её вручную изменить/стереть, запись считается чужой.
  • Grace-состояние в памяти; несколько реплик демона одновременно не поддерживаются.
  • Поток Docker events без общего таймаута (переподключается при обрыве; страховка — периодический опрос).
  • Реальный Selectel API не проверялся (нет кредов) — см. отчёт в swarm-report/.