Использование traefik reverse proxy для упрощения локальной разработки множества web-сервисов
Это небольшой пересказ с примерами конфигураций моего небольшого и спонтанного “воркшопа” про то, как я организовал своё локальное окружение для одновременной разработки n-ного количества web-сервисов.
Предисловие
Пару лет назад, когда я только освоился с технологией docker, у меня был такой подход, что каждый сервис, с которым мне приходится работать через браузер или http client, занимает определённый порт на localhost. Это было больно по нескольким причинам:
- Необходимо точно помнить какие порты уже заняты, да ещё и помнить какой сервис занимает какой порт.
- Для сайтов, работающих по доменным именам, в основном приходилось делать дополнительные записи в файл hosts.
Всё это выливалось в постоянные телодвижения по конфигурации не только когда приходится настраивать окружение на свежеустановленной системе, но и даже при работе на системе, где уже всё настроено.
Да, это не так критично, но всё-равно тратится время. Поэтому в конечном итоге я начал искать пути решения этой проблемы. Поиск по сайтам в google и в ответах на stackoverflow приносил мало результатов. Решения в основном заключались в настройке локального dns-сервера и статической или динамической его конфигурации. Решения эти были довольно сложными в реализации, да и ещё не было понимания, как это повлияет на ОС.
Так я и сидел, прокидывая порты на хост, решая конфликты и вспоминая четырёхзначные числа. Пока я не нашёл traefik
, который позиционирует себя как “продвинутый HTTP reverse proxy и load balancer”. Первая часть меня зацепила, и, почитав документацию, я пришёл к выводу, что это идеальное решение проблемы, описанной выше.
Использование traefik
Я не буду вдаваться в глубокий разбор технологии реверсивного проксирования или самого traefik, просто расскажу, как конкретно он помогает в разработке и почему это удобно.
Первым шагом будет запуск traefik. Для простоты (а именно это приоритет в локальной разработке) всё буду делать через docker-compose и docker-compose.yml файлы. Таким образом, выделим директорию где-то на диске и начнём. У меня это директория ~/code/libs
. Создаём внутри неё новую директорию traefik
.
1 | cd ~/code/libs |
Перейдя туда, начинаем описывать конфигурацию стека из одного сервиса:
1 | version: '3.7' |
Немного о конфигурации. Порт 80
используется для непосредственных запросов в сервисы через traefik. На порту 8080
располагается небольшой dashboard с небольшим количеством информации для мониторинга. Том с сокетом докера необходимо добавить в контейнер, иначе traefik не сможет использовать провайдер докера. И немного по ключу command
:
--api.insecure=true
включаем доступ до dashboard--providers.docker
включаем провайдер docker--providers.docker.network=traefik_default
говорим traefik использовать только его дефолтную сеть для поиска сервисов, готовых к взаимодействию--providers.docker.exposedByDefault=false
данный флаг отключает автоматическое подключение всех контейнеров к traefik. В противном случае, traefik будет пытаться создать прокси до всех сервисов, у которых открыт хотя бы один порт.
Запускаем стек:
1 | docker-compose up --build -d |
И проверим, что всё запустилось, перейдя в браузере по http://localhost:8080
. Отобразится такая страница с dashboard.
Следующим шагом будет запуск какого-нибудь сервиса с web-интерфейсом. Для примера я взял AWS-S3 совместимое хранилище minio. Рядом с директорией traefik
создадим директорию minio
с файлом docker-compose.yml
внутри:
1 | cd .. |
Базовая конфигурация этого сервиса через docker-compose
будет выглядеть следующим образом:
1 | version: '3.7' |
Теперь необходимо сделать так, чтобы traefik
и minio
смогли общаться между собой. Для этого в конец minio/docker-compose.yml
добавляем сеть traefik_default
как внешнюю. И сразу же скажем сервису minio
использовать новую сеть. Конфигурация теперь будет иметь вид:
1 | version: '3.7' |
Ну и наконец, собственно магия traefik. В сервис необходимо добавить три лейбла:
- traefik.enable=true
, чтобы сервис был включён в список конечных точек проксирования.
1
traefik.http.routers.<serviceName>.rule=Host(`<hostName>.docker.localhost`)
где `<serviceName>` нужно заменить на название сервиса, оно не обязательно должно совпадать с названием в `docker-compose.yml`, `<hostName>` нужно заменить на валидный поддомен. Валидность заключается в соблюдении правил построении доменных имён.
traefik.http.services.<serviceName>.loadbalancer.server.port=<port>
обязательно необходимо добавлять, если сервис слушает порт отличный от 80.
Заключительный вид файла minio/docker-compose.yml
:
1 | version: '3.7' |
Запустим контейнер с minio
1 | docker-compose up --build -d |
Теперь достаточно перейти по url http://minio.docker.localhost
и убедиться, что всё работает.
Вот таким образом можно без каких-либо проблем задавать доступность сервисов по доменному имени в домене *.docker.localhost
на локальной машине. Дополнительно traefik предоставляет гибкую настройку множества параметров, в том числе и https, а также поддерживает работу не только с обычными контейнерами docker
, запускаемыми через docker run
или docker-compose
, но и docker swarm
, и kubernetes
.