Info
Content

Configuration Discovery

Overview

У Traefik'а много друзей
Screenshot_2021_02_02-12_49_03-2023-05-18-at-16manyfriends.png

Обнаружение конфигурации в 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

История лейблов и контейнеров
Screenshot_2021_02_02-12_49_03-2023-05-18-at-20storylc.png

Прикрепи лейблы к своим контейнерам и позволь Traefik'у сделать все остальное

Traefik работает и с Docker Engine (standalone) и с Docker Swarm

Configuration Examples

  • Docker standalone
    В конфиге Traefik включаем провайдер docker
    providers:
      docker: {}
    
    В docker-compose снабжаем сервис лейблом
    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 попытается найти биндинг на порт из лейбла. Если не выйдет то он откатится на использование внутренней сети, но порт продолжит использовать тот что указан в лейбле

Screenshot_2021_02_02-12_49_03-2023-05-19-at-00.png

--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/

HTTP

https://doc.traefik.io/traefik/providers/http/

No Comments
Back to top