feat: traefik-selectel-dns — A-записи Selectel по роутам Traefik + CI сборка образа
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Конфиг демона traefik-selectel-dns. Секреты Selectel здесь НЕ хранятся:
|
||||
# SELECTEL_USERNAME / SELECTEL_PASSWORD / SELECTEL_ACCOUNT_ID / SELECTEL_PROJECT_ID
|
||||
# задаются только через env (или *_FILE). Любой параметр можно переопределить
|
||||
# env-переменной TSD_* (см. README).
|
||||
|
||||
# Разрешённые зоны (opt-in по зоне): записи создаются только для хостов,
|
||||
# равных зоне или являющихся её поддоменом. Зоны должны существовать в проекте Selectel.
|
||||
zones:
|
||||
- example.com
|
||||
|
||||
# IPv4 публичного адреса ВМ с Traefik — значение всех создаваемых A-записей.
|
||||
ip: 203.0.113.10
|
||||
ttl: 300 # 60..604800
|
||||
interval: 30s # период опроса Traefik API
|
||||
dryRun: false # true — только логировать, ничего не менять в DNS
|
||||
|
||||
traefik:
|
||||
apiURL: http://traefik:8080 # внутренний адрес API, наружу не публиковать
|
||||
timeout: 10s
|
||||
|
||||
docker:
|
||||
enabled: true # подписка на события контейнеров (триггер немедленного reconcile)
|
||||
host: tcp://docker-proxy:2375 # или unix:///var/run/docker.sock; недоступность не фатальна
|
||||
|
||||
delete:
|
||||
enabled: false # по умолчанию записи не удаляются
|
||||
gracePeriod: 10m # удалять только после непрерывного отсутствия роута
|
||||
|
||||
# selectel: # обычно не нужно
|
||||
# baseURL: https://api.selectel.ru/domains/v2
|
||||
# authURL: https://cloud.api.selcloud.ru/identity/v3
|
||||
# timeout: 30s
|
||||
|
||||
listen: ":9090" # /healthz
|
||||
logLevel: info # debug|info|warn|error
|
||||
logFormat: json # json|text
|
||||
@@ -0,0 +1,97 @@
|
||||
# Пример: Traefik + traefik-selectel-dns на одной ВМ.
|
||||
# Перед запуском создайте файлы секретов (права 0400/0440, не в git):
|
||||
# mkdir -p secrets && umask 077
|
||||
# printf '%s' 'service-user' > secrets/selectel_username
|
||||
# printf '%s' 'password' > secrets/selectel_password
|
||||
# printf '%s' '123456' > secrets/selectel_account_id
|
||||
# printf '%s' 'project-uuid' > secrets/selectel_project_id
|
||||
# Пользователь Selectel — сервисный, с минимальной ролью на DNS в нужном проекте.
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3 # в проде закрепите конкретную версию/digest
|
||||
restart: unless-stopped
|
||||
command: ["--configFile=/etc/traefik/traefik.yml"]
|
||||
ports: # публикуются ТОЛЬКО 80/443; 8080 (API) не публикуется
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
# Имена переменных lego (selectelv2); суффикс _FILE — чтение значения из файла
|
||||
SELECTELV2_USERNAME_FILE: /run/secrets/selectel_username
|
||||
SELECTELV2_PASSWORD_FILE: /run/secrets/selectel_password
|
||||
SELECTELV2_ACCOUNT_ID_FILE: /run/secrets/selectel_account_id
|
||||
SELECTELV2_PROJECT_ID_FILE: /run/secrets/selectel_project_id
|
||||
secrets:
|
||||
- selectel_username
|
||||
- selectel_password
|
||||
- selectel_account_id
|
||||
- selectel_project_id
|
||||
volumes:
|
||||
- ./traefik.example.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./dynamic:/etc/traefik/dynamic:ro
|
||||
- letsencrypt:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- proxy # сюда подключаются пользовательские контейнеры
|
||||
- control # только Traefik <-> демон
|
||||
|
||||
docker-proxy:
|
||||
# Демону нужен только поток событий: даём ему read-only прокси вместо docker.sock.
|
||||
image: tecnativa/docker-socket-proxy:latest # закрепите версию
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
EVENTS: 1
|
||||
CONTAINERS: 0
|
||||
POST: 0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
networks:
|
||||
- control
|
||||
|
||||
traefik-selectel-dns:
|
||||
image: git.realmanual.ru/pub/traefik-selectel:latest # или build: ..
|
||||
# build:
|
||||
# context: ..
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- traefik
|
||||
environment:
|
||||
SELECTEL_USERNAME_FILE: /run/secrets/selectel_username
|
||||
SELECTEL_PASSWORD_FILE: /run/secrets/selectel_password
|
||||
SELECTEL_ACCOUNT_ID_FILE: /run/secrets/selectel_account_id
|
||||
SELECTEL_PROJECT_ID_FILE: /run/secrets/selectel_project_id
|
||||
secrets:
|
||||
- selectel_username
|
||||
- selectel_password
|
||||
- selectel_account_id
|
||||
- selectel_project_id
|
||||
volumes:
|
||||
- ./config.example.yaml:/etc/traefik-selectel-dns/config.yaml:ro
|
||||
read_only: true
|
||||
cap_drop: [ALL]
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- control # доступ к Traefik API и docker-proxy; исходящий интернет — к Selectel
|
||||
|
||||
secrets:
|
||||
selectel_username:
|
||||
file: ./secrets/selectel_username
|
||||
selectel_password:
|
||||
file: ./secrets/selectel_password
|
||||
selectel_account_id:
|
||||
file: ./secrets/selectel_account_id
|
||||
selectel_project_id:
|
||||
file: ./secrets/selectel_project_id
|
||||
|
||||
volumes:
|
||||
letsencrypt:
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
control:
|
||||
name: traefik-control # НЕ подключайте к ней пользовательские контейнеры
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.30.250.0/24 # должна совпадать с sourceRange в dynamic/api-internal.yml
|
||||
@@ -0,0 +1,14 @@
|
||||
# Traefik API только для демона: entrypoint "traefik" (:8080) + разрешён только источник
|
||||
# из подсети сети control. Пользовательские контейнеры (сеть proxy) получат 403.
|
||||
http:
|
||||
routers:
|
||||
api-internal:
|
||||
rule: PathPrefix(`/api`)
|
||||
entryPoints: [traefik]
|
||||
service: api@internal
|
||||
middlewares: [api-internal-allow]
|
||||
middlewares:
|
||||
api-internal-allow:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 172.30.250.0/24
|
||||
@@ -0,0 +1,13 @@
|
||||
# Пример роута через file-provider: демон увидит его в Traefik API так же, как docker-роуты.
|
||||
http:
|
||||
routers:
|
||||
legacy-app:
|
||||
rule: Host(`legacy.example.com`)
|
||||
entryPoints: [websecure]
|
||||
service: legacy-app
|
||||
tls: {} # используется wildcard-сертификат с entrypoint websecure
|
||||
services:
|
||||
legacy-app:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://10.0.0.5:8080
|
||||
@@ -0,0 +1,56 @@
|
||||
# Статический конфиг Traefik v3.
|
||||
# Креды Selectel для dns-challenge (lego, провайдер selectelv2) передаются через env
|
||||
# SELECTELV2_*_FILE (см. docker-compose.example.yml), в этом файле секретов нет.
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
websecure:
|
||||
address: ":443"
|
||||
http:
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
# Общий wildcard-сертификат: Traefik выпустит его при старте, роуты с tls: {}
|
||||
# на этом entrypoint будут использовать его без отдельных запросов в ACME.
|
||||
domains:
|
||||
- main: example.com
|
||||
sans:
|
||||
- "*.example.com"
|
||||
# Внутренний entrypoint для API. Порт НЕ публикуется (ports:), а роутер api@internal
|
||||
# ограничен по IP подсетью сети control (dynamic/api-internal.yml), т.к. Traefik также
|
||||
# подключён к сети proxy с пользовательскими контейнерами.
|
||||
traefik:
|
||||
address: ":8080"
|
||||
|
||||
api:
|
||||
insecure: false # не открываем API автоматически — только через ограниченный роутер
|
||||
dashboard: false # демону нужен только /api/http/routers
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: admin@example.com
|
||||
storage: /letsencrypt/acme.json
|
||||
# Для отладки используйте staging:
|
||||
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
dnsChallenge:
|
||||
provider: selectelv2
|
||||
resolvers:
|
||||
- "1.1.1.1:53"
|
||||
- "8.8.8.8:53"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: proxy
|
||||
file:
|
||||
directory: /etc/traefik/dynamic
|
||||
watch: true
|
||||
|
||||
log:
|
||||
level: INFO
|
||||
@@ -0,0 +1,17 @@
|
||||
# Пример пользовательского контейнера: достаточно обычных labels Traefik,
|
||||
# DNS-запись для whoami.example.com демон создаст сам (зона example.com разрешена в конфиге).
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
traefik.enable: "true"
|
||||
traefik.http.routers.whoami.rule: Host(`whoami.example.com`)
|
||||
traefik.http.routers.whoami.entrypoints: websecure
|
||||
traefik.http.routers.whoami.tls: "true"
|
||||
networks:
|
||||
- proxy
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
name: proxy
|
||||
Reference in New Issue
Block a user