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. |
No Comments