Руководство для начинающих по настройке Traefik для приложений Rails

Руководство для начинающих по настройке Traefik для приложений Rails

27 февраля 2024 г.

В течение многих лет Nginx использовался по умолчанию в качестве обратного прокси-сервера для приложений Rails. Однако с выпуском Kamal сообщество Rails открыло Traefik как новое решение для обратного прокси.

За 15 лет опыта работы с Rails я создал почти идеальную конфигурацию для Nginx, которая прошла через все мои проекты. С Traefik мне пришлось начинать с нуля.

Введение в Traefik

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

Когда входящий запрос поступает в Traefik, он обслуживается через EntryPoint. Traefik может прослушивать несколько точек входа, и каждая точка входа связана с портом и протоколом (HTTP/HTTPS, TCP, UDP). После получения запроса он передается маршрутизатору.

Маршрутизатор — это правило, которое сообщает Traefik, как обрабатывать запрос. Он может основываться на пути, хосте, заголовках и т. д. Затем маршрутизатор перенаправит запрос в соответствующую службу. Но перед пересылкой запроса он может быть изменен промежуточным программным обеспечением.

Промежуточное программное обеспечение — это часть кода, которая может изменить запрос или ответ до того, как он достигнет службы. Промежуточное программное обеспечение — это место, где вы можете добавить аутентификацию, переписать путь, добавить заголовки и т. д.

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

Traefik Overview

По сравнению с Nginx конфигурация Traefik совершенно другая. Помимо традиционного файла конфигурации (который может быть как в формате YAML, так и в формате TOML), Traefik можно настроить с помощью динамической конфигурации. Это означает, что вы можете настроить Traefik с помощью файла, а также с помощью REST API, метки Docker, аннотации Kubernetes и т. д.

Поскольку Kamal — это инструмент оркестрации Docker, настройка Traefik выполняется с помощью меток Docker. Это означает, что вам не нужно писать файл конфигурации; вместо этого вам следует предоставить метки вашим контейнерам Docker. Метки работают динамически, поэтому для их применения не требуется перезагружать Traefik. В то же время управлять ярлыком Docker может быть довольно сложно, особенно в начале.

Панель мониторинга Traefik

Хорошая новость заключается в том, что Traefik довольно хорошо работает с Kamal прямо из коробки (Kamal предоставляет базовую конфигурацию по умолчанию, которую я покажу позже), и, возможно, вам не нужно будет ничего менять. Однако, если вы хотите посмотреть, как настроен Traefik, вы можете включить веб-панель. .

Для этого откройте конфигурацию Kamal (обычно config/deploy.yml) и добавьте следующие строки.

# config/deploy.yml

traefik:
  args:
    api.dashboard: true
  labels:
    traefik.http.routers.dashboard.servixce: api@internal
    traefik.http.routers.dashboard.rule: "Host(`traefik.onetribe.com`)"
    traefik.http.middlewares.auth.basicauth.users: user:$2y$05$us7dsDg56EJ/qojvhLvy9OEshrzoWjGSKXziBqeiFq3Ehf1pAiGSG
    traefik.http.routers.dashboard.middlewares: auth@docker

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

# config/deploy.production.yml

traefik:
  labels:
    traefik.http.routers.dashboard.rule: "Host(`traefik.onetribe.team`)"
    traefik.http.middlewares.auth.basicauth.users: user-production:$2y$05$us7dsDg56EJ/qojvhLvy9OEshrzoWjGSKXziBqeiFq3Ehf1pAiGSG

# config/deploy.staging.yml

traefik:
  labels:
    traefik.http.routers.dashboard.rule: "Host(`traefik.staging.onetribe.team`)"
    traefik.http.middlewares.auth.basicauth.users: user-staging:$2y$05$us7dsDg56EJ/qojvhLvy9OEshrzoWjGSKXziBqeiFq3Ehf1pAiGSG

Давайте пройдемся построчно в файле config/deploy.yml.

  • В строке 5, api.dashboard: true включает панель мониторинга Traefik, поскольку по умолчанию она отключена.

* В строке 7 я определил маршрутизатор, который будет обслуживать панель мониторинга. Внутренняя служба API Traefik называется api@internal; Я подключил его к маршрутизатору dashboard.

* Затем в строке 9 я определил правило, которое предписывает Traefik обслуживать панель мониторинга в домене traefik.onetribe.team. Правило может основываться на пути, хосте, заголовках и т. д..

* Поскольку я не хочу показывать панель мониторинга общедоступным, я добавил промежуточное программное обеспечение базовой аутентификации в строках 9 и 10. Traefik поддерживает различные методы аутентификации: базовый, дайджест, переслать и т. д. Я использовал базовую аутентификацию, так как ее проще всего настроить.

Пароль можно зашифровать с помощью команды htpasswd, которая является частью набора инструментов Apache. , и это действительно удивительно, как программное обеспечение, которому 20 лет, все еще используется. Чтобы зашифровать пароль для нового пользователя, выполните следующую команду.

htpasswd -nB user

Журнал трафика

Помимо визуализации конфигурации важно иметь хорошее логирование. Большинство моих проектов Kamal используют AWS CloudWatch для ведения журналов, поэтому я настроил Traefik для отправки журналов в CloudWatch. Для этого я добавил следующие строки в файл config/deploy.yml.

logging:
  driver: awslogs
  options:
    awslogs-region: us-east-1
    awslogs-group: application
    awslogs-create-group: true
    tag: "-"

Это позволит настроить ведение журнала для контейнеров вашего приложения. В приведенном выше примере я использовал application в качестве группы журналов; вы можете использовать любое имя, какое захотите. Параметр tag важен; Я использовал имя и идентификатор контейнера, чтобы различать журналы из разных контейнеров. На рисунке ниже показано, как организованы журналы в CloudWatch.

CloudWatch logstreams

Как видите, помимо журналов контейнера приложения, у меня также есть поток журналов Traefik, который включает в себя как журналы ошибок, так и журналы доступа (что не самое лучшее, но так оно и есть). Ведение журнала Traefik можно настроить, передав аргументы в контейнер Traefik. Я предполагаю, что мои запросы на проверку работоспособности выполняются довольно быстро, поэтому я установил минимальную продолжительность 50 мс для фильтрации неважных данных.

traefik:
  args:
    log.format: json
    accesslog: true
    accesslog.format: json
    accesslog.filters.minduration: 50ms

Промежуточное ПО 101

Я уже говорил о промежуточном программном обеспечении ранее в этой статье; давайте посмотрим на них поближе. Промежуточное программное обеспечение — это фрагмент кода, который может изменить запрос или ответ до того, как он достигнет службы. Для защиты панели управления Traefik я использовал базовое промежуточное программное обеспечение для аутентификации.

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

traefik.http.middlewares.<middleware_1>.basicauth.users: username:<encrypted_password>
traefik.http.middlewares.<middleware_2>.ipwhitelist.sourcerange: 127.0.0.1/32
traefik.http.routers.<router_name>.middlewares: <middleware_1>, <middleware_2>, <middleware_3>

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

Камаль добавляет промежуточное ПО по умолчанию к каждому сервису, использующему Traefik. Это важно знать, потому что если вы добавите промежуточное программное обеспечение к маршрутизатору, оно заменит промежуточное программное обеспечение по умолчанию. Если вы хотите добавить промежуточное программное обеспечение к промежуточному программному обеспечению по умолчанию, вам необходимо добавить его в список промежуточного программного обеспечения.

WWW-перенаправление

Перенаправление с домена с www на домен без www — распространенная практика. Важно иметь один домен из соображений SEO и безопасности.

В Nginx я делал это с помощью простой директивы rewrite.

server {
  server_name www.onetribe.team;
  return 301 $scheme://onetribe.team$request_uri;
}

Чтобы сделать это с помощью Traefik, вам необходимо настроить промежуточное ПО RedirectRegex на маршрутизаторе.

servers:
  web:
    hosts:
      - <ip_address>
    labels:
      traefik.http.routers.onetribe-web.middlewares: onetribe-web-www-redirect@docker
      traefik.http.middlewares.onetribe-web-www-redirect.redirectregex.regex: ^http://www.(.*)
      traefik.http.middlewares.onetribe-web-www-redirect.redirectregex.replacement: https://$1

Вы, наверное, заметили, что я использовал схему http:// в регулярном выражении. Почему бы не https://? Во всех моих конфигурациях с Traefik я выполняю завершение HTTPS на балансировщике нагрузки до того, как запрос достигнет Traefik. В Rails 7.1 появился config.assume_ssl опция для обработки таких конфигураций.< /п>

Сжать

Почти все конфигурации Nginx, которые я видел, имели директиву gzip. Сжатие ответов для экономии трафика и ускорения работы веб-сайта является хорошей практикой. В Digital Ocean есть отличное руководство, объясняющее, как работает HTTP-сжатие и как его настроить с помощью Nginx.

server {
  # ...
  gzip on;
  gzip_comp_level 2;
  gzip_min_length 1000;
  gzip_proxied any;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_vary on;
  # ...
}

У Traefik есть промежуточное программное обеспечение для сжатия, которое можно использовать для достижения того же результата.

servers:
  web:
    hosts:
      - <ip_address>
    labels:
      traefik.http.routers.onetribe-web.middlewares: onetribe-web-compress@docker
      traefik.http.middlewares.onetribe-web-compress.compress: true

Полный пример

Приведенный ниже пример сочетает в себе два промежуточных программного обеспечения, определенных выше, и промежуточное программное обеспечение, которое добавляется по умолчанию с помощью Kamal – Retry. Промежуточное программное обеспечение Retry повторно отправляет запросы заданное количество раз на внутренний сервер, если тот сервер не отвечает.

servers:
  web:
    hosts:
      - <ip_address>
    labels:
      traefik.http.routers.onetribe-web.middlewares: onetribe-web-www-redirect@docker,onetribe-web-retry@docker,onetribe-web-compress@docker
      traefik.http.routers.onetribe-web.rule: PathPrefix(`/`)
      traefik.http.services.onetribe-web.loadbalancer.server.scheme: http

      traefik.http.middlewares.onetribe-web-www-redirect.redirectregex.regex: ^http://www.(.*)
      traefik.http.middlewares.onetribe-web-www-redirect.redirectregex.replacement: https://$1

      traefik.http.middlewares.onetribe-web-compress.compress: true

      traefik.http.middlewares.onetribe-web-retry.retry.attempts: 5
      traefik.http.middlewares.onetribe-web-retry.retry.initialinterval: 500ms

Обработка ресурсов Rails

Наконец, речь идет не о Traefik, а о конфигурации Rails. В Nginx меня обычно не заботило, как обрабатываются мои CSS, JS и другие статические ресурсы; Nginx сделал это за меня. Все необходимые заголовки (например, сжатие, о котором мы говорили выше, и управление кешем) были добавлены Nginx.

Traefik — это не веб-сервер; это пограничный маршрутизатор, поэтому он не обрабатывает статические ресурсы. Это означает, что вам необходимо настроить Rails для правильной обработки статических ресурсов.

Стоп, обработка статических файлов в Rails медленная и неэффективная. И вы правы, или, по крайней мере, вы были правы. Современные версии Puma хорошо обрабатывают статические ресурсы. Кроме того, в 2024 году мы обычно используем облачное хранилище, такое как AWS S3, для обработки пользовательских загрузок, поэтому Rails будет обслуживать только файлы CSS и JS, что не имеет большого значения для Puma.

В моем файле config/environments/production.rb я закончил что-то вроде этого.

  # config/environments/production.rb
  # ...

  config.public_file_server.enabled = true
  config.public_file_server.headers = {
    "Cache-Control" => "public, max-age=#{30.days.to_i}, must-revalidate"
  }
Заголовок

Cache-Control важен; он сообщает браузеру, как долго ему следует кэшировать файл. В этом примере я установил его на 30 дней. Must-revalidate сообщает браузеру о необходимости повторной проверки файла после истечения срока действия кэша.

При таких настройках Rails будет обслуживать статические файлы только один раз для каждого клиента. Если вы считаете, что этого недостаточно, вы можете использовать CDN, например Cloudflare или AWS CloudFront, для кэширования ответов от Rails и значительно снизить нагрузку на ваш сервер.

Заключение

Как это обычно бывает с новыми технологиями, требуется время, чтобы к ним привыкнуть. Траефик не является исключением. Мне потребовалось некоторое время, чтобы понять, как это работает и как это настроить. При этом я вижу преимущества использования Traefik перед Nginx с Rails — главное из них, конечно же, поддержка Docker из коробки.

Я считаю, что это была основная причина, по которой Basecamp решил выбрать Traefik.

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE