Ingress контроллер в Kubernetes работает как обратный прокси-сервер, который обрабатывает входящие сетевые запросы к приложениям, работающим на кластере Kubernetes. Он обеспечивает контроль доступа к приложениям и маршрутизацию трафика между ними. Он обрабатывает запросы, поступающие из внешней сети (например, из Интернета или WAN сегмента сети), и направляет их на определенные внутренние сервисы, основываясь на правилах, определенных в конфигурации ingress. Эти правила могут включать определения маршрутов, SSL настройки, метрики и многое другое.

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

На более низком уровне Ingress-контроллеры обычно используют прокси-серверы, такие как Nginx или Envoy, для обработки входящих сетевых подключений и перенаправления трафика на бэкенд. Важно отметить, что Ingress-контроллеры должны быть запущены на каждом узле, где развёрнуты приложения, к которым нужно получить доступ извне кластера. Это позволяет контроллеру обрабатывать входящие сетевые подключения на каждом узле и направлять трафик на соответствующие приложения.

Основные задачи Ingress контроллера

  1. Прослушивание трафика: Ingress Controller обычно прослушивает определенный сетевой порт (например, порт 80 для HTTP или порт 443 для HTTPS) для получения входящего трафика от внешних клиентов. Ingress-контроллеры поддерживают различные сетевые протоколы, такие как TCP, UDP, HTTP и HTTPS. Выбор протокола зависит от типа обрабатываемого трафика.

  2. Балансировка нагрузки: когда запрос поступает на ingress контроллер, он выполняет балансировку нагрузки для распределения входящего трафика между несколькими сервисами бэкенда. Это часто делается с использованием циклического перебора (round-robin) или других алгоритмов балансировки нагрузки.

  3. Сопоставление хоста и пути: Ingress Controller анализирует заголовки запроса и проверяет хост и путь, чтобы определить, какая сервис бэкенда должен обрабатывать запрос. Он сравнивает запрошенный хост и путь с правилами, определенными в ресурсе Ingress, чтобы найти совпадение.

  4. Обратный прокси-сервер: как только ingress контроллер идентифицирует сервис на бэкенде для обработки запроса, он действует как обратный прокси-сервер. Он пересылает запрос соответствующему сервису, устанавливая новое сетевое соединение.

  5. Перезапись запроса. Контроллеры входящего трафика могут выполнять перезапись запроса (rewrite), изменяя заголовки запроса или URL-адрес перед его пересылкой во внутренний сервис. Это может быть полезно для таких сценариев, как перенаправление URL-адресов или маршрутизация на основе пути URI.

  6. Терминирование TLS: если Ingress Controller настроен на обработку HTTPS-трафика, он выполняет терминирование TLS. Это включает в себя расшифровку входящего трафика, зашифрованного TLS, и его пересылку во внутреннюю службу по незашифрованному соединению.

  7. Проксирование ответа: после того, как сервис обработает запрос и сгенерирует ответ, ingress контроллер снова действует как обратный прокси-сервер. Он получает ответ от сервиса и пересылает его обратно клиенту.

  8. Управление соединениями: Ingress Controller управляет жизненным циклом сетевых подключений. Он устанавливает и поддерживает соединения с серверными службами, контролирует их работоспособность и управляет пулом соединений для оптимизации производительности. Порой тонкая настройка важна для поддержания большого числа соединений.

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

  10. Ведение журнала и мониторинг. Ingress-контроллеры часто предоставляют возможности ведения журнала и мониторинга для отслеживания входящих запросов, измерения производительности и устранения неполадок. Эта информация может оказаться неоценимой для оперативной аналитики и отладки. В логах приложения по умолчанию мы увидим IP адрес самого ingress контроллера, так как именно он устанавливает соединение с бэкендом, однако такое поведение можно изменить.

Deep dive в ingress-nginx controller

Сразу оговорюсь, что существует два похожих контроллера: ingress-nginx и Nginx ingress. Они созданы разными разными компаниями и имеют разную реализацию, хоть и похожи. Nginx ingress создан компанией nginx, которая сейчас является частью компании F5.

Основной задачей ingress-nginx является сборка файла конфигурации nginx (nginx.conf), который и будет содержать правила маршрутизации трафика. Основным следствием этого является необходимость перезагрузки Nginx после любого изменения файла конфигурации. Однако важно отметить, что мы не перезагружаем Nginx при изменениях, которые влияют только на конфигурацию upstream (т. е. конечные точки изменяются при развертывании приложения). Для этого используется пода lua-nginx .

В основе ingress контроллера лежит стандартная работа контроллера репликации (подробно о контроллерах я рассказывал в другой статье). Обычно контроллер репликации Kubernetes использует шаблон цикла синхронизации, чтобы проверить, актуально ли желаемое состояние контроллера (desired state) или требуется изменение. Для этого нам необходимо построить модель, используя разные объекты из кластера, в частности Ingresses, Services, Endpoints, Secrets и Configmaps, чтобы сгенерировать файл конфигурации на определенный момент времени, отражающий состояние кластера.

Чтобы получить этот объект из кластера, мы используем Kubernetes Informers, в частности, FilteredSharedInformer. Эти информеры позволяют реагировать на изменения, используя колбэки на отдельные изменения при добавлении, изменении или удалении нового объекта. К сожалению, невозможно узнать, повлияет ли конкретное изменение на окончательный файл конфигурации. Поэтому при каждом изменении нам приходится перестраивать новую конфигурацию с нуля на основе состояния кластера и сравнивать ее с текущей моделью. Если новая конфигурация равна текущей, то новый файл конфигурации NGINX не создается и перезагрузка не требуется. В противном случае мы проверяем, касается ли разница в конфигурации только конечных точек (endpoints, то, куда будет роутиться трафик). Если это так, мы затем отправляем новый список конечных точек обработчику Lua, работающему внутри Nginx, с помощью запроса HTTP POST и снова избегаем создания новой конфигурации NGINX и перезагрузки. Если разница между запущенной и новой моделью касается не только конечных точек, мы создаем новую конфигурацию NGINX на основе новой модели, заменяем текущую модель и перезапускаем сервис.

Построение модели конфигурации

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

Важно понимать, что любое изменение в кластере может генерировать события, которые информер отправит на контроллер и является одной из причин добавления в очередь. Напомню, что всякий раз, когда kubernetes ресурс изменяется, обработчик событий ресурса помещает ключ в Workqueue. Источником изменений как раз служат ресурсы типа kind: Ingress, содержащих правила маршрутизации.

Для построения модели конфигурации выполняются следующие операции анализа:

  • Упорядочивание правил входящего трафика по CreationTimestampполям, т. е. сначала старые правила.
  • Если один и тот же путь для одного и того же хоста определен более чем в одном Ingress, побеждает самое старое правило.
  • Если более одного Ingress содержит раздел TLS для одного и того же хоста, побеждает самое старое правило.
  • Если несколько Ingress определяют аннотацию, которая влияет на конфигурацию блока Server, побеждает самое старое правило.
  • Создается список виртуальных серверов NGINX (для каждого имени хоста)
  • Создается список восходящих потоков NGINX (upstream).
  • Если несколько Ingress определяют разные пути для одного и того же хоста, ingress контроллер объединит определения.
  • Аннотации применяются ко всем путям в Ingress.
  • Несколько Ingress могут определять разные аннотации. Эти определения не являются общими для всех Ingress.

В некоторых случаях требуется перезагрузка сервиса:

  • Создан новый Ingress ресурс.
  • Раздел TLS добавлен к существующему Ingress.
  • Изменение аннотаций Ingress, которое влияет не только на конфигурацию восходящего потока. Например load-balance, аннотация не требует перезагрузки.
  • Путь добавляется/удаляется из Ingress.
  • Ресурсы Ingress, Service, Secret были удалены.
  • Доступен какой-то отсутствующий объект, на который ссылаются, из Ingress, например служба или секрет.
  • Секрет обновлен.

Поскольку контроллер работает с использованием  цикла синхронизации, он применяет конфигурацию ко всем подходящим объектам. Если некоторые объекты Ingress имеют неправильную конфигурацию, например синтаксическую ошибку в аннотации nginx.ingress.kubernetes.io/configuration-snippet, сгенерированная конфигурация становится недействительной, не перезагружается и, следовательно, Ingress больше не будут учитываться.

Чтобы предотвратить возникновение такой ситуации, контроллер Ingress-Nginx дополнительно предоставляет admission controller с вебхуком, чтобы проверить валидность ingress объектов. Этот вебхук добавляет входящие ingress объекты в список ингресов, генерирует конфигурацию и вызывает nginx, чтобы убедиться, что в конфигурации нет синтаксических ошибок.

Ingress Controller Pod

Давайте посмотрим, из чего состоит под ингрес контроллера (IC) на примере Nginx Ingress.

Под IC состоит из одного контейнера, который, в свою очередь, включает в себя следующее:

  1. Процесс IC, который настраивает NGINX в соответствии с Ingress правилами и другими ресурсами, созданными в кластере.
  2. Главный процесс NGINX, который управляет рабочими процессами NGINX.
  3. Рабочие процессы NGINX (воркеры), которые обрабатывают клиентский трафик и балансируют нагрузку на серверные приложения.

Контроллер опирается на следующие типы ресурсов, которые есть в кластере:

  • Layer 7 конфигурация балансировщиков нагрузки:
    • Ingresses
    • VirtualServers (CR)
    • VirtualServerRoutes (CR)
  • Layer 7 политики:
    • Policies (CR)
  • Layer 4 конфигурация балансировщиков нагрузки:
    • TransportServers (CR)
  • Обнаружение сервисов:
    • Services
    • Endpoints
    • Pods
  • Настройка секретов:
    • Secrets
  • Общая конфигурация:
    • ConfigMap
    • GlobalConfiguration (CR)

CR — так обозначены кастомные ресурсы, которые доступны после установки их определений (CRD) в кластер.

Ниже представлена архитектурная диаграмма, показывающая, как эти процессы взаимодействуют друг с другом и с некоторыми внешними процессами/сущностями:

Под ingress контроллера

Опишем соединения, которые устанавливаются процессами контроллера с типами протоколов и данных в скобках.

  1. (HTTP) Prometheus получает метрики IC и NGINX через конечную точку HTTP, которую предоставляет IC. Значение по умолчанию: 9113/metrics.
  2. (HTTPS) IC считывает API Kubernetes, чтобы получить последние версии ресурсов в кластере, и записывает в API, чтобы обновлять статусы обрабатываемых ресурсов и отправлять события.
  3. (HTTP) Kubelet проверяет готовность пода IC (по умолчанию: 8081/nginx-ready), чтобы определить готовность пода IC.
  4. (Файловый ввод-вывод) При запуске контроллер считывает шаблоны конфигурации, необходимые для генерации конфигурации, из файловой системы. Шаблоны расположены в каталоге / контейнера и имеют расширение .tmpl.
  5. (Файловый ввод-вывод) IC записывает журналы в свои stdout и stderr, которые собираются средой выполнения контейнера (runtime).
  6. (Файловый ввод-вывод) IC генерирует конфигурацию NGINX на основе ресурсов, созданных в кластере (список типов ресурсов смотри выше) и записывает ее в файловую систему в папке /etc/nginx. Файлы конфигурации имеют расширение .conf.
  7. (Файловый ввод-вывод) IC записывает сертификаты TLS и ключи из любых секретов TLS, на которые ссылаются входные и другие ресурсы, в файловую систему.
  8. (HTTP) IC извлекает метрики NGINX через UNIX-сокет unix:/var/lib/nginx/nginx-status.sock и преобразует их в формат Prometheus, используемый в № 1.
  9. (HTTP) Чтобы считать перезагрузку конфигурации успешной, IC гарантирует, что хотя бы один рабочий NGINX имеет новую конфигурацию. Для этого IC проверяет конкретную конечную точку через UNIX-сокет unix:/var/lib/nginx/nginx-config-version.sock.
  10. Чтобы запустить NGINX, контроллер запускает команду nginx, которая запускает мастер NGINX.
  11. (Сигнал) Чтобы перезагрузить NGINX, IC запускает команду nginx -s reload, которая проверяет конфигурацию и отправляет сигнал перезагрузки мастеру NGINX.
  12. (Сигнал) Чтобы завершить работу NGINX, контроллер выполняет команду nginx -s quit, которая отправляет сигнал корректного завершения работы мастеру NGINX.
  13. (Файловый ввод-вывод) Главный сервер NGINX отправляет журналы на свои стандартные потоки вывода и stderr, которые собираются средой выполнения контейнера.
  14. (Файловый ввод-вывод) Мастер NGINX считывает сертификат TLS и ключи, указанные в конфигурации, при запуске или перезагрузке.
  15. (Файловый ввод-вывод) Мастер NGINX считывает файлы конфигурации при запуске или во время перезагрузки.
  16. (Сигнал) Мастер NGINX управляет жизненным циклом рабочих процессов NGINX: он создает воркеры с новой конфигурацией и завершает работу воркеров со старой конфигурацией.
  17. (Файловый ввод-вывод) Воркер NGINX записывает журналы в свои стандартные потоки вывода и stderr, которые собираются средой выполнения контейнера.
  18. (UDP) Воркер NGINX отправляет журналы задержки ответов апстрим сервера HTTP через протокол Syslog через UNIX  сокет /var/lib/nginx/nginx-syslog.sock на контроллер. В свою очередь последний анализирует и преобразует логи в метрики Prometheus.
  19. (HTTP,HTTPS,TCP,UDP) Клиент отправляет и получает трафик от любого из воркеров NGINX через порты 80 и 443, а также любые дополнительные порты, предоставляемые ресурсом GlobalConfiguration.
  20. (HTTP,HTTPS,TCP,UDP) Воркер NGINX отправляет трафик на бэкенды и получает трафик от них.
  21. (HTTP) Администратор может подключиться к NGINX stub_status, используя порт 8080 через воркеров NGINX. Примечание. По умолчанию NGINX разрешает подключения только с localhost.

Создание нового ресурса Ingress

Создание и обработка контроллером нового ресурса Ingress происходит в следующей последовательности:

  1. Пользователь создает новый ресурс Ingress.
  2. Процесс контроллера имеет кэш ресурсов в кластере. Кэш включает только те ресурсы, которые интересуют IC, например Ingress. Кэш синхронизируется с API Kubernetes, отслеживая изменения в ресурсах.
  3. Как только в кэше появляется новый Ingress ресурс, он уведомляет цикл управления об измененном ресурсе.
  4. Цикл управления получает последнюю версию Ingress-ресурса из кэша. Поскольку ресурс Ingress ссылается на другие ресурсы, такие как секреты TLS, цикл управления также получает последние версии всех ресурсов, на которые ссылаются.
  5. Цикл управления генерирует сертификаты и ключи TLS из секретов TLS и записывает их в файловую систему.
  6. Цикл управления генерирует и записывает файлы конфигурации NGINX, соответствующие Ingress ресурсу, и записывает их в файловую систему.
  7. Цикл управления перезагружает NGINX и ожидает успешной перезагрузки NGINX. В рамках перезагрузки:
    • NGINX читает сертификаты и ключи TLS.
    • NGINX читает файлы конфигурации.
    • Цикл управления генерирует событие для Ingress-ресурса и обновляет его статус. Если перезагрузка не удалась, событие включает сообщение об ошибке.

Дополнительная конфигурация через аннотации

Стандартный ресурс Ingress содержит только те поля, которые описаны в Kubernetes API соответствующей версии. Однако, дополнительные настройки контроллеру можно передать через аннотации Ingress ресурса.

Контроллер ingress-nginx имеет аннотации, начинающиеся с nginx.ingress.kubernetes.io, контроллер Nginx ingress использует nginx.org. Полный список аннотаций доступен по ссылкам в документации:

Примеры и наиболее полезные конфигурации аннотаций будут собраны в следующей статье.

Был ли наш пост полезен?

Нажмите на звезду, чтобы оценить мои труды!

Средний рейтинг: 5 / 5. Количество голосов: 2

Пока голосов нет. Проголосуй первым!

Мне жаль, что пост вам не помог 🙁

Позвольте мне исправиться.

Поделитесь, что можно улучшить?

Похожие посты