Configuration Discovery
Overview
Обнаружение конфигурации в Traefik'e достигается через провайдеры
Провайдеры это компоненты инфраструктуры, такие как оркестраторы, контейнерные движки, облачные провайдеры или key-value базы данных. Идея в том что Traefik делает запросы в API провайдера чтобы найти релевантную информацию о маршрутизации, и когда Traefik обнаруживает изменения он динамически обновляет маршруты
Orchestrators
Все провайдеры отличаются, но их можно поделить на 4 категории:
- Label-based - каждый задеплоенный контейнер имеет набор лейблов прикрепленных к нему
- Key-Value-based - каждый задеплоенный контейнер обновляет информацию в key-value хранилище
- Annotation-based - выделенный объект с аннотациями описывающий характеристики контейнера
- File-based - использует файлы для определения конфигурации
Provider Namespace
Когда ты описываешь некоторые объекты в динамической конфигурации Traefik'a, такие как middleware, сервисы, TLS опции или транспорты, они селятся в неймспейс своего провайдера. Например, если ты опишешь middleware используя docker лейблы, он будет обитать в неймспейсе docker провайдера
Если ты используешь множество провайдеров и хочешь сослаться на объект описанный в другом неймспейсе (у другого провайдера), тогда имя объекта должно иметь суффикс из @<provider-name>
resource-name>@<provider-name>
As Kubernetes also has its own notion of namespace, one should not confuse the provider namespace with the Kubernetes Namespace of a resource when in the context of cross-provider usage
In this case, since the definition of a Traefik dynamic configuration object is not in Kubernetes, specifying a Kubernetes Namespace when referring to the resource does not make any sense
On the other hand, if you were to declare a middleware as a Custom Resource in Kubernetes and use the non-CRD Ingress objects, you would have to add the Kubernetes Namespace of the middleware to the annotation like this
<middleware-namespace>-<middleware-name>@kubernetescrd
Referencing a Traefik Dynamic Configuration Object from Another Provider
Описание ресурса через файл-провайдер
http: middlewares: add-foo-prefix: addPrefix: prefix: "/foo"
Использование его в другом провайдере
your-container: # image: your-docker-image labels: # Attach add-foo-prefix@file middleware (declared in file) - "traefik.http.routers.my-container.middlewares=add-foo-prefix@file"
Supported Providers
Таблица поддерживаемых провайдеров
https://doc.traefik.io/traefik/providers/overview/#supported-providers
Provider | Type | Configuration Type | Provider Name |
---|---|---|---|
Docker | Orchestrator | Label | docker |
Kubernetes IngressRoute | Orchestrator | Custom Resource | kubernetescrd |
Kubernetes Ingress | Orchestrator | Ingress | kubernetes |
Kubernetes Gateway API | Orchestrator | Gateway API Resource | kubernetesgateway |
Consul Catalog | Orchestrator | Label | consulcatalog |
Nomad | Orchestrator | Label | nomad |
ECS | Orchestrator | Label | ecs |
Marathon | Orchestrator | Label | marathon |
Rancher | Orchestrator | Label | rancher |
File | Manual | YAML/TOML format | file |
Consul | KV | KV | consul |
Etcd | KV | KV | etcd |
ZooKeeper | KV | KV | zookeeper |
Redis | KV | KV | redis |
HTTP | Manual | JSON format | http |
Configuration Reload Frequency
providers.providersThrottleDuration
Опционально, по умолчанию 2 секунды
Иногда некоторые провайдеры могут испытывать внезапные всплески изменений которые генерируют множество событий изменения конфигурации. Если Traefik возьмет их всех в расчет то будет вызвано релоадов конфигурации больше чем необходимо
Чтобы обойти это можно задать опцию providers.providersThrottleDuration
. Она задает длительность ожидания между релоадами. Таким образом если пройзойдет множество изменений то применена будет последняя версия конфигурации на момент релоада
Эта опция не может быть задана на каждый провайдер по отдельности, но throttling algorithm применяется к каждому из них независимо
Значение опции должно быть указано в секундах или как валидный формат продолжительности (см. time.ParseDuration)
providers:
providersThrottleDuration: 10s
--providers.providersThrottleDuration=10s
Restrict the Scope of Service Discovery
По умолчанию Traefik создает роуты для всех найденных контейнеров
Если ты хочешь ограничить область Traefik SD, иными словами запретить создание роутов для некоторых контейнеров, ты можешь сделать это двумя различными способами:
- с помощью опции
exposedByDefault
- через более тонкий механизм детализации основанный на ограничениях
exposedByDefault
and traefik.enable
Список провайдеров поддерживающих эти опции
- Docker
- ECS
- Consul Catalog
- Nomad
- Rancher
- Marathon
Constraints
Список провайдеров поддерживающих ограничения
- Docker
- ECS
- Consul Catalog
- Nomad
- Rancher
- Marathon
- Kubernetes CRD
- Kubernetes Ingress
- Kubernetes Gateway
Docker
Прикрепи лейблы к своим контейнерам и позволь Traefik'у сделать все остальное
Traefik работает и с Docker Engine (standalone) и с Docker Swarm
Configuration Examples
- Docker standalone
В конфиге Traefik включаем провайдер docker
В docker-compose снабжаем сервис лейбломproviders: docker: {}
version: "3" services: my-container: # ... labels: - traefik.http.routers.my-container.rule=Host(`example.com`)
- Docker Swarm
В конфиге Traefik включаем и настраиваем провайдер
Вешаем лейблы на сервис, а не на контейнерproviders: docker: # swarm classic (1.12-) # endpoint: "tcp://127.0.0.1:2375" # docker swarm mode (1.12+) endpoint: "tcp://127.0.0.1:2377" swarmMode: true
version: "3" services: my-container: deploy: labels: - traefik.http.routers.my-container.rule=Host(`example.com`) - traefik.http.services.my-container-service.loadbalancer.server.port=8080
Routing Configuration
Когад в качестве провайдера используется docker, Traefik использует лейблы контейнера для получения конфигурации
Подробнее лейблы можно посмотреть тут https://doc.traefik.io/traefik/routing/providers/docker/
Routing Configuration with Labels
По умолчанию Traefik смотрит на лейблы уровня контейнера при standalone docker engine
Когда используется docker-compose лейблы указываются в директиве labels
у сервиса
Можно отметить что важно понимать что не только сам докер может "работать через docker провайдер", также такие инструменты как terraform, ansible и прочие могут создавать контейнеры и вешать на них лейблы (таким образом они могут работать с Traefik'ом)
Port Detection
Traefik получает private IP и порт контейнера из docker api
Обнаружение порта работает следующим образом:
- Если контейнер expose'ит один порт, то Traefik будет использовать его для приватной конфигурации
- Если контейнер expose'ит множество портов или ни одного, то ты должен вручную указать какой порт будет использовать Traefik для коммуникации с контейнером
Это делается через лейблtraefik.http.services.<service_name>.loadbalancer.server.port
Host networking
https://doc.traefik.io/traefik/providers/docker/#host-networking
IPv4 && IPv6
https://doc.traefik.io/traefik/providers/docker/#ipv4-ipv6
Docker API Access
Traefik'у требуется доступ к docker socket'у для получения оттуда динамической конфигурации
Ты можешь указать какой docker api endpoint использовать с помощью директивы endpoint
Небезопасно просто так выдавать доступ к сокету для Traefik (да и вообще кому угодно). Если произойдет компрометация веб сервера то злоумышленник может получить полный доступ к кластеру. Можно найти некоторые варианты решения этой проблемы по ссылке https://doc.traefik.io/traefik/providers/docker/#docker-api-access
Docker Swarm Mode
Чтобы включить режим Docker Swarm (вместо standalone docker engine) как провайдер конфигураций, нужно установить опцию swarmMode
в true
Routing Configuration with Labels
В режиме Swarm, Traefik использует лейблы найденные на сервисах а не на отдельных контейнерах
Поэтому, если ты используешь compose файл, лейблы надо определять в секции deploy
Port Detection
Docker Swarm не предоставляет никакой информации о портах Traefik'у
Поэтому ты должен вручную указывать порт, который будет использоваться для коммуникации с контейнером. Задается он через лейбл traefik.http.services.<service_name>.loadbalancer.server.port
Docker API Access
Режим Docker Swarm следует тем же правилам что и не-swarm режим
Однако Swarm API доступен только на менеджер ноде, поэтому надо деплоить Traefik на менеджер ноду
version: '3'
services:
traefik:
# ...
deploy:
placement:
constraints:
- node.role == manager
Следуя гайдлайнам из предыдущей секции, если ты заэкспозишь Docker API по TCP, то Traefik может быть зашедулен на любую другую ноду (воркер), лишь бы API оттуда был доступен
Provider Configuration
endpoint
Required, Default="unix:///var/run/docker.sock"
Смотри секции Docker API Access and Docker Swarm API Access для дополнительной информации
Можно предоставить доступ к API через сокет, тогда нужно прокинуть этот сокет в контейнер с Traefik через volume
version: '3'
services:
traefik:
image: traefik:v2.10 # The official v2 Traefik docker image
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
И указать путь до него --providers.docker.endpoint=unix:///var/run/docker.sock
Можно и по ssh --providers.docker.endpoint=ssh://traefik@192.168.2.5:2022
(надо чтобы пользователь из под которого запущен Traefik мог сделать этот ssh)
useBindPortIP
Optional, Default=false
Traefik роутит запросы на IP:port контейнера. Когда указана опция useBindPortIP=true
, ты говоришь ему использовать IP:port приаттаченный к контейнеру биндингом вместо того чтобы ходить по внутренней сети
Когда используется в связке с лейблом traefik.http.services.<name>.loadbalancer.server.port
, Traefik попытается найти биндинг на порт из лейбла. Если не выйдет то он откатится на использование внутренней сети, но порт продолжит использовать тот что указан в лейбле
--providers.docker.useBindPortIP=true
exposedByDefault
Optional, Default=true
Экспозить контейнеры по умолчанию сквозь Traefik. Если проставить в false
, то контейнеры не имеющие лейбла traefik.enable=true
будут игнорироваться в итогой конфигурации роутинга
--providers.docker.exposedByDefault=false
network
Optional, Default=""
Определяет дефолтную докер-сеть для связи со всеми контейнерами
Эта опция может быть переопределена по-контейнерно с помощью лейбла traefik.docker.network
--providers.docker.network=test
defaultRule
Optional, Default=Host(
{{ normalize .Name }})
Эта опция определяет какое правило роутинга применять к контейнеру если для него не указано правила через лейбл
Оно должно быть валидным go-template выражением и может использовать sprig функции
Имя контейнера доступно через ContainerName
, имя сервиса через Name
, лейблы через Labels
providers:
docker:
defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
# ...
swarmMode
Optional, Default=false
Включает swarm режим вместо одиночного docker демона
--providers.docker.swarmMode=true
swarmModeRefreshSeconds
Optional, Default=15
Определяет интервал поллинга в swarm режиме
--providers.docker.swarmModeRefreshSeconds=30
httpClientTimeout
Optional, Default=0
Определяет клиентский таймаут для HTTP подключений. Если стоит ноль то таймаута нет
--providers.docker.httpClientTimeout=300
watch
Optional, Default=true
Отслеживать ли эвенты докера
--providers.docker.watch=false
constraints
Optional, Default=""
В опция constraints
может быть проставлено выражение которое Traefik будет матчить с лейблами контейнеров чтобы определить нужно ли создавать роут для этого контейнера. Если ни один из лейблов контейнера не подходит под выражение, то роута для этого контейнера создано не будет. Если выражение пустое то под него подходит любой контейнер
Синтаксис выражения базируется на функциях Label("key", "value")
и LabelRegex("key", "value")
с простой булевой логикой
Примеры
# Includes only containers having a label with key `a.label.name` and value `foo`
constraints = "Label(`a.label.name`, `foo`)"
# Excludes containers having any label with key `a.label.name` and value `foo`
constraints = "!Label(`a.label.name`, `value`)"
# With logical AND.
constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)"
# With logical OR.
constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)"
# With logical AND and OR, with precedence set by parentheses.
constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))"
# Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression.
constraints = "LabelRegex(`a.label.name`, `a.+`)"
Задается так
providers:
docker:
constraints: "Label(`a.label.name`,`foo`)"
Или так
--providers.docker.constraints=Label(`a.label.name`,`foo`)
tls
Optional
Описывает TLS конфигурацию для защищенного подключения к докеру
ca
Optional
ca
это путь до ca используемого для защищенного подключения к докеру
providers:
docker:
tls:
ca: path/to/ca.crt
cert
cert
это путь до публичного сертификата используемого для безопасного подключения к докеру. При использовании этой опции становится обязательным использование опции key
providers:
docker:
tls:
cert: path/to/foo.cert
key: path/to/foo.key
key
Optional
key
это путь до приватного ключа используемого для безопасного подключения к докеру. При использовании этой опции становится обязательным использование опции cert
providers:
docker:
tls:
cert: path/to/foo.cert
key: path/to/foo.key
insecureSkipVerify
Optional, Default=false
Если insecureSkipVerify
стоит в true
, то TLS подключение до докера будет разрешено с любым сертификатом предоставленым сервером вне зависимости от того какие хостнеймы он покрывает
--providers.docker.tls.insecureSkipVerify=true
allowEmptyServices
Optional, Default=false
Если параметру присвоено значение true
, создается любой балансировщик нагрузки серверов, определенный для контейнеров Docker, независимо от работоспособности соответствующих контейнеров. Затем он также остается живым и отзывчивым даже в те моменты, когда он становится пустым, то есть когда все его дочерние контейнеры становятся неработоспособными. Это приводит к получению 503
HTTP-ответов вместо 404
в приведенных выше случаях.
--providers.docker.allowEmptyServices=true
Kubernetes IngressRoute
https://doc.traefik.io/traefik/providers/kubernetes-crd/
Kubernetes Ingress
https://doc.traefik.io/traefik/providers/kubernetes-ingress/
Kubernetes Gateway API
https://doc.traefik.io/traefik/providers/kubernetes-gateway/
Consul Catalog
https://doc.traefik.io/traefik/providers/consul-catalog/
Nomad
https://doc.traefik.io/traefik/providers/nomad/
ECS
https://doc.traefik.io/traefik/providers/ecs/
Marathon
https://doc.traefik.io/traefik/providers/marathon/
Rancher
https://doc.traefik.io/traefik/providers/rancher/
File
Старый добрый конфигурационный файл
File провайдер позволяет тебе описывать динамическую конфигурацию через yaml или toml файл
Есть поддержка как одного конфига так и множества раздельных файлов
Этот провайдер может быть хорошим решением для переиспользования общих элементов из других провайдеров, например описание разрешенных middleware, basic auth, etc)
Configuration Examples
Сперва включаем file провайдер
providers:
file:
directory: "/path/to/dynamic/conf"
--providers.file.directory=/path/to/dynamic/conf
Далее описываем в файле роутеры, middleware и сервисы
http:
# Add the router
routers:
router0:
entryPoints:
- web
middlewares:
- my-basic-auth
service: service-foo
rule: Path(`/foo`)
# Add the middleware
middlewares:
my-basic-auth:
basicAuth:
users:
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
- test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
usersFile: etc/traefik/.htpasswd
# Add the service
services:
service-foo:
loadBalancer:
servers:
- url: http://foo/
- url: http://bar/
passHostHeader: false
Provider Configuration
Чтобы посмотреть все опции которые можно описать через file провайдер см. dynamic configuration и static configuration
Есть ограничения. См. "Limitations" https://doc.traefik.io/traefik/providers/file/#provider-configuration
filename
Описывает путь до конфига
filename
и directory
взаимноисключащие, рекомендуется использовать directory
--providers.file.filename=/path/to/config/dynamic_conf.yml
directory
Описывает путь до директории которая содержит конфиги
filename
и directory
взаимноисключащие, рекомендуется использовать directory
--providers.file.directory=/path/to/config
watch
Установка опции watch
в true
позволит Traefik'у автоматически отслеживать изменения в файлах. Это работает и с директорией и с файлом
providers:
file:
directory: /path/to/dynamic/conf
watch: true
Go Templating
Go Templating only works with dedicated dynamic configuration files. Templating does not work in the Traefik main static configuration file
Traefik поддерживает использование go-template для автомтической генерации повторяющихся секций в конфигах. Эти секции должны быть валидными go-template и могут содержать sprig функции
Проиллюстрируем это на возможности простого описания множества роутеров, сервисов и TLS сертификатов
http:
routers:
{{range $i, $e := until 100 }}
router{{ $e }}-{{ env "MY_ENV_VAR" }}:
# ...
{{end}}
services:
{{range $i, $e := until 100 }}
application{{ $e }}:
# ...
{{end}}
tcp:
routers:
{{range $i, $e := until 100 }}
router{{ $e }}:
# ...
{{end}}
services:
{{range $i, $e := until 100 }}
service{{ $e }}:
# ...
{{end}}
tls:
certificates:
{{ range $i, $e := until 10 }}
- certFile: "/etc/traefik/cert-{{ $e }}.pem"
keyFile: "/etc/traefik/cert-{{ $e }}.key"
store:
- "my-store-foo-{{ $e }}"
- "my-store-bar-{{ $e }}"
{{end}}
Consul
https://doc.traefik.io/traefik/providers/consul/
Etcd
https://doc.traefik.io/traefik/providers/etcd/
ZooKeeper
https://doc.traefik.io/traefik/providers/zookeeper/
Redis
https://doc.traefik.io/traefik/providers/redis/
No Comments