Настройка обратного прокси Traefik v2 для контейнеров Docker в Ubuntu

Docker – довольно эффективный метод запуска приложений в среде производства. Но в некоторых ситуациях нужно запустить несколько приложений на одном хосте Docker. Возможно ли это и как это сделать? Да, в такой ситуации можно настроить обратный прокси-сервер, который будет поддерживать открытыми только порты 80 и 443.

Traefik – это обратный прокси с поддержкой Docker и встроенным дашбордом для мониторинга. Уже довольно давно широко используется Traefik v1. Но в этом мануале мы установим и настроим Traefik v2, который довольно сильно отличается от v1.

Читайте также: Настройка обратного прокси-сервера Traefik для контейнеров Docker в Ubuntu 20.04

Одно из основных отличий Traefik v2 от v1 в том, что в нем нет фронтендов и бэкендов – их функциональность распределена между маршрутизаторами, промежуточном программным обеспечением и сервисами. Ранее бэкенд выполнял работу по внесению изменений в запросы и передаче этого запроса той стороне, что должна была его обрабатывать. За счет внедрения промежуточного программного обеспечения, которое может изменять запросы перед их отправкой сервису, Traefik v2 более подробно распределяет задачи. Промежуточное ПО позволяет записывать внесение изменений пошагово, благодаря чему их могут использовать разные маршрутизаторы; также их можно использовать повторно. Маршрутизаторы также могут использовать множество различных промежуточных программ.

Данный мануал поможет настроить Traefik для маршрутизации запросов к двум разным контейнерам приложений: WordPress и Adminer. Каждый контейнер подключен к БД MySQL. Сервер Traefik будет обслуживать весь трафик по HTTPS с помощью сертификата Let’s Encrypt.

Требования

  • Сервер Ubuntu 20.04, настроенный с помощью этого мануала.
  • Запущенный хост Docker. В этом вам поможет мануал Установка и использование Docker в Ubuntu 20.04.
  • Docker Compose (установить приложение можно с помощью этого мануала).
  • Домен и три записи А: db-admin.your_domain, blog.your_domain and monitor.your_domain. Каждая запись должна указывать на IP-адрес хоста Docker. В мануале используется условное обозначение your_domain, которое вы должны заменить вашим доменом.

1: Настройка и запуск Traefik

Проект Traefik предоставляет официальный образ Docker, который поможет быстро запустить Traefik в контейнере Docker.

Но прежде чем запустить такой контейнер, нужно создать конфигурационный файл и зашифрованный пароль, чтобы получить доступ к панели мониторинга.

Используйте утилиту htpasswd, чтобы создать зашифрованный пароль. Установите утилиту. Она входит в пакет apache2-utils.

sudo apt-get install apache2-utils

Затем с помощью htpasswd создайте пароль. Замените secure_password в команде паролем, который вы хотите использовать для администратора Traefik:

htpasswd -nb admin secure_password

Вывод утилиты будет иметь такой вид:

admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/

Он используется в конфигурационном файле Traefic для настройки базовой аутентификации HTTP в панели мониторинга Traefik. Скопируйте всю строку, чтобы затем вставить ее в файл.

Чтобы настроить сервер Traefik, создайте файлы traefik.toml и traefik_dynamic.toml в формате TOML. TOML – это стандартизированный язык конфигурации (аналогичный INI-файлам). Эти конфигурационные файлы позволяют настроить сервер Traefik и разные дополнительные интеграции, или провайдеры. В данном мануале мы используем три доступных провайдера Traefik: api, docker и acme, который нужен для поддержки TLS сертификатов Let’s Encrypt.

Откройте файл traefik.toml:

nano traefik.toml

В раздел entryPoints добавьте две именованные точки входа, чтобы открыть доступ к портам http 80 и https 443, доступ к которым по умолчанию будет у всех бэкендов. Назовем эти точки web и websecure соответственно.

[entryPoints] [entryPoints.web] address = ":80"
[entryPoints.web.http.redirections.entryPoint] to = "websecure"
scheme = "https"
[entryPoints.websecure] address = ":443"

Обратите внимание: вы также автоматически перенаправляете трафик на TLS.

Затем настройте провайдер api, который дает доступ к интерфейсу дашборда мониторинга. Вам нужно только добавить заголовок [api], после этого дашборд включится по умолчанию.

...
[api] dashboard = true

Для полной защиты веб-запросов мы будем использовать Let’s Encrypt, чтобы создать валидные сертификаты TLS. Traefik v2 поддерживает Let’s Encrypt «из коробки», и вы можете настроить его, создав резольвер сертификатов типа acme.

Давайте настроим его сейчас:

...
[certificatesResolvers.lets-encrypt.acme] email = "your_email@your_domain"
storage = "acme.json"
[certificatesResolvers.lets-encrypt.acme.tlsChallenge]

Этот раздел называется acme. ACME – это протокол, с помощью которого сервер взаимодействует с Let’s Encrypt для управления сертификатами. Чтобы Traefik создавал сертификаты для хостов, укажите в строке email свой адрес электронной почты. Затем нужно указать, что хранить информацию Let’s Encrypt нужно в файле JSON, acme.json.

Раздел acme.tlsChallenge позволяет определить, как Let’s Encrypt может подтверждать сертификаты. Мы настроим его для обслуживания фала как части задачи для порта 443.

Теперь нужно настроить Traefik на взаимодействие с Docker.

Добавьте следующие конфигурации в файл:

...
[providers.docker] watch = true
network = "web"

Провайдер docker включает Traefik в качестве прокси-сервера для контейнеров Docker. Он будет следить (на что указывает строка watch) за новыми контейнерами в сети web, которую мы скоро создадим.

В окончательной конфигурации мы также используем провайдер file. В Traefik v2 нельзя смешивать и связывать статические и динамические конфигурации. Потому в файле traefik.toml мы определяем только статические конфигурации, а динамические конфигурации будут храниться в другом файле, traefik_dynamic.toml. Здесь мы используем провайдер file, чтобы сообщить Traefik, что он должен читать динамические конфигурации из другого файла.

Добавьте следующий раздел:

[providers.file] filename = "traefik_dynamic.toml"

На этом этапе файл traefik.toml должен выглядеть так:

[entryPoints] [entryPoints.web] address = ":80"
[entryPoints.web.http.redirections.entryPoint] to = "websecure"
scheme = "https"
[entryPoints.websecure] address = ":443"
[api] dashboard = true
[certificatesResolvers.lets-encrypt.acme] email = "your_email@your_domain"
storage = "acme.json"
[certificatesResolvers.lets-encrypt.acme.tlsChallenge] [providers.docker] watch = true
network = "web"
[providers.file] filename = "traefik_dynamic.toml"

Сохраните и закройте файл.

Теперь создайте traefik_dynamic.toml.

Значения динамической конфигурации, которые нужно сохранить в отдельном файле, будут определять поведение промежуточного ПО и маршрутизаторов. Чтобы защитить свой дашборд паролем, необходимо настроить маршрутизатор API и промежуточное ПО для обработки базовой аутентификации HTTP. Начнем с установки промежуточного программного обеспечения.

Промежуточное ПО настраивается отдельно для каждого протокола: если, например, вы работаете с HTTP, вы указываете его как раздел, привязанный к http.middlewares. Затем идет имя промежуточного программного обеспечения (чтобы позже на него было удобно ссылаться), а затем – его тип (в данном случае это будет basicAuth). Назовем это промежуточное ПО simpleAuth.

Откройте новый файл traefik_dynamic.toml:

nano traefik_dynamic.toml

Поместите в него такой код:

[http.middlewares.simpleAuth.basicAuth] users = [
"admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
]

Чтобы настроить маршрутизатор для api, вам снова нужно привязать имя протокола, но вместо http.middlewares вы будете использовать http.routers, за которым следует имя маршрутизатора. В этом случае api предоставляет собственный именованный маршрутизатор, который можно настроить с помощью раздела [http.routers.api]. мы также настроим домен, который будем использовать с дашбордом. Для этого нужно установить ключ rule и задать хост, точку входа для использования сети websecure и промежуточное ПО для simpleAuth.

Добавьте следующие конфигурации в файл:

...
[http.routers.api] rule = "Host(`monitor.your_domain`)"
entrypoints = ["websecure"] middlewares = ["simpleAuth"] service = "api@internal"
[http.routers.api.tls] certResolver = "lets-encrypt"

Точка входа сети web обрабатывает порт 80, а точка входа в сеть websecure использует порт 443 для поддержки TLS/SSL. Весь трафик, поступающий на порт 80, автоматически перенаправляется на точку входа в websecure, чтобы обеспечить безопасные соединения для всех запросов.

Обратите внимание, последние три строки здесь настраивают сервис, включают tls и устанавливают в certResolver to “lets-encrypt”. Сервисы позволяют определить, где запрос будет полностью обработан. Сервис api@internal – это встроенный сервис, который работает за настроенным вами API. Как и маршрутизаторы и промежуточное программное обеспечение, сервисы можно настраивать в текущем файле, но для достижения желаемого результата в нашем случае этого делать не нужно.

Готовый файл traefik_dynamic.toml будет выглядеть так:

[http.middlewares.simpleAuth.basicAuth] users = [
"admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
] [http.routers.api] rule = "Host(`monitor.your_domain`)"
entrypoints = ["websecure"] middlewares = ["simpleAuth"] service = "api@internal"
[http.routers.api.tls] certResolver = "lets-encrypt"

Сохраните и закройте файл.

Теперь можно запустить Traefik.

2: Запуск контейнера Traefik

Сейчас мы создадим сеть Docker для поддержки взаимодействия прокси-сервера и контейнеров. Такая сеть необходима, потому что ее можно использовать для работы с приложениями, запущенными в Docker Compose. Мы назовем такую сеть web.

docker network create web

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

Затем создайте пустой файл, в котором будут храниться данные о шифровании Let’s Encrypt. Поместите его в контейнер, чтобы Traefik мог его использовать.

touch acme.json

Затем заблокируйте доступ к файлу acme.json, чтобы только пользователь root мог читать и изменять его. Если вы этого не сделаете, Traefik не сможет использовать этот файл.

chmod 600 acme.json

Когда файл будет передан в Docker, внутри контейнера ему автоматически присвоят владельца root.

Теперь создайте контейнер Traefik с помощью команды:

docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $PWD/traefik.toml:/traefik.toml \
-v $PWD/traefik_dynamic.toml:/traefik_dynamic.toml \
-v $PWD/acme.json:/acme.json \
-p 80:80 \
-p 443:443 \
--network web \
--name traefik \
traefik:v2.2

Давайте разделим команду на части и рассмотрим ее подробно:

  • Флаг –d запускает контейнер как демон, в фоновом режиме. Затем команда добавляет в контейнер файл docker.sock, благодаря чему процесс Traefik может прослушивать изменения в контейнерах. Также в контейнер можно поместить файлы traefik.toml, traefik_dynamic.toml и acme.json.
  • После этого порты 80 и 443 хоста Docker подключаются к таким же портам в контейнере Traefik. Теперь Traefik получает все запросы HTTP и HTTPS.
  • В качестве сети контейнера нужно указать web. Контейнер называется traefik.
  • Для создания контейнера используется образ traefik:v2.2.

ENTRYPOINT образа Docker – это команда, которая запускается всегда, когда контейнер создается из образа. В этом случае она представляет собой бинарный файл traefik внутри контейнера. Дополнительные аргументы этой команде можно передать при запуске контейнера, но все необходимые данные мы указали ранее в файле traefik.toml.

После запуска контейнера у вас будет дашборд, с помощью которого можно просмотреть состояние контейнеров. Вы также можете использовать эту панель для визуализации интерфейсов и бэкэндов, которые зарегистрировал Traefik. Откройте панель мониторинга в браузере:

https://monitor.your_domain/dashboard/

Вам будет предложено ввести имя и пароль администратора, и пароль (имя – admin, пароль – строка, которую вы создали в разделе 1).

После аутентификации на экране появится дашборд.

Пока что на дашборде не так много данных. Оставьте это окно открытым, и вы увидите, что содержимое дашборда изменится, когда вы добавите контейнеры для Traefik.

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

3: Добавление контейнеров для Traefik

Контейнер Traefik запущен и готов обслуживать другие контейнеры приложений. Добавьте следующие контейнеры:

  1. Блог, запущенный с помощью официального образа WordPress.
  2. Сервер управления базами данных на основе официального образа Adminer.

Управлять этими приложениями можно с помощью Docker Compose, используя файл docker-compose.yml:

nano docker-compose.yml

Укажите в файле версии и сеть:

version: "3"
networks:
web:
external: true
internal:
external: false

Версия 3 Docker Compose – это новейшая версия формата файла Compose.

Чтобы сервер Traefik мог опознать приложения, они должны входить в одну сеть. Поскольку используемая сеть создана вручную, нужно указать ее имя (web) и присвоить строке external значение true. Затем нужно определить другую сеть, чтобы связать эти контейнеры с контейнером базы данных, который не будет обслуживаться через контейнер Traefik. Эта внутренняя сеть будет называться internal.

Затем нужно определить все сервисы по очереди. Давайте начнем с контейнера blog, который основан на официальном образе WordPress. Добавьте в файл такую конфигурацию:

...
services:
blog:
image: wordpress:4.9.8-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.http.routers.blog.rule=Host(`blog.your_domain`)
- traefik.http.routers.blog.tls=true
- traefik.http.routers.blog.tls.certresolver=lets-encrypt
- traefik.port=80
networks:
- internal
- web
depends_on:
- mysql

Параметр environment позволяет указать переменные среды, которые будут установлены внутри контейнера. Если значение WORDPRESS_DB_PASSWORD не установлено, Docker Compose будет извлекать его из оболочки и передавать при создании контейнера. Определить эту переменную среды можно в оболочке перед запуском контейнеров – при этом пароли не попадут в конфигурационный файл.

В разделе labels указываются значения для Traefik. Метки Docker сами по себе ничего не делают, но Traefik читает их и понимает, как обращаться с контейнерами. Каждая метка выполняет такие действия:

  • traefik.http.routers.adminer.rule=Host(`blog.your_domain`) создает новый маршрутизатор для контейнера и затем определяет правило маршрутизации, которое проверяет, адресован ли запрос данному контейнеру.
  • traefik.routers.custom_name.tls=true указывает, что данный маршрутизатор должен использовать TLS.
  • traefik.routers.custom_name.tls.certResolver=lets-encrypt указывает, что для этого маршрутизатора следует использовать созданный вами ранее резольвер сертификатов, let’s-encrypt.
  • traefik.port задает открытый порт, который Traefik должен использовать для маршрутизации трафика в этот контейнер.

При такой конфигурации весь трафик, отправленный на порт 80 или 443 хоста Docker, будет перенаправлен в контейнер blog.

Этот контейнер принадлежит двум различным сетям, чтобы Traefik мог найти его через сеть web и связываться с контейнером базы данных через сеть internal.

Параметр depends_on помогает Docker Compose понять, что этот контейнер нужно запускать после запуска его зависимостей. Поскольку для работы WordPress необходима рабочая БД, контейнер mysql запускается раньше, чем контейнер blog.

Теперь настройте сервис MySQL:

services:
...
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD:
networks:
- internal
labels:
- traefik.enable=false

Для создания этого контейнера используется официальный образ MySQL 5.7. Обратите внимание: параметру environment снова не присвоено никакого значения. Для переменных MYSQL_ROOT_PASSWORD и WORDPRESS_DB_PASSWORD необходимо установить одинаковое значение, чтобы контейнер WordPress мог связываться с MySQL. Контейнер mysql не должен взаимодействовать с Traefik или с внешним миром, потому он принадлежит только сети internal. Поскольку Traefik имеет доступ к сокету Docker, процесс по-прежнему будет открывать маршрутизатор контейнера mysql по умолчанию. Поэтому нужно добавить метку traefik.enable=false, чтобы Traefik не смог сделать этот контейнер доступным.

Теперь нужно добавить параметры контейнера Adminer:

services:
...
adminer:
image: adminer:4.6.3-standalone
labels:
- traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
- traefik.http.routers.adminer.tls=true
- traefik.http.routers.adminer.tls.certresolver=lets-encrypt
- traefik.port=8080
networks:
- internal
- web
depends_on:
- mysql

Этот контейнер основан на официальном образе Adminer. Параметры network и depends_on совпадают с этими же параметрами контейнера blog.

Строка traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`) позволяет Traefik проверить запрошенный хост. Если он соответствует шаблону db-admin.your_domain, Traefik направит трафик в контейнер adminer через порт 8080.

В результате файл docker-compose.yml  будет выглядеть так:

version: "3"
networks:
web:
external: true
internal:
external: false
services:
blog:
image: wordpress:4.9.8-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.http.routers.blog.rule=Host(`blog.your_domain`)
- traefik.http.routers.blog.tls=true
- traefik.http.routers.blog.tls.certresolver=lets-encrypt
- traefik.port=80
networks:
- internal
- web
depends_on:
- mysql
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD:
networks:
- internal
labels:
- traefik.enable=false
adminer:
image: adminer:4.6.3-standalone
labels:
labels:
- traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
- traefik.http.routers.adminer.tls=true
- traefik.http.routers.adminer.tls.certresolver=lets-encrypt
- traefik.port=8080
networks:
- internal
- web
depends_on:
- mysql

Сохраните и закройте файл.

Прежде чем запустить контейнеры, нужно задать значения переменных WORDPRESS_DB_PASSWORD и MYSQL_ROOT_PASSWORD.

export WORDPRESS_DB_PASSWORD=secure_database_password
export MYSQL_ROOT_PASSWORD=secure_database_password

Вместо secure_database_password укажите надежный пароль БД. В WORDPRESS_DB_PASSWORD и MYSQL_ROOT_PASSWORD нужно использовать один и тот же пароль.

Теперь запустите контейнеры:

docker-compose up -d

Снова откройте дашборд Traefik. Вы увидите, что в нем появились разделы backend и frontend, а в них – новые серверы.

Если вы изучите раздел Routers, вы найдете маршрутизаторы adminer и blog, настроенные с поддержкой TLS.

Откройте в браузере blog.your_domain (где your_domain – ваш домен). Соединение будет перенаправлено на зашифрованный порт 443. Теперь можно закончить установку WordPress.

После этого откройте в браузере db-admin.your_domain. Контейнер mysql не доступен в интернете, но контейнер adminer имеет доступ к нему через внутреннюю сеть (internal).

На экране появится форма входа Adminer. Укажите mysql в поле Server, используйте имя пользователя root, в поле пароля введите значение переменной MYSQL_ROOT_PASSWORD. Поле Database оставьте пустым. Нажмите Login.

После этого вы получите доступ к интерфейсу Adminer.

Оба сайта теперь работают. Чтобы получить доступ к дашборду, введите monitor.your_domain.

Заключение

Теперь сервер Traefik v2 проксирует запросы в контейнеры приложений Docker.

Traefik позволяет легко настраивать большое количество сервисов и устраняет необходимость перезапускать контейнер traefik при добавлении новых приложений в контейнер traefik. Traefik незамедлительно получает все сведения об изменениях через файл сокета Docker.

Чтобы узнать больше о возможностях Traefik v2, читайте его официальную документацию.

Tags: , , , , , , ,

Добавить комментарий