Traefik — реверспрокси, предназначенный для работы с Docker. Он позволяет очень просто и декларативно проксировать сервисы в контейнерах. Сначала вас могут отпугнуть лейблы, но вы привыкнете :)

В нескольких примерах постараюсь показать, как просто запроксировать сайты и api, автоматизировать получение сертификатов и даже навесить несколько middleware (например для добавления хедеров).

Для начала стоит создать конфиг траефика:

 
# traefik.yml

# ...

providers:
 docker:
 network: traefik
 exposedbydefault: false

 # добавляем file провайдер, который будет подтягивать данные из
 # директории external
 file:
 directory: ./external

# ...

Для проксирования сервисов в локальной сети требуется добавить docker-host сервис, так как localhost внутри контейнера укажет на сеть самого контейнера, а не на локальную сеть машины.

# docker-compose.yml

version: "3.8"

services:
 # ...
 traefik:
 # ...
 networks:
 - traefik
 # добавляем общую для докерхоста и траефика сеть
 - local

 docker-host:
 image: qoomon/docker-host
 cap_add: [ "NET_ADMIN", "NET_RAW" ]
 restart: always
 networks:
 - local

# ...

networks:
 traefik:
 external:
 name: traefik
 local:


 
 # Dockerfile
FROM traefik:v2.5.2

WORKDIR /traefik

COPY ./traefik.yml ./traefik.yml

CMD ["traefik"]

# docker-compose.yml

version: "3.8"

services:
 traefik:
 build: .
 container_name: traefik
 restart: always
 ports:
 # открываем порты для http, https, и дашборда траефика,
 # последним не стоит светить за пределы локальной сети
 # к нему мы будем стучаться через ssh (об этом ниже)
 - 80:80
 - 443:443
 - 127.0.0.1:8080:8080
 volumes:
 # траефику нужен доступ к docker.sock, чтобы мониторить контейнеры
 - /var/run/docker.sock:/var/run/docker.sock:ro
 # а вот и вольюм для сертификатов
 - /data/letsencrypt:/letsencrypt
 networks:
 - traefik

 # для примера подключим whoami - простенький сервис, который показывает
 # инфу о запросе в текстовом виде
 whoami:
 image: "traefik/whoami"
 restart: always
 labels:
 # включаем траефик для этого контейнера
 - traefik.enable=true
 # задаем сеть траефика
 - traefik.docker.network=traefik
 # самое интересное: добавляем роутер и правило для него
 # в нашем случае роутер будет назваться whoami
 # и будет доступен по домену example.com
 # обязательно добавьте название роутера, оно должно
 # быть уникальным, в нашем случаем это whoami (идет после
 # traefik.http.routers.)
 - traefik.http.routers.whoami.rule=Host(`example.com`)
 # Задаем через какой энтрипоинт будет доступен роутер
 - traefik.http.routers.whoami.entrypoints=https
 # задаем certresolver
 - traefik.http.routers.whoami.tls.certresolver=simple-resolver
 # на самом деле порт не обязательно указывать явно
 # traefik в состоянии сам определить, какой порт слушает сервис,
 # но может так случиться, что один контейнер слушает сразу несколько
 # портов (к примеру так делает rabbitMq), тогда надо будет создавать
 # несколько роутеров и явно прописывать несколько портов
 - traefik.http.services.whoami.loadbalancer.server.port=80
 networks:
 - traefik

# ну и собственно сети
networks:
 traefik:
 external:
 name: traefik
 

Всё, теперь можно запускать и радоваться
Если хотите потыкать в dashboard, то это можно сделать, зафорвардив порты через ssh…

ssh -L 8080:localhost:8080 root@example.com

…и открыть в браузере localhost:8080

Что такое Traefik и как им пользоваться?, image #2

Проксирование внешних сервисов

Traefik можно использовать не только для сервисов в Docker, но и для внешних. Из коробки поддерживает балансировку нагрузки, т.е. если у вас реплицирован сервис, то просто указываете все хосты и траефик возьмет на себя всю остальную работу.

Для проксирования внешних сервисов (вне докер сети) надо добавить провайдер в traefik.yml

 
 # traefik.yml

# ...

providers:
 docker:
 network: traefik
 exposedbydefault: false

 # добавляем file провайдер, который будет подтягивать данные из
 # директории external
 file:
 directory: ./external

# ...
 

Для проксирования сервисов в локальной сети требуется добавить docker-host сервис, так как localhost внутри контейнера укажет на сеть самого контейнера, а не на локальную сеть машины.

 
 # docker-compose.yml

version: "3.8"

services:
 # ...
 traefik:
 # ...
 networks:
 - traefik
 # добавляем общую для докерхоста и траефика сеть
 - local

 docker-host:
 image: qoomon/docker-host
 cap_add: [ "NET_ADMIN", "NET_RAW" ]
 restart: always
 networks:
 - local

# ...

networks:
 traefik:
 external:
 name: traefik
 local:
 
 
 # Dockerfile

FROM traefik:v2.5.2

WORKDIR /traefik

COPY ./traefik.yml ./traefik.yml
# копируем папку с конфигами внешних сервисов
COPY ./external ./external

CMD ["traefik"]

И сам конфиг внешнего сервиса. Все конфиги кидаем в директорию external.

 
 # external/example.yml
http:
 services:
 example-api:
 loadBalancer:
 servers:
 # если сервис расположен на внешнем хосте,
 # то просто пишем ip или домен
 - url: "http://123.456.789.123:4716"
 example-web-client:
 loadBalancer:
 servers:
 # если на localhost, то docker-host
 - url: "http://docker-host:8132"

 routers:
 example-web-client:
 entryPoints:
 - https
 # вебклиент будет доступен по любым путям на домене # web.example.com
 rule: "Host(`site.example.com`)"
 service: example-web-client
 tls:
 certResolver: simple-resolver
 example-api:
 entryPoints:
 - https
 # апи будет доступно только на site.example.com/api(.*)
 # при этом для вебклиента не надо прописывать дополнительные
 # правила, траефик сам будет роутить запросы на /api,
 # это работает примерно как специфичность в css
 rule: "Host(`site.example.com`) && PathPrefix(`/api`)"
 service: example-api
 tls:
 certResolver: simple-resolver
 

Wildcard сертификаты

Traefik умеет и работать с Wildcard сертификатами! Перепишем docker-compose.yml так, чтобы whoami был доступен по *.example.com

Для начала надо добавить wildcard-resolver в конфиг Traefik.


# traefik.yml

certificatesResolvers:
 # ...
 wildcard-resolver:
 acme:
 dnschallenge:
 # указываем dns провайдера, в этом примере будет godaddy,
 # но траефик умеет работать и с другими:
 # https://doc.traefik.io/traefik/https/acme/#dnschallenge
 provider: godaddy
 email: me@example.com
 storage: /letsencrypt/acme.jso
 
 

# docker-compose.yml

version: "3.8"

services:
 traefik:
 build: ./proxy
 container_name: traefik
 restart: always
 environment:
 # указываем api ключи нашего провайдера из переменных окружения
 - GODADDY_API_KEY=${GODADDY_API_KEY}
 - GODADDY_API_SECRET=${GODADDY_API_SECRET}
 - GODADDY_POLLING_INTERVAL=10
 - GODADDY_PROPAGATION_TIMEOUT=300
 ports:
 - 80:80
 - 443:443
 - 127.0.0.1:8080:8080
 volumes:
 - /var/run/docker.sock:/var/run/docker.sock:ro
 - /data/letsencrypt:/letsencrypt
 labels:
 - traefik.enable=true
 - traefik.http.routers.api.entrypoints=http
 networks:
 - local
 - traefik

 whoami:
 image: "traefik/whoami"
 restart: always
 labels:
 - traefik.enable=true
 - traefik.docker.network=traefik
 # меняем правила для роутера
 - traefik.http.routers.whoami.rule="Host(`example.com`) || HostRegexp(`{subdomain:.+}.example.com`)"
 - traefik.http.routers.whoami.entrypoints=https
 # задаём wildcard-resolver
 - traefik.http.routers.whoami.tls.certresolver=wildcard-resolver
 # домены, на которые ресолвер будет получать серты
 - traefik.http.routers.whoami.tls.domains[1].main=example.com
 - traefik.http.routers.whoami.tls.domains[1].sans=*.example.com
 - traefik.http.services.whoami.loadbalancer.server.port=80

 networks:
 - traefik

 # ...
 
 

Middlewares

Traefik позволяет создавать Middleware и навешивать их на роутеры и даже энтри поинты!

К примеру, еслинадо убрать какой-нибудь сервис из поисковой выдачи, то всегда можно просто навесить на него хедер X-Robots-Tag: noindex, nofollow


# docker-compose.yml

# ...
 whoami:
 image: "traefik/whoami"
 restart: always
 labels:
 - traefik.enable=true
 - traefik.docker.network=traefik
 - traefik.http.routers.whoami.rule="Host(`example.com`) || HostRegexp(`{subdomain:.+}.example.com`)"
 - traefik.http.routers.whoami.entrypoints=https
 - traefik.http.routers.whoami.tls.certresolver=wildcard-resolver
 - traefik.http.routers.whoami.tls.domains[1].main=example.com
 - traefik.http.routers.whoami.tls.domains[1].sans=*.example.com
 - traefik.http.services.whoami.loadbalancer.server.port=80
 # Создаем middleware, где:
 # noindex - название
 # headers - тип мидлвера
 - "traefik.http.middlewares.noindex.headers.customresponseheaders.X-Robots-Tag=noindex, nofollow"
 # Добавляем наш мидлвер роутеру
 - traefik.http.routers.whoami.middlewares=noindex@docker
 
 

На роутер можно навешать сразу несколько мидлверов, в таком случае их надо указывать через запятую.

- “traefik.http.routers.whoami.middlewares=noindex@docker, something@docker, example@file”

Middleware можно вешать не только на роутеры, но и на целые энтри поинты. В таком случае все равно создаем middleware в лейблах, можно это сделать на самом Traefik.


# docker-compose.yml
# ...
 traefik:
 # ...
 labels:
 - "traefik.enable=true"
 - "traefik.docker.network=traefik"
 - "traefik.http.routers.api.entrypoints=http"
 - "traefik.http.middlewares.noindex.headers.customresponseheaders.X-Robots-Tag=noindex, nofollow"
# ...

И добавить в traefik.yml мидлвер в энтрипоинт

# traefik.yml
# ...
entrypoints:
 http:
 address: :80
 http:
 redirections:
 entryPoint:
 to: https
 scheme: https
 permanent: true
 https:
 address: :443
 # добавляем http middleware
 http:
 middlewares:
 - "noindex@docker"
# ...

Подробнее читайте в документации https://doc.traefik.io/traefik/middlewares/overview/

  • Технологии