Рассчитываю, что данная статья больше подойдет для тех, кто столкнулся с настройкой маршрутизации в Traefik 2.0.

В процессе разработки и исследования новых для меня инструментов, таких как Docker, Traefik и веб сервисы на .Net Core, возникла необходимость переадресации сетевых запросов к контейнизированному веб сервису.

image

Если вам инетересно найденное решение описанной проблемы, прошу под кат

Что имеем:

  • Хостинг host.ru
  • Docker контейнер с .Net Core веб сервисом авторизации (auth)
  • Docker контейнер c Traefik 2.0

Что хотим:

  • Определять по пути (path) в запросе к какому контейнеру переадресовать сетевой запрос
    http://host.ru/path

Проблема:

  • Запрос, который переадресовывается в .Net Core контейнер, содержит
    GET: /path
  • Контейнер с .Net Core сервисом имеет свой веб сервер Kestrel, который внутри контейнера пытается сам переадресовать запрос к сервису и не может найти такого пути
    GET: /path
    , следовательно мы должный модифицировать запрос средствами Traefik и заменить:

    /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

Не претендую на красивость решения, на корректность в выборе инструментов.

Пример Docker compose файла с контейнерами Traefik и Auth
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)


  1. Ernado
    04.12.2019 21:07

    В данном случае, вместо .NET Core можно подставить любой сервис написанный на чем угодно.


  1. suxarik
    05.12.2019 09:22

    Это нужно только когда много разных эндпоинтов и нужно их разруливать на traefik. В данном случае мне кажется гораздо логичнее сделать на Kestrel биндинг на virtual path (/auth), раз все запросы на него идут через внешние балансеры


    1. Geminix Автор
      05.12.2019 09:54

      Да это было бы проще, но мы тогда сделаем контейнер с сервисом, зависимым от ещё каких-то внешних условий


  1. 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 меняется?