traefik
https://doc.traefik.io/traefik
Welcome
Traefik это опенсорсный Edge Router который делает публикацию твоих сервисов простой и веселой. Он принимает запросы от имени твой системы и ищет какой компонент отвечает за его обработку
Что отличает Traefik от других, помимо множества функций, так это то что он автоматически определяет правильную конфигурацию для твоих сервисов. Магия происходит когда Traefik инспектирует твою инфраструктуру в которой он находит релевантную информацию о том какой сервис обрабатывает какие запросы
Traefik нативно совместим со всеми крупными технологиями кластеризации, такими как: Kubernetes, Docker, Docker Swarm, AWS, Mesos, Marathon, и список продолжает расти. А еще он может работать одновременно с несколькими (обычно это нужно для старого софта на bare metal)
С Traefik'ом нет необходимости поддерживать и синхронизировать кучу раздельных конфигов, все происходит автоматически в реальном времени (без рестартов и прерываний подключений). С Traefik'ом ты оплачиваешь время на разработку и деплой новых фич, а не на конфигурирование и поддержку этого в рабочем состоянии
Разрабатывая Traefik, наша основная цель сделать его простым в использовании и мы уверены это тебе понравится
-- The Traefik Maintainer Team
Getting Started
Concepts
Introduction
Traefik основан на концептах EntryPoints, Routers, Middlewares и Services
Основные функции включают: динамическое конфигурирование, автоматический service discovery и поддержку множества бекендов и протоколов
- EntryPoints - это сетевые входные точки внутрь Traefik. Они определяют порт который будет принимать пакеты и протокол TCP/UDP
- Routers - Роутер отвечает за подключение входящих запросов к сервисам которые их обслужат
- Middlewares - прикрепляются к роутерам и могут модифицировать запросы или ответы перед тем как те будут отправлены твоему сервису
- Services - Сервисы отвечают за конфигурирование того как достигать актуальные сервисы которые должны обрабатывать входящие запросы
Edge Router
Traefik это Edge Router, это значит что он дверь в вашу платформу и он слышит и роутит каждый входящий запрос: он знает всю логику и каждое правило которые определяют какие сервисы обрабатывают какие запросы (базируясь на path, host, headers, etc)
Auto Service Discovery
Тогда как традиционные edge router'ы (или reverse proxies) нуждаются в конфиге который должен содержать все возможные маршруты до твоих сервисов, Traefik получает эту информацию из самих же сервисов
Деплоя свои сервисы ты прикрепляешь к ним информацию которая говорит Traefik'у характеристики запросов которые может обработать сервис
Это значит что когда сервис задеплоен, Traefik замечает его немедленно и обновляет свои правила роутинга в реальном времени. Аналогично, когда сервис удален из инфраструктуры, соответствующее правило также удаляется
Тебе больше не требуется создавать и синхронизировать конфиги загроможденные айпишниками и другими правилами
Quick Start
Docker
Launch Traefik With the Docker Provider
Создай файл docker-compose.yml
в котором опиши сервис reverse-proxy
который использует официальный образ Traefik
version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.10
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
Запусти следующей командой:
docker-compose up -d reverse-proxy
Дальше ты можешь открыть в браузере http://localhost:8080/api/rawdata и увидеть Traefik'овый API
(7tech.local:default) vandud@192-168-0-106: ~ 🚀 curl -s http://172.28.103.198:8080/api/rawdata | jq
{
"routers": {
"api@internal": {
"entryPoints": [
"traefik"
],
"service": "api@internal",
"rule": "PathPrefix(`/api`)",
"priority": 2147483646,
"status": "enabled",
"using": [
"traefik"
]
},
...
"wordpress@docker": {
"entryPoints": [
"http"
],
"service": "wordpress-wordpress-1-75b7desrqbkk8g5mmncpzeati",
"rule": "Host(`wordpress.docker`)",
"status": "enabled",
"using": [
"http"
]
}
},
"middlewares": {
"dashboard_redirect@internal": {...},
"dashboard_stripprefix@internal": {...},
},
"services": {
"api@internal": {
"status": "enabled",
"usedBy": [
"api@internal"
]
},
...
"wordpress-wordpress-1-75b7desrqbkk8g5mmncpzeati@docker": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.11.6:80"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"wordpress@docker"
],
"serverStatus": {
"http://10.0.11.6:80": "UP"
}
}
}
}
Traefik Detects New Services and Creates the Route for You
Теперь когда у нас поднят Traefik мы будем деплоить новые сервисы
Добавь в docker-compose:
whoami:
image: traefik/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`wordpress.docker`) && PathPrefix(`/whoami`)"
whoami
это простой сервис который выдает информации о машине на которую он задеплоен
Деплоим и видим что traefik его обнаружил
🚀 curl -s http://wordpress.docker/whoami
Hostname: 102031f395a3
IP: 127.0.0.1
IP: 10.0.11.16
IP: 172.18.0.5
RemoteAddr: 10.0.11.9:60988
GET /whoami HTTP/1.1
Host: wordpress.docker
User-Agent: curl/7.87.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.0.0.2
X-Forwarded-Host: wordpress.docker
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 72df34ecb3e3
X-Real-Ip: 10.0.0.2
More Instances? Traefik Load Balances Them
Kubernetes
https://doc.traefik.io/traefik/getting-started/quick-start-with-kubernetes/
Configuration Introduction
Конфигурация в Traefik может быть заслана двумя путями:
- Полностью динамическая конфигурация роутинга (dynamic configuration)
- Стартовая конфигурация (static configuration)
Элементы статической конфигурации задают подключение к провайдерам и определяют входные точки в Traefik (entrypoints) (эти элементы обычно не меняются)
Динамическая конфигурация содержит все что определяет как будут обрабатываться запросы твоей системой
Эта конфигурация может меняться и бесшовно подгружаться на горячую (без прерывания подключений)
The Dynamic Configuration
Traefik берет динамическую конфигурацию от провайдеров: будь это оркестратор, сервис регистри или простой конфиг файл
The Static Configuration
Здесь есть три взаимоисключающих пути (можно использовать только один в один момент времени) задания статической конфигурации:
- Конфиг файл
- CLI аргументы
- Переменные окружения
Эти варианты применяются в порядке описаном выше
Если значение опции не указано - применяется дефолтное значение
Более того, если опция имеет под-опции, и какая-либо из этих подопций не указано - будет использовано значение по умолчанию (насколько я понял для всей опции, а не только для неуказанной под-опции)
Например, опции --providers.docker
достаточно для того чтобы включить docker провайдер, несмотря на то что существует другие под-опции такие как --providers.docker.endpoint
. После установки этот параметр устанавливает (и сбрасывает) все значения по умолчанию для вложенных параметров --providers.docker
Configuration File
При старте Traefik ищет статическую конфигурацию в файле traefik.yml
(или traefik.yaml
или traefik.toml
) который ожидает найти в:
/etc/traefik
$XDG_CONFIG_HOME/
$HOME/.config/
.
(the working directory)
Положение конфигурационного файла можно переопределить через опцию configFile
traefik --configFile=foo/bar/myconfigfile.yml
Arguments
Список всех доступных аргументов можно посмотреть в выводе опции --help
traefik --help
# or
docker run traefik[:version] --help
# ex: docker run traefik:v2.10 --help
Либо в https://doc.traefik.io/traefik/reference/static-configuration/cli/
Environment Variables
Все доступные переменные окружения можно посмотреть в https://doc.traefik.io/traefik/reference/static-configuration/env/
Available Configuration Options
Все конфигурационные опции задокументированы в связанных с ними секциях
Ты можешь просмотреть доступные функции в меню, providers, или routing section
Install Traefik
Ты можешь установить Traefik следующими способами:
- Используя официальный Docker image
- Используя Helm Chart
- Используя готовый бинарь
- Скомпилировать свой собственный бинарь из исходников
Use the Official Docker Image
https://doc.traefik.io/traefik/getting-started/install-traefik/#use-the-official-docker-image
Use the Helm Chart
https://doc.traefik.io/traefik/getting-started/install-traefik/#use-the-helm-chart
Exposing the Traefik dashboard
https://doc.traefik.io/traefik/getting-started/install-traefik/#exposing-the-traefik-dashboard
Use the Binary Distribution
https://doc.traefik.io/traefik/getting-started/install-traefik/#use-the-binary-distribution
Compile your Binary from the Sources
https://doc.traefik.io/traefik/getting-started/install-traefik/#compile-your-binary-from-the-sources
FAQ
https://doc.traefik.io/traefik/getting-started/faq/#faq
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/
HTTP
https://doc.traefik.io/traefik/providers/http/
Routing & Load Balancing
Overview
Что происходит с запросами?
Давайте приблизимся к архитектуре Traefik'a и поговорим о том какие компоненты позволяют создавать роуты
Сперва, когда ты запускаешь Traefik, ты определяешь entrypoint'ы (в их наипростейшей форме - номер порта). Далее, подключенный к этим entrypoint'ас, роутер анализирует входящие запросы чтобы увидеть как они матчатся на набор рулов. Если матчатся, то роутер может трансформировать запрос используя фрагменты middleware перед тем как перенаправить его к твоему сервису
Clear Responsibilities
- Providers - находят сервисы которые живут в твоей инфре
- Entrypoints - принимают входящий трафик
- Routers - анализируют запросы
- Services - перенаправляют запросы на твои сервисы
- Middlewares - могут изменять запросы или принимать решения на основе запросов
Example with a File Provider
Ниже пример полного конфига для file-провайдера который будет форвардить запросы к http://example.com/whoami/
на сервис доступный на ttp://private/whoami-service/
. В процессе Traefik будет производить проверку что пользователь аутентифицирован (используется BasicAuth middleware)
Статическая конфигурация:
entryPoints:
web:
# Listen on port 8081 for incoming requests
address: :8081
providers:
# Enable the file provider to define routers / middlewares / services in file
file:
directory: /path/to/dynamic/conf
Динамическая конфигурация:
# http routing section
http:
routers:
# Define a connection between requests and services
to-whoami:
rule: "Host(`example.com`) && PathPrefix(`/whoami/`)"
# If the rule matches, applies the middleware
middlewares:
- test-user
# If the rule matches, forward to the whoami service (declared below)
service: whoami
middlewares:
# Define an authentication mechanism
test-user:
basicAuth:
users:
- test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
services:
# Define how to reach an existing service on our infrastructure
whoami:
loadBalancer:
servers:
- url: http://private/whoami-service
Transport configuration
Много чего происходит в подключении между клиентом и Traefik'ом, а также между Traefik'ом и бэкенд серверами
В дополнение несколько параметров позволяют глобально конфигурировать поведение подключений между Traefik'ом и бэкендами. Это достигается за счет секции serversTransport
insecureSkipVerify
Optional, Default=false
insecureSkipVerify
выключает проверку сертификата
--serversTransport.insecureSkipVerify=true
rootCAs
Лист CA сертификатов для использования с самосертами
serversTransport:
rootCAs:
- foo.crt
- bar.crt
maxIdleConnsPerHost
Optional, Default=2
Если стоит не ноль, то maxIdleConnsPerHost
контролирует максимальное кол-во idle (keep-alive) подключений которые будут поддерживаться per-host
--serversTransport.maxIdleConnsPerHost=7
forwardingTimeouts
Секция forwardingTimeouts
о количестве тайм-аутов, относящихся к переадресации запросов на внутренние серверы
forwardingTimeouts.dialTimeout
Optional, Default=30s
dialTimeout
- как долго может устанавливаться подключение. Ноль означает отсутствие таймаута
forwardingTimeouts.responseHeaderTimeout
Optional, Default=0s
responseHeaderTimeout
если не ноль то задает длительность ожидания ответных заголовков после полной отправки запроса (включая тело запроса). Это время не включает время чтения тела ответа. Ноль означает отсутствие таймаута
forwardingTimeouts.idleConnTimeout
Optional, Default=90s
idleConnTimeout
максимальное время жизни idle (keep-alive) подключения пока оно будет оставаться в idle состоянии перед закрытием. Ноль означает отсутствие таймаута
serversTransport:
forwardingTimeouts:
dialTimeout: 1s
responseHeaderTimeout: 1s
idleConnTimeout: 1s
EntryPoints
Открытие подключений для входящих запросов
Entrypoints это сетевые входные точки в Traefik. Они определяют порт через который будут приниматься пакеты и то будет это TCP или UDP
Configuration Examples
Port 80 only:
entryPoints:
web:
address: ":80"
Мы описали entrypoint который слушает 80 порт и назвали его web
Port 80 & 443:
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
Описаны два entrypoint'a один называется web
, другой websecure
web
слушает 80 порт, а websecure
443
UDP на порту 1704:
entryPoints:
streaming:
address: ":1704/udp"
Configuration
General
Entrypoint'ы это часть статической конфигурации. Они могут быть заданы через файл или через cli
entryPoints: |
name: |
address: ":8888" # same as ":8888/tcp" | --entryPoints.name.address=:8888 # same as :8888/tcp
http2: |
maxConcurrentStreams: 42 | --entryPoints.name.http2.maxConcurrentStreams=42
http3: |
advertisedPort: 8888 | --entryPoints.name.http3.advertisedport=8888
transport: |
lifeCycle: |
requestAcceptGraceTimeout: 42 | --entryPoints.name.transport.lifeCycle.requestAcceptGraceTimeout=42
graceTimeOut: 42 | --entryPoints.name.transport.lifeCycle.graceTimeOut=42
respondingTimeouts: |
readTimeout: 42 | --entryPoints.name.transport.respondingTimeouts.readTimeout=42
writeTimeout: 42 | --entryPoints.name.transport.respondingTimeouts.writeTimeout=42
idleTimeout: 42 | --entryPoints.name.transport.respondingTimeouts.idleTimeout=42
proxyProtocol: |
insecure: true | --entryPoints.name.proxyProtocol.insecure=true
trustedIPs: |
- "127.0.0.1" | --entryPoints.name.proxyProtocol.trustedIPs=127.0.0.1,192.168.0.1
- "192.168.0.1" |
forwardedHeaders: |
insecure: true | --entryPoints.name.forwardedHeaders.insecure=true
trustedIPs: |
- "127.0.0.1" | --entryPoints.name.forwardedHeaders.trustedIPs=127.0.0.1,192.168.0.1
- "192.168.0.1" |
Address
Адрес определяет порт и опционально хостнейм на котором нужно слушать входящие запросы и пакеты. Он также определяет протокол который нужно использовать (TCP/UDP). Если протокол не указан то по умолчанию используется TCP. Формат следующий:
[host]:port[/tcp|/udp]
Если нужно использовать и TCP и UDP на одном и том же порту, то нужно описать два entrypoint'a
entryPoints:
tcpep:
address: ":3179"
udpep:
address: ":3179/udp"
Пример указания конкретного айпишника
entryPoints:
specificIPv4:
address: "192.168.2.7:8888"
specificIPv6:
address: "[2001:db8::1]:8888"
HTTP/2
maxConcurrentStreams
Optional, Default=250
maxConcurrentStreams
определяет кол-во одновременных потоков на подключение которые может инициировать клиент. Значение должно быть больше нуля
--entryPoints.name.http2.maxConcurrentStreams=250
HTTP/3
http3
Опция http3
включает протокол HTTP/3 для entrypoint'a. HTTP/3 требует TCP entrypoint, так как HTTP/3 всегда стартует как TCP подключение которое впоследствии будет апгрейднуто до UDP. В основном это тот же entrypoint что и для TLS
Так как HTTP/3 использует UDP, то ты не можешь иметь TCP entrypoint с HTTP/3 на том же порту что и UDP entrypoint. HTTP/3 требует использования TLS, поэтому только роутеры с TLS могут использовать HTTP/3
Так как спецификация HTTP/3 все еще находится в состоянии черновика, то поддержка протокола в Traefik является экспериментальной и должна быть активирована в секции experimental
статической конфигурации
experimental:
http3: true
entryPoints:
name:
http3: {}
advertisedPort
http3.advertisedPort
описывает какой UDP порт предлагать как HTTP/3 authority. По умолчанию это entypoint порт. Эта опция может быть использована для оверайдинга outhority в заголовке alt-svc
, например если публично торчащий порт отличается от того который слушает Traefik
experimental:
http3: true
entryPoints:
name:
http3:
advertisedPort: 443
Forwarded Headers
Можно сказать Traefik'у доверять информации из X-Forwarded-*
заголовков
entryPoints:
web:
address: ":80"
forwardedHeaders:
trustedIPs:
- "127.0.0.1/32"
- "192.168.1.7"
entryPoints:
web:
address: ":80"
forwardedHeaders:
insecure: true
Transport
respondingTimeouts
respondingTimeouts
таймаут для входящих в Traefik запросов. Это опция не имеет эффекта для UDP entrypoint'ов
https://doc.traefik.io/traefik/routing/entrypoints/#respondingtimeouts
transport.respondingTimeouts.readTimeout
Optional, Default=0s
readTimeout
задает максимальную продоложительность чтения всего запроса включая тело
Если стоит 0 то лимита нет
Может быть указано в форматах поддерживаемых типом time.ParseDuration. Если юнит не указан то воспринимается как секунды
transport.respondingTimeouts.writeTimeout
Optional, Default=0s
writeTimeout
задает таймаут записи ответа
Этот таймаут покрывает время от начала чтения заголовков запроса и до конца записи ответа
Если 0 то лимита нет
transport.respondingTimeouts.idleTimeout
Optional, Default=180s
idleTimeout
как долго keep-alive подключение может находиться в состоянии idle
Если 0 то лимита нет
entryPoints:
name:
address: ":8888"
transport:
respondingTimeouts:
readTimeout: 42
writeTimeout: 42
idleTimeout: 42
lifeCycle
Контролирует поведение Traefik'a во время фазы выключения
lifeCycle.requestAcceptGraceTimeout
Optional, Default=0s
Как долго продолжать принимать запросы перед инициацией graceful termination периода (как гласит опция graceTimeOut
). Эта опция дает нижележащим балансерам возможность выкинуть Traefik из ротации
Может быть указано в форматах поддерживаемых типом time.ParseDuration. Если юнит не прописан то воспринимается как секунды
Ноль отключает прием запросов в grace period, то есть он будет переходить в grace period сразу
lifeCycle.graceTimeOut
Optional, Default=10s
Задает как долго ждать завершения уже начатых (активных) запросов перед тем как окончательно выключиться
Может быть указано в форматах поддерживаемых типом time.ParseDuration. Если юнит не прописан то воспринимается как секунды
В этот период уже не будут приниматься новые запросы
entryPoints:
name:
address: ":8888"
transport:
lifeCycle:
requestAcceptGraceTimeout: 42
graceTimeOut: 42
ProxyProtocol
https://doc.traefik.io/traefik/routing/entrypoints/#proxyprotocol
HTTP Options
Вся эта секция посвящена только опциям связанных с entrypoint'ами и применимым только к http роутингу
Redirection
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
entryPoint
Эта секция удобна для включения постоянного редиректа всех входящих запросов на другой entrypoint
entryPoint.to
Required
Может содержать имя другого entrypoint (websecure
) или порт :443
entryPoint.scheme
Optional, Default="https"
Схема цели редиректа (http/https/etc)
entryPoint.permanent
Optional, Default=true
Перманентен ли редирект
entryPoint.priority
Optional, Default=MaxInt32-1 (2147483646)
Приоритет сгенеренного роутера
entryPoints:
foo:
http:
redirections:
entryPoint:
priority: 10
permanent: true
scheme: https
to: websecure
Middlewares
Список middlewares которые будут добавляться по умолчанию в список middlewares каждого роутера ассоциированного с этим entrypoint'ом
entryPoints:
websecure:
address: ':443'
http:
middlewares:
- auth@file
- strip@file
TLS
Эта секция о дефолтных настройках TLS которые будут применяться ко всем роутерам ассоциированным с этим entrypoint'ом
Если TLS секция (любое из ее полей) прописано пользователем, то дефолтная конфигурация не применяется вообще
Эта секция конфигурируется точно так же как у HTTP роутеров
entryPoints:
websecure:
address: ':443'
http:
tls:
options: foobar
certResolver: leresolver
domains:
- main: example.com
sans:
- foo.example.com
- bar.example.com
- main: test.com
sans:
- foo.test.com
- bar.test.com
UDP Options
Эта секция посвящена опциям от entrypoint для UDP роутинга
Timeout
Optional, Default=3s
Как долго сессии ждать в idle состоянии перед тем как высвободить связанные с ней ресурсы. Значение должно быть больше нуля
--entrypoints.foo.address=:8000/udp
--entrypoints.foo.udp.timeout=10s
Routers
Соединение запросов с сервисами
Роутер занят направлением входящих запросов в сервисы которые их обработают. В процессе этого роутеры могут использовать middleware для модифицирования запросов перед отправкой их в сервис
Configuration Example
Requests /foo are Handled by service-foo -- Using the File Provider
http:
routers:
my-router:
rule: "Path(`/foo`)"
service: service-foo
Forwarding all (non-tls) requests on port 3306 to a database service
tcp:
routers:
to-database:
entryPoints:
- "mysql"
# Catch every request (only available rule for non-tls routers. See below.)
rule: "HostSNI(`*`)"
service: database
## Static configuration
entryPoints:
web:
address: ":80"
mysql:
address: ":3306"
Configuring HTTP Routers
Символ
@
запрещено использовать в именах роутеров
EntryPoints
Если не прописано то роутер будет принимать запросы из всех описанных entrypoint'ов. Если надо ограничить охват то можно прописать опцию entryPoints
http:
routers:
Router-1:
# won't listen to entry point web
entryPoints:
- "websecure"
- "other"
rule: "Host(`example.com`)"
service: "service-1"
Rule
Рулы это набор матчеров сконфигурированных значениями которые определяют подпадает ли конкретный запрос под их критерии. Если рулы пройдены, то роутер становится активным, вызывает middleware и потом перенаправляет запрос в сервис
Чтобы указать значение рула используй обратные тики
`
или экранированные двойные кавычки\"
Одиночные кавычки не разрешено использовать в качестве значения golang string literals
Примеры:
rule = "Host(`example.com`)"
rule = "Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))"
Далее таблица с доступными матчерами
Rule | Description |
---|---|
Headers(`key`, `value`) |
Check if there is a key keydefined in the headers, with the value value |
HeadersRegexp(`key`, `regexp`) |
Check if there is a key keydefined in the headers, with a value that matches the regular expression regexp |
Host(`example.com`, ...) |
Check if the request domain (host header value) targets one of the given domains . |
HostHeader(`example.com`, ...) |
Same as Host , only exists for historical reasons. |
HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...) |
Match the request domain. See "Regexp Syntax" below. |
Method(`GET`, ...) |
Check if the request method is one of the given methods (GET , POST , PUT , DELETE , PATCH , HEAD ) |
Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...) |
Match exact request path. See "Regexp Syntax" below. |
PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`) |
Match request prefix path. See "Regexp Syntax" below. |
Query(`foo=bar`, `bar=baz`) |
Match Query String parameters. It accepts a sequence of key=value pairs. |
ClientIP(`10.0.0.0/16`, `::1`) |
Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. |