MEAN-stack и Docker. Часть 3 - Traefik reverse proxy
Третья часть цикла, посвященного контейнеризации MEAN-stack приложений, в которой мы настроим обратный прокси-сервер (reverse proxy) и балансировщик нагрузки (load balancer) Traefik.
Содержание цикла
- Часть 1 - Dockerfile, образы, контейнеры
- Часть 2 - Docker Compose
- Часть 3 - Traefik reverse proxy
- Часть 4 - Docker Swarm
- Часть 5 - Mongo Replica Set в Docker Swarm
Введение
В предыдущей части мы написали docker-compose файл, в котором настроили запуск сервисов с серверной частью приложения, клиентской частью и базой данных. Теперь же нам необходимо настроить приложение следующим образом:
- Angular приложение должно быть доступно только по адресу
docker-example.local
; - серверное api должно принимать запросы по адресу
api.docker-example.local
; - должен быть открыт только порт 80.
Для этого нужно поднять прокси-сервер, который будет принимать все запросы на порту 80 и по хосту ретранслировать запросы на сервис client
для docker-example.local
и на server
для api.docker-example.local
.
Самое популярное решение для этих целей - использовать прокси-сервер nginx. Однако в этом проекте я попробую использовать Traefik - молодой реверс-прокси сервер и балансировщик нагрузки, который подает большие надежды.
Такой выбор был сделан по следующим причинам:
- хорошая интеграция с Docker, Docker Swarm, Kubernetes
- более интуитивная конфигурация и настройка
- HTTPS от Let's Encrypt из коробки
- еще ряд некоторых плюшек из разряда Websocket, HTTP/2, метрики Prometheus
- интересно попробовать
Hosts
Сперва добавим наши фейковые домены в hosts:
# windows: c:/windows/system32/drivers/etc/hosts
# ubuntu/mac: /etc/hosts
127.0.0.1 docker-example.local
127.0.0.1 api.docker-example.local
# Traefik Dashboard
127.0.0.1 traefik.docker-example.local
Конфигурация Traefik
Вся настройка Traefik производится в том же docker-compose файле.
docker-compose.yml
services:
# ...
# Добавляем сервис реверс-прокси Traefik
reverse-proxy:
image: traefik
# В командах производим основную настройку
command:
# Включаем Traefik Dashboard (порт 8080)
- "--api"
# Точка входа http на порту 80 используется по умолчанию
- "--entrypoints=Name:http Address::80"
- "--defaultentrypoints=http"
# Включаем режим совместимости с Docker
- "--docker"
# Домен по умолчанию
- "--docker.domain=docker-example.local"
# Следить за изменениями докера
- "--docker.watch"
restart: always
# Открываем только 80 порт
ports:
- 80:80
# Даем Traefik доступ к docker.sock
# для отслеживания событий Docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Подключаемся к сети для прокси
networks:
traefik-net:
# Альтернативное имя хотса для доступа по сети traefik-net
aliases:
- api.docker-example.local
# В метках сервисов прописываем правила для Traefik
labels:
# Запросы на хост `traefik.docker-example.local`
- traefik.frontend.rule=Host:traefik.docker-example.local
# перенаправлять на порт 8080 (Traefik Dashboard) этого сервиса
- traefik.port=8080
Настройка сервисов
Сами сервисы подключим к сети traefik-net
, избавляемся от проброшенных портов. В labels зададим правила проксирования.
server service:
server:
image: myusername/public:mean-docker-server
restart: on-failure
depends_on:
- db
environment:
- "db:uri=mongodb://db/docker"
networks:
# Подключаемся к сети
- traefik-net
- db-net
# В метках прописываем правила для Traefik
labels:
# Для реверс-прокси использовать сеть traefik-net
- traefik.docker.network=traefik-net
# Запросы на хост `api.docker-example.local`
- traefik.frontend.rule=Host:api.docker-example.local
# перенаправлять на порт 3000 этого сервиса
- traefik.port=3000
client service:
client:
image: myusername/public:mean-docker-client
restart: on-failure
depends_on:
- server
networks:
# Подключаемся к сети
- traefik-net
labels:
# Запросы на хост `docker-example.local`
- traefik.frontend.rule=Host:docker-example.local
# перенаправлять на порт 4000 этого сервиса
- traefik.port=4000
db service:
db:
image: mongo
restart: on-failure
# К сети proxy-net не подключаемся
# с сервером общаемся по db-net
networks:
- db-net
labels:
# В проксировании не нуждаемся
- traefik.enable=false
Сети:
networks:
traefik-net:
external: true
db-net:
В работе с сетями у траефика есть небольшая проблема. Дело в том, что docker compose при старте создает сети и к их именам добавляет префикс с названием проекта. Т.е. в compose файле мы указываем, что необходимо создать сеть traefik-net
. В метке сервиса server мы указываем traefik, что для прокси из двух сетей необходимо использовать traefik.docker.network=traefik-net
. Но после старта эта сеть не будет найдена, ибо докер назвал ее mean-docker-stack_traefik-net
.
Есть два выхода:
- Предугадывать переименование сети и указывать
traefik.docker.network=mean-docker-stack_traefik-net
; - Предварительно перед запуском создать external сеть
traefik-net
и использовать ее, указав, что она являетсяexternal
в docker-compose файле.
В данном случае я воспользовался вариантом №2.
Настройка HTTPS от Let's Encrypt в Traefik
Для настройки https в командах сервиса reverse-proxy
добавим/заменим следующие строки:
reverse-proxy:
# ...
command:
- "--api"
- "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
- "--entrypoints=Name:https Address::443 TLS"
- "--defaultentrypoints=http,https"
- "--acme"
- "--acme.storage=/etc/traefik/acme/acme.json"
- "--acme.entryPoint=https"
- "--acme.httpChallenge.entryPoint=http"
- "--acme.onHostRule=true"
- "--acme.onDemand=false"
- "--acme.email=contact@mydomain.com"
Во время тестирования рекомендую использовать Let's Encrypt's staging server:
- "--acme.caServer=https://acme-staging.api.letsencrypt.org/directory"
Подробнее читать в официальной документации Traefik.
Запуск
Предварительно создадим сеть traefik-net
:
docker network create traefik-net
Запускаем уже известной нам командой:
docker-compose up
Рабочее приложение наблюдаем в браузере по адресу http://docker-example.local/
В следующей части попробуем развернуть наше приложение в кластере Docker Swarm.