Русский
Русский
English
Статистика
Реклама

Из песочницы Введение в Traefik 2.0

Traefik это обратный прокси-сервер с открытым исходным кодом, обеспечивающий простую работу с микросервисами и/или просто контейнерами с вашими приложениями.


Обратный прокси-сервер (reverse proxy, реверс-прокси) служит для ретрансляции запросов из внешней сети к каким-либо серверам/сервисам внутренней сети (например веб-сервера, БД или файловые хранилища) и позволяет:


  • обеспечить сокрытие структуры внутренней сети и подробностей о находящейся в ней сервисах;
  • осуществлять балансировку нагрузки (load balancing) между экземплярами одного и того же сервиса или серверами с одинаковыми задачами;
  • обеспечить зашифрованное (HTTPS) соединение между клиентом и любым сервисом, в таком случае SSL сессия создается между клиентом и прокси, а между прокси и сервисом во внутренней сети устанавливается незашифрованное HTTP соединение, если сервис поддерживает HTTPS то можно организовать зашифрованное соединение и во внутренней сети;
  • организовать контроль доступа к сервисам (аутентификацию клиента), а также установить файрвол (брандмауэр).

В статье будет описываться использование Traefik в Docker в качестве реверс-прокси для других контейнеров Docker, а также не контейнеризированных сервисов.


image


Введение


Traefik позиционируется разработчиками как Edge Router, то есть можно направить его непосредственно в глобальную сеть одной стороной и во внутреннюю другой. Если у читателя создалось впечатление что таким образом создается единая точка отказа всей системы, то так и есть, но есть несколько моментов: во-первых, Traefik имеет развитый функционал для автоматического восстановления при сбоях; во-вторых, существует Traefik EE платная версия, в которой помимо прочих преимуществ имеется HA (Hight Availability, Высокая доступность), что подразумевает распределение нагрузки между несколькими экземплярами сервиса (узлами), таким образом при отказе одного его задачи перераспределяются на другие узлы, а отказавший узел отключается и затем немедленно вводится обратно в эксплуатацию. В качестве примечания отметим, что в статье будет рассматриваться бесплатная версия Traefik.


Одним из основных достоинств Traefik является возможность изменения его конфигурации без приостановки работы (на лету) при применении любого и поддерживаемых бэкэндов, называемых провайдерами.


Список основных провайдеров:


  • Docker
  • Kubernetes
  • Consul Catalog
  • Marathon
  • Rancher
  • File

В рамках этой статьи будут рассмотрены первый и последний провайдеры из этого списка.
Вероятно, не знакомому с темой читателю будет не понятно, чем является провайдер с именем File, это некоторый файл (или папка с файлами), в котором описана конфигурация какого-либо сервиса, не связанного с другими провайдерами, но который должен быть скрыт за реверс-прокси. Остальные же провайдеры являются различными системами оркестрации контейнеров.


Файл конфигурации Traefik, а также файлы для провайдера File могут быть написаны на TOML либо YAML, в статье будут приведены примеры на YAML так как этот синтаксис больше нравится автору, а какой-либо функциональной разницы между ними нет, а также не составляет трудности переписать файлы на другой формат конфигурации. Traefik будет развернут в Docker. Для развертывания будет использоваться docker-compose, для обеспечения простоты повторного развертывания.


*В статье будут приведены команды для ОС Linux.


Деплой Traefik


Предполагается что у читателя установлены и настроены docker и docker-compose, их установка выходит за рамки этой статьи.


Создадим в домашней папке пользователя папку traefik, в которой будем хранить всю конфигурацию, и перейдем в эту папку


mkdir ~/traefikcd ~/traefik

Для развертывания (деплоя) Traefik создадим файл docker-compose.yml и отредактируем его в любом удобном вам редакторе. Для начала этот файл будет иметь следующий вид:


version: '3'services:  traefik:    image: traefik:v2.2    container_name: traefik    restart: unless-stopped    security_opt:      - no-new-privileges:true    ports:      - 80:80      - 443:443     volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro

Во внешний мир будут смотреть порты 80 и 443 для HTTP и HTTPS соответственно. Также пробросим в контейнер сокет демона Docker для работы механизма автоматической конфигурации. Конфигурацию Traefik будем описывать в файле traefik.yml находящемся в папке data в текущей директории.


Если для разделения внешней и внутренней сетей используются networks Docker-а, то Traefik должен иметь доступ к внешней сети и ко всем внутренним в которых находятся целевые сервисы.

Создадим и будем постепенно наполнять этот файл.


Для начала опишем точки входа в наш прокси (те самые порты, которые смотрят во внешний мир):


entryPoints:  http:    address: ":80"  https:    address: ":443"

Здесь http и https это просто названия (могут быть любыми, хоть a и b) и были выбраны так для удобства.


Теперь добавим первого провайдера Docker, это делается следующим образом:


providers:  docker:    endpoint: "unix:///var/run/docker.sock"    exposedByDefault: false

Параметром указываем что Traefik не должен брать все контейнеры подряд, далее будет объяснено каким образом мы будем сообщать какие контейнеры нас интересуют. Также здесь видно зачем мы пробрасывали сокет в контейнер именно через него Traefik будет получать сведения о запускаемых контейнерах на этом хосте (можно подключиться и к демону на другом хосте).


Следующим шагом развернем весь HTTP трафик в HTTPS (почему это было сделано именно таким образом будет описано дальше):


http:  routers:    http-catchall:      rule: HostRegexp(`{host:.+}`)      entrypoints:      - http      middlewares:      - redirect-to-https  middlewares:    redirect-to-https:      redirectScheme:        scheme: https        permanent: false

Traefik может проксировать не только HTTP трафик, но и просто TCP и UDP, поэтому указываем что этот блок конфигурации относится к http.


Здесь мы встречаем два из трех основных элементов роутинга в Traefik 2 routers (роутеры) и middlewares(промежуточные обработчики), рассмотрим их подробнее.


Роутеры


Рассмотрим на примере описанного выше роутера:


  • http-catchall имя роутера, может быть любым, но обязано быть уникальным в рамках блока http всей конфигурации Traefik;
  • rule: правило, описывает какой трафик попадает в этот роутер, в данном случае описывается HostRegexp, то есть поле Host запроса должно попадать под регулярное выражение .+ (то есть любое), здесь мы видим специфику регулярных выражений в Traefik оно должно быть заключено в фигурные скобки и иметь наименование (host в данном случае), то есть синтаксис имеем вид {name:reg_exp};
  • entrypoints массив описанных ранее точек входа, которые будут использоваться этим роутером, в нашем случае используем только http;
  • middlewares массив промежуточных обработчиков, куда попадает трафик перед передачей к сервису (сервисы будут рассмотрены позднее).

Подробнее о различных видах правил можно прочитать в документации.


Промежуточные Обработчики


  • redirect-to-https имя обработчика, может быть любым, но обязано быть уникальным в рамках блока http всей конфигурации Traefik;
  • redirectScheme тип обработчика, в данном случае изменение схемы запроса;
  • scheme: https вынуждает клиента использовать схему HTTPS при запросе к прокси;
  • permanent: false говорит клиенту что это не навсегда и может измениться в будущем.

Подробнее о различных обработчиках можно прочитать в документации (дальше в статье будет описан ещё один обработчик BasicAuth).


Полностью файл traefik.yml
entryPoints:  http:    address: ":80"  https:    address: ":443"http:  routers:    http-catchall:      rule: hostregexp(`{host:.+}`)      entrypoints:      - http      middlewares:      - redirect-to-https  middlewares:    redirect-to-https:      redirectScheme:        scheme: https        permanent: falseproviders:  docker:    endpoint: "unix:///var/run/docker.sock"    exposedByDefault: false

Таким образом мы получим первую рабочую конфигурацию. Выполняем


sudo docker-compose up -d

И прокси должен подняться, можно почитать логи (sudo docker-compose logs -f) и убедиться, что всё работает.


Let's Encrypt


Поскольку мы хотим использовать HTTPS нам нужно где-то взять SSL сертификаты для сервисов, есть возможность использовать свои сертификаты, но мы настроем автоматическое получение бесплатных сертификатов от Let's Encrypt.


Добавим в конфигурацию (traefik.yml) новый блок:


certificatesResolvers:  letsEncrypt:    acme:      email: postmaster@example.com      storage: acme.json      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"      httpChallenge:        entryPoint: http

Здесь:


  • letsEncrypt это просто имя резолвера;
  • acme тип резолвера (других типов в общем-то и нет);
  • storage файл, в котором хранятся сведения о полученных сертификатах;
  • httpChallenge тип acme-челенжа, дополнительно указываем параметр точку входа;
  • caServer: "https://acme-staging-v02.api.letsencrypt.org/directory" позволяет использовать не основной сервер Let's Encrypt в тестовых целях, так как основной имеет строгие лимиты API (можно закомментировать, когда наладите получение сертификатов).

Также дополним пункт volumes в файле docker-compose.yml, чтобы сохранять сертификаты при перезапуске контейнера (предварительно создав файл data/acme.json):


    volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro      - ./data/acme.json:/acme.json

Docker провайдер


HTTPS настроен, пришло время поднять первый сервис, пусть это будет дашборд самого Traefik, так как Traefik у нас в Docker, воспользуемся этим провайдером.


Для описания конфигурации в Docker Traefik использует метки (labels) контейнеров. Допишем в наш файл docker-compose.yml:


    labels:      - "traefik.enable=true"      - "traefik.http.routers.traefik.entrypoints=https"      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"      - "traefik.http.routers.traefik.tls=true"      - "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"      - "traefik.http.routers.traefik.service=api@internal"      - "traefik.http.services.traefik-traefik.loadbalancer.server.port=888"

Разберем построчно:
traefik.enable=true указываем что Traefik должен обеспечить доступ к этому контейнеру, необходимо для всего остального;
traefik.http.routers.traefik.entrypoints=https создаем новый роутер с точной входа https;
traefik.http.routers.traefik.rule=Host(traefik.example.com) роутер будет жить по адресу traefik.example.com;
traefik.http.routers.traefik.tls=true указываем что используется TLS;
traefik.http.routers.traefik.tls.certresolver=letsEncrypt указываем через какой резолвер получать сертификат;
traefik.http.routers.traefik.service=api@internal указываем, что сервер за этим роутером api@internal, это специальный сервис, созданный по умолчанию, это как раз и есть дашбоард который мы хотели увидеть;
traefik.http.services.traefik-traefik.loadbalancer.server.port=888 издержки интерфейса, без этого не заработает, но можно написать абсолютно любую цифру.


Дашбоард надо включить, для этого добавим в файл traefik.yml:


api:  dashboard: true

На данном этапе можно пересоздать контейнер (нужно так как мы меняли docker-compose.yml):


sudo docker-compose down && sudo docker-compose up -d

Когда всё поднимется можно перейти на traefik.example.com (тут на самом деле должен быть ваш домен, который направлен на хост с Traefik) и увидеть дашборд.


Дашбоард это хорошо, но мы не хотим, чтобы все пользователи интернета имели к нему доступ, закроем его от внешнего мира с помощью BasicAuth, для это в Traefik есть специальный middleware.


Для начала сгенерируем для нас строку с логином и паролем (admin/password)^


$ htpasswd -nb admin passwordadmin:$apr1$vDSqkf.v$GTJOtsd9CBiAFFnHTI2Ds1

Теперь добавим в наш docker-compose.yml новые строчки:


      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$vDSqkf.v$$GTJOtsd9CBiAFFnHTI2Ds1"      - "traefik.http.routers.traefik.middlewares=traefik-auth"

Заметим, что символы $ из полученной строки мы должны заменить на $$.
traefik.http.middlewares.traefik-auth.basicauth.users=... создаем middleware типа basicauth с параметром users;
traefik.http.routers.traefik.middlewares=traefik-auth указываем что роутер traefik использует только что-то созданный middleware.


Весь docker-compose.yml
version: '3'services:  traefik:    image: traefik:v2.2    container_name: traefik    restart: unless-stopped    security_opt:      - no-new-privileges:true    ports:      - 80:80      - 443:443     volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro      - ./data/acme.json:/acme.json    labels:      - "traefik.enable=true"      - "traefik.http.routers.traefik.entrypoints=https"      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"      - "traefik.http.routers.traefik.tls=true"      - "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"      - "traefik.http.routers.traefik.service=api@internal"      - "traefik.http.services.traefik-traefik.loadbalancer.server.port=888"      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$vDSqkf.v$$GTJOtsd9CBiAFFnHTI2Ds1"      - "traefik.http.routers.traefik.middlewares=traefik-auth"

Теперь при попытке доступа к дашборду у нас спросят логин и пароль.


Приведем также кофигурацию некого другого сервиса, развернутого через docker-compose (аналогично работает и для обычного docker):


    labels:      - "traefik.enable=true"      - "traefik.http.routers.test.entrypoints=https"      - "traefik.http.routers.test.rule=Host(`test.example.com`)"      - "traefik.http.routers.test.tls=true"      - "traefik.http.routers.test.tls.certresolver=letsEncrypt"      - "traefik.http.services.test-service.loadbalancer.server.port=80"

Здесь одна новая метка traefik.http.services.test-service.loadbalancer.server.port=80 присваиваем этому контенеру имя сервиса test-service и порт 80, он автоматически присоединится к роутеру test, Traefik автоматически постороит маршрут до этого контенера, даже если он находится на другом хосте.


File провайдер


С контейнерами работает, а как быть если есть какой-то сервис работающий на выделенном хосте (пускай IP 192.168.1.222 и порт 8080) и мы его хотим пропустить через этот же прокси, заодно закрыв его с помощью HTTPS. Для этого есть решение.


Добавим в docker-compose.yml ещё один volume:


    volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro      - ./data/custom/:/custom/:ro      - ./data/acme.json:/acme.json

Пускай описания таких хостов у нас будут лежать в data/custom/ (а что, вдруг ещё появятся).


Добавим в traefik.yml конфигурацию file провайдера для этих файлов:


providers:...  file:    directory: /custom    watch: true

Директория следует из нашего docker-compose.yml, а watch: true значит что Traefik будет автоматически обновлять конфигурацию при обнаружении изменений в этих файлах (помните про обновление конфигурации на лету, вот работает даже для файлов, а не только для оркестраторов).


Перезапускаем Traefik и теперь можно создать файл с описанием нашего отдельного хоста (data/custom/host.yml):


http:  routers:    host:      entryPoints:       - https      service: service-host      rule: Host(`host.example.com`)       tls:        certResolver: letsEncryptservices:    service-host:        loadBalancer:        servers:        - url: http://192.168.1.222:8080/        passHostHeader: true 

Роутер описывался раньше, тут добавилось только service: service-host связь с нашим сервисом, и конфигурация для TLS.


Описание для сервиса имеет вид:


имя_сервиса:  loadBalancer:    servers:    - хосты для балансировки нагрузки    - ...

Дополнительно мы указываем параметр passHostHeader: true чтобы тот хост думал, что он на самом деле смотрит в сеть и прокси нет.


Заключение


Приведем содержание файлов с полученными конфигурациями:


docker-compose.yml
version: '3'services:  traefik:    image: traefik:v2.2    container_name: traefik    restart: unless-stopped    security_opt:      - no-new-privileges:true    ports:      - 80:80      - 443:443     volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro      - ./data/custom/:/custom/:ro      - ./data/acme.json:/acme.json    labels:      - "traefik.enable=true"      - "traefik.http.routers.traefik.entrypoints=https"      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"      - "traefik.http.routers.traefik.tls=true"      - "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"      - "traefik.http.routers.traefik.service=api@internal"      - "traefik.http.services.traefik-traefik.loadbalancer.server.port=888"      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$vDSqkf.v$$GTJOtsd9CBiAFFnHTI2Ds1"      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"

data/traefik.yml
api:  dashboard: trueentryPoints:  http:    address: ":80"  https:    address: ":443"http:  routers:    http-catchall:      rule: hostregexp(`{host:.+}`)      entrypoints:      - http      middlewares:      - redirect-to-https  middlewares:    redirect-to-https:      redirectScheme:        scheme: https        permanent: falseproviders:  docker:    endpoint: "unix:///var/run/docker.sock"    exposedByDefault: false  file:    directory: /custom    watch: truecertificatesResolvers:  letsEncrypt:    acme:      email: postmaster@example.com      storage: acme.json      #caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"      httpChallenge:        entryPoint: http

data/custom/host.yml
http:  routers:    host:      entryPoints:       - https      service: service-host      rule: Host(`host.example.com`)       tls:        certResolver: letsEncryptservices:    service-host:        loadBalancer:        servers:        - url: http://192.168.1.222:8080/        passHostHeader: true 

В статье было описано как настроить Traefik в качестве обратного HTTP прокси при использовании провайдеров Docker и File. Было настроено использование бесплатных SSL сертификатов от Let's Encrypt, настроено принудительное перенаправление клиентов на протокол HTTPS, а также приведен пример настройки аутентификации клиентов прокси перед доступом к сервисам.


Режимы TCP и UDP прокси настраиваются похожим образом с небольшими изменениями (подробнее можно прочитать в документации, например TCP), эти режимы позволяют проксировать практически любой трафик, создавая возможность сделать Traefik действительно единственным сервисом смотрящим в глобальную сеть.


Бонус. Мониторинг


Traefik позволяет собирать сведения о своей работе в различных форматах, рассмотрим, как это делается при использовании Prometheus.


Добавим новую точку входа:
data/traefik.yml:


entryPoints:...  metrics:    address: ":8082"

docker-compose.yml:


    ports:      - 80:80      - 443:443       - 8082:8082

И добавим возможность собирать с этого порта метрики для Prometheus, data/traefik.yml:


metrics:  prometheus:    entryPoint: metrics

Осталось только настроить Prometheus на сбор метрик с traefik_ip:8082.


Приведем содержание файлов с полученными конфигурациями:


docker-compose.yml
version: '3'services:  traefik:    image: traefik:v2.2    container_name: traefik    restart: unless-stopped    security_opt:      - no-new-privileges:true    ports:      - 80:80      - 443:443       - 8082:8082    volumes:      - /etc/localtime:/etc/localtime:ro      - /var/run/docker.sock:/var/run/docker.sock:ro      - ./data/traefik.yml:/traefik.yml:ro      - ./data/custom/:/custom/:ro      - ./data/acme.json:/acme.json    labels:      - "traefik.enable=true"      - "traefik.http.routers.traefik.entrypoints=https"      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"      - "traefik.http.routers.traefik.tls=true"      - "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"      - "traefik.http.routers.traefik.service=api@internal"      - "traefik.http.services.traefik-traefik.loadbalancer.server.port=888"      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$vDSqkf.v$$GTJOtsd9CBiAFFnHTI2Ds1"      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"

data/traefik.yml
api:  dashboard: trueentryPoints:  http:    address: ":80"  https:    address: ":443"  metrics:    address: ":8082"metrics:  prometheus:    entryPoint: metricshttp:  routers:    http-catchall:      rule: hostregexp(`{host:.+}`)      entrypoints:      - http      middlewares:      - redirect-to-https  middlewares:    redirect-to-https:      redirectScheme:        scheme: https        permanent: falseproviders:  docker:    endpoint: "unix:///var/run/docker.sock"    exposedByDefault: false  file:    directory: /custom    watch: truecertificatesResolvers:  letsEncrypt:    acme:      email: postmaster@example.com      storage: acme.json      #caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"      httpChallenge:        entryPoint: http
Источник: habr.com
К списку статей
Опубликовано: 28.06.2020 22:13:05
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Devops

Traefik

Docker

Linux

Категории

Последние комментарии

© 2006-2020, personeltest.ru