В процессе разработки и исследования новых для меня инструментов, таких как Docker, Traefik и веб сервисы на .Net Core, возникла необходимость переадресации сетевых запросов к контейнизированному веб сервису.
Если вам инетересно найденное решение описанной проблемы, прошу под кат
Что имеем:
- Хостинг host.ru
- Docker контейнер с .Net Core веб сервисом авторизации (auth)
- Docker контейнер c Traefik 2.0
Что хотим:
- Определять по пути (path) в запросе к какому контейнеру переадресовать сетевой запрос
http://host.ru/path
Проблема:
- Запрос, который переадресовывается в .Net Core контейнер, содержит
GET: /path
- Контейнер с .Net Core сервисом имеет свой веб сервер Kestrel, который внутри контейнера пытается сам переадресовать запрос к сервису и не может найти такого пути
, следовательно мы должный модифицировать запрос средствами Traefik и заменить:GET: /path
/path на /
Найденное решение:
- В настройках контейнера auth делаем следующее
labels: #определяем, что пришел запрос к path - "traefik.http.routers.auth.rule=PathPrefix(`/path`)" #модифицируем запрос - "traefik.http.middlewares.auth-stripprefix.stripprefix.prefixes=/path" #определяем ПО промежуточного слоя - "traefik.http.routers.auth.middlewares=auth-stripprefix@docker
Результат:
- Все запросы по адресу host.ru/path модифицируются и направляются в контейнер auth, где уже сервер Kestrel корректно обрабатывает запрос
- Корректно выполняются так же запросы вида host.ru/auth/foo
Не претендую на красивость решения, на корректность в выборе инструментов.
version: "3.5"
services:
reverse-proxy:
image: traefik:v2.0
container_name: reverse-proxy
command:
--providers.docker
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
auth:
image: auth:latest
container_name: auth_traefik
ports:
- 3001:80
labels:
- "traefik.http.routers.auth.rule=PathPrefix(`/path`)"
- "traefik.http.middlewares.auth-stripprefix.stripprefix.prefixes=/path"
- "traefik.http.routers.auth.middlewares=auth-stripprefix@docker
Комментарии (4)
suxarik
05.12.2019 09:22Это нужно только когда много разных эндпоинтов и нужно их разруливать на traefik. В данном случае мне кажется гораздо логичнее сделать на Kestrel биндинг на virtual path (/auth), раз все запросы на него идут через внешние балансеры
Geminix Автор
05.12.2019 09:54Да это было бы проще, но мы тогда сделаем контейнер с сервисом, зависимым от ещё каких-то внешних условий
Yustos
05.12.2019 13:02Привет!
Traefik кеширует коннекты до бэкендов.
Например, пришел пользователь А. Бэкенд B потребовал ntlm-аутентификацию. Аутентификация была выполнена успешно (потребуется stick режим, поскольку ntlm проходит через несколько запросов и они должны попадать в один бэкенд). Traefik будет держать этот же коннект открытым какое-то время (пять минут или вроде того). В течении этих пяти минут другие пользователи, попавшие на бэкенд B будут работать под учеткой пользователя A.
На connection:close traefik не реагирует.
Вот API для проверки:
[HttpGet("Whoami")] public IActionResult Whoami() { var user = _context?.HttpContext?.User?.Identity?.Name; if (user == null) { return Unauthorized(); } var ctx = _context.HttpContext; return Ok(new { user, ctx.Connection.Id, ctx.TraceIdentifier, IP = ctx.Connection.RemoteIpAddress.ToString() }); }
Дергаете метод сами, затем просите соседа. Всё работает? Пользователь корректен? ConnectionId меняется?
Ernado
В данном случае, вместо .NET Core можно подставить любой сервис написанный на чем угодно.