Проблемы взаимодействия разработчиков с облачными инфраструктурами на базе Kubernetes в тестовых средах
Фомин Д.С., Бальзамов А.В., Савкина А.В., Федосин С.А.
Национальный исследовательский Мордовский государственный университет имени Н.П. Огарева, Саранск, Россия
Аннотация: Актуальность и цели. Объектом исследования являются проблемы, возникающие во время взаимодействия разработчиков с облачными инфраструктурами. Предметом исследования являются методы обеспечения корректной работы облачных инфраструктур с Kubernetes в тестовых средах. Цель работы — поиск оптимального метода решения проблем непосредственного сетевого доступа к контейнерам Kubernetes и взаимодействия с его нодами кластера извне. Материалы и методы. Исследования проводились в области архитектурных решений и DevOps при построении высоконагруженных систем с использованием инструментов для построения виртуального DNS и для упрощенного взаимодействия с нодами кластера. Результаты. Проведен анализ проблем, возникающих при работе с кластерами Kubernetes в тестовых средах и предложены методы решения рассмотренных проблем. Выводы. Предложенные подходы позволяют использовать дополнительные инструменты для работы с тестовыми и рабочими кластерами Kubernetes, что помогает снизить сложность взаимодействия разработчиков с ними и повысить скорость развертывания и масштабируемость. Кроме того, описанные методы позволяют упростить администрирование крупных сетей.
Ключевые слова: дистрибутив, система, контейнеры, безопасность, приложение, Kubernetes, облачные инфраструктуры, тестовые среды.
Введение
Современные онлайн-сервисы и веб-приложения представляют собой большой комплекс разнообразных сервисов, которые работают как вместе, так и независимо друг от друга. Сервисы могут выступать в разных ролях, например: брокеры сообщений, сервисы доступа к базам данных, сервисы государственного межведомственного взаимодействия или сервисы работы с криптографией. Все перечисленные сервисы необходимо поддерживать в актуальном и рабочем состоянии в любой момент времени. Средний стек сервисов одного программного продукта может включать от 50 до 100 экземпляров. В связи с этим управление, модернизация и администрирование в равной степени осложнены. Для решения указанной проблемы используются системы контейнеризации Docker и оркестрации Kubernetes.
При работе с контейнерами на платформе оркестрации Kubernetes могут возникать проблемы разного рода. Самыми важными из них при взаимодействии с облачными инфраструктурами во время тестирования и разработки являются непосредственное сетевое обращение к кластеру и обновление (развертывание) master (управляющие) и worker (обычные, рабочие) нод кластера.
Для поддержания производительности стека контейнеров на достаточном уровне используются кластеры с множеством серверных машин с виртуализацией. Если необходимо обновить программное обеспечение, установленное на машинах, нужно будет подключаться к каждой из них, что делает процесс затратным как по времени, так и по человеческим ресурсам.
Во всех виртуальных средах, построенных на платформе Kubernetes, используется собственная сетевая инфраструктура, которая накладывает ограничения и создает неудобства как для разработки программного обеспечения, так и для его работы в продуктивном контуре. Основная проблема заключается в том, что сетевая инфраструктура Kubernetes для разработчиков программного обеспечения слишком сложна и затратна по времени на каждый цикл тестирования, так как она не предполагает никакого внешнего сетевого взаимодействия.
При изучении указанных проблем были определены методы их решения для упрощения дальнейшей работы с кластером.
Проблема взаимодействия с нодами кластера Kubernetes
Одна из проблем взаимодействия разработчиков с облачными инфраструктурами на базе Kubernetes в тестовых средах возникает в процессе развертывания или тестирования приложения, когда производится стартовая настройка кластера Kubernetes. Данный процесс включает в себя создание и настройку рабочих станций под ноды кластера. Главной проблемой на этом этапе работы является трудоемкость, т.е. время, затрачиваемое на настройку каждой машины отдельно. Указанная проблема актуальна и при дальнейшей технической поддержке кластера, так как его нодам периодически требуется обновление либо добавление компонентов кластера Kubernetes.
Самым эффективным способом решения указанной проблемы является использование программного обеспечения Ansible — системы управления конфигурациями, которая применяется для автоматизации настройки и развертывания программного обеспечения [1]. Основной операционной системой, на которой используется Ansible, является Linux. В этом случае связь нод кластера с хостовой машиной производится по сетевому протоколу SSH, что упрощает доступ к командам администратора без дополнительных настроек.
Для использования Ansible на каждой машине, на которой предположительно будет располагаться нода кластера, должны быть установлены SSH и Python [2].
Следующим шагом будет копирование открытого SSH-ключа с хостовой машины на рабочие. После переноса открытых ключей можно написать первый тестовый Playbook и заполнить файл hosts. Файл hosts содержит описание адресов и данных машин, с которыми Ansible будет взаимодействовать.
Рисунок 1 – Файл hosts
Машины можно объединять в группы для разграничения выполняемых команд и других взаимодействий.
Playbook — конфигурационный выполняемый файл для Ansible, в котором описываются выполняемые действия на требуемых машинах. Указанный файл может включать самые гибкие настройки и запоминать переменные, заполняемые на одной машине, для переноса их на другие.
Рисунок 2 – Playbook файл для настройки master ноды с генерацией и сохранением секретного ключа для присоединения worker нод
При выполнении массива команд, записанных в playbook файле, весь ход процесса будет отражен в консоли, включая ошибки и описание способов их устранения.
Программное решение для удаленного управления конфигурациями Ansible также позволяет производить сбор информации и проводить аналитику с группой физических или виртуальных машин.
Таким образом, Ansible является необходимым инструментом при работе с кластерами Kubernetes. Особенно важно, что Ansible позволяет сэкономить время на установку, поддержку и анализ кластеров, причем экономия времени будет тем больше, чем крупнее и сложнее создаваемый кластер.
Кроме того, после установки инструмента Ansible можно использовать Kubespray — специально настроенный набор команд для ускоренного развертывания кластера с дополнительными настройками, который позволит установить желаемые стартовые настройки для кластера и развернуть его одной командой [3].
Для использования Kubespray необходимо сделать копию GitHub репозитория: https://github.com/kubernetes-sigs/kubespray.git, а затем перейти в загруженный каталог. Сделать копию папки /inventory/sample, перейти в нее и настроить требуемые параметры будущего кластера в файлах group_vars/k8s_cluster/addons.yml и group_vars/k8s_cluster/k8s-cluster.yml. Для описания стека серверов, на которые необходимо установить кластер, нужно внести изменения в файл inventory.ini, аналогично файлу hosts, представленному на рис. 1.
Kubespray работает на базе утилиты Ansible, и потому необходимо также провести стартовую настройку виртуальных машин, описанную ранее. Одним из преимуществ Kubespray является то, что устанавливать Ansible на master ноду не нужно, так как его компиляция и выполнение происходят в пространстве проекта Python, предоставляемого с Kubespray. Для сбора необходимых зависимостей для развертывания следует выполнить следующий набор команд в папке Kubespray:
mkdir venv python3 -m venv ./venv source ./venv/bin/activate pip install -r requirements.txt
Затем выполняется следующая команда, запускающая развертывание кластера: ansible-playbook -i ./inventory/lab/inventory.ini --become --become-user=root cluster.yml [4]. Развертывание занимает от 15 до 30 мин в зависимости от скорости интернет-соединения и вычислительных мощностей виртуальных машин. По завершении работы Kubespray можно проверить состояние нового кластера с одной master нодой и тремя worker нодами с помощью следующей команды на master ноде: kubectl get nodes.
Рисунок 3 – Развернутый кластер Kubernetes
Для упрощенного доступа к сервисам из сети хостовой машины на этапе заполнения параметров Kubespray включается поддержка ingress-nginx контроллера и балансировщика нагрузки MetalLB в режиме Layer2 [5]. Для MetalLB выделяется пул IP-адресов, которые могут быть заняты новыми сервисами. MetalLB берет адрес из указанного диапазона, назначает его одной из нод и сообщает об этом окружающим посредством ARP или BGP. Все запросы, приходящие на заданный адрес, он направляет соответствующему сервису Kubernetes. Если нода внезапно перестает работать, то MetalLB переназначает IP другой ноде [6].
Проблема непосредственного сетевого доступа к контейнерам Kubernetes
Очередная проблема взаимодействия разработчиков с облачными инфраструктурами на базе Kubernetes в тестовых средах обусловлена тем, что Kubernetes имеет свою внутреннюю подсеть для более быстрого и безопасного общения между контейнерами, поэтому доступ к развернутым сервисам в этом кластере не всегда удобен или вообще невозможен. Это объясняется принципами безопасности и тем, что дальнейшее решение об открытости для уникального конкретного кейса и настройке кластера должен принимать разработчик, что затрудняет процесс разработки и тестирования конечного кластера [6].
Одним из вариантов, предлагаемых самими разработчиками Kubernetes, является использование proxy для доступа к необходимым сервисам. К примеру, для доступа к панели управления кластером необходимо добавить сервис proxy, и производить вход в панель администрирования с помощью генерируемого при каждом запуске уникального ключа.
Второй вариант от производителя — это запускать сервис proxy на одной из master нод. Данный способ также включает обновляемый секретный ключ. Указанные способы рекомендуются разработчиком только для тестовых сред и строго запрещены при production (производственном) развертывании. В реальности оба способы неприменимы даже для тестовых сред, так как во время тестирования нередко происходят плановые перезагрузки, что влечет повторное развертывание.
Система доменных имен DNS — это система связи различных типов информации, например, связи IP адресов с легко запоминающимися именами. По умолчанию большинство кластеров Kubernetes автоматически настраивают внутреннюю службу DNS в качестве компактного механизма поиска служб. Встроенная система обнаружения служб позволяет приложениям легко находить друг друга и взаимодействовать на кластерах Kubernetes, даже в случае создания подов и служб, их удаления и перемещения между узлами.
До выпуска версии Kubernetes 1.11 служба Kubernetes DNS была основана на kube-dns. В версии 1.11 появилась версия службы CoreDNS, устраняющая ряд проблем kube-dns со стабильностью и безопасностью.
Вне зависимости от того, какое программное обеспечение обрабатывает записи DNS, оба варианта работают одинаково:
- создается служба с именем kube-dns и один или несколько подов;
- служба kube-dns прослушивает события службы и события конечных точек, которые активируются при создании, обновлении или удалении служб Kubernetes и связанных с ними подов через Kubernetes API, и обновляет записи DNS по мере необходимости;
- происходит проверка создания подов kubelet, которая задает опцию /etc/resolv.conf nameserver для каждого нового пода как IP-адрес кластера службы kube-dns с соответствующими опциями поиска, позволяющими использовать более короткие имена хостов;
- для работающих в контейнерах приложений можно разрешать такие имена хостов, как example-service.namespace, и они будут считаться корректными IP-адресами кластера [7].
Для внутренней маршрутизации Kubernetes по стандарту также использует домен svc.cluster.local, которому дописывается имя сервиса и его namespace. Полное имя для внутреннего доступа к сервису будет выглядеть так: service.namespace.svc.cluster.local, но данное доменное имя доступно только внутри кластера Kubernetes (при развертке сервисов каждому поду приложения). Из этого следует, что для тестирования и разработки приложений, которые в последующем будут размещаться и функционировать на кластере Kubernetes, необходимо, как было уже описано выше, использовать proxy или создавать DNS-записи в файле hosts на компьютере разработчика с конфигурацией подов на использование внешнего IP-адреса (IP-адреса хостовой машины, на которой в данный момент развернут под). Так как сеть Kubernetes закрытая, компьютер разработчика ничего про нее не знает и не имеет к ней доступа. Поскольку под — это расходный материал в Kubernetes и у него есть жизненный цикл, то после перезапуска Kubernetes может развернуть его на другой ноде, и внешний адрес пода изменится, что делает разработку и отладку всей программной инфраструктуры трудоемкой.
Для устранения данных проблем у Kubernetes имеется объект Сервис. Сервис в Kubernetes — это абстрактный объект, который определяет логический набор подов и политику доступа к ним. Сервисы создают слабую связь между подами, которые от них зависят, позволяют приложениям принимать трафик, могут быть по-разному открыты, в зависимости от указанного поля type в ServiceSpec.
- ClusterIP (по умолчанию) — открывает доступ к сервису по внутреннему IP-адресу в кластере. Этот тип делает сервис доступным только внутри кластера.
- NodePort — открывает сервис на одном и том же порту каждого выбранного узла в кластере с помощью NAT. Делает сервис доступным вне кластера, используя <NodeIP>:<NodePort>. Является надмножеством ClusterIP.
- LoadBalancer — создает внешний балансировщик нагрузки в текущем облаке (если это поддерживается) и назначает фиксированный внешний IP-адрес для сервиса. Является надмножеством NodePort.
- ExternalName — открывает доступ к сервису с указанным именем (определенным в поле externalName в спецификации) и возвращает запись CNAME; proxy не используется. Для этого типа требуется версия kube-dns 1.7 или выше [8].
Рисунок 4 – Конфигурация пода DNS Kubernetes
Сервис направляет трафик через набор подов. Сервисы — это абстракция, позволяющая взаимозаменять поды Kubernetes без ущерба для приложения. Сервисы в Kubernetes находят и маршрутизируют трафик между зависимыми подами (это могут быть фронтенд и бэкенд-компоненты приложения).
Рисунок 5 – Схема работы сервисов в Kubernetes
Сервисы в Kubernetes используются в основном только для внутренней маршрутизации трафика. Есть возможность использования сервисов в режиме LoadBalancer, но это плохо масштабируемое решение, так как для каждого пода надо будет выделять отдельный внешний IP-адрес.
Эффективным и масштабируемым решением для организации внешнего сетевого доступа является использование Ingress-контроллера в кластере Kubernetes и установка локального DNS-сервера. Ingress-контроллер — это сущность Kubernetes кластера, которая отвечает за работу с внешним трафиком и его маршрутизацию.
Основные преимущества использования ingress контроллеров:
- Реализация Ingress-контроллера может быть на базе различного популярного и проверенного программного обеспечения: nginx, haproxy, traefik и др. Стандартно Kubernetes использует контроллер на базе Nginx.
- Так как Ingress-контроллер работает на седьмом уровне модели OSI, в то время как сервис на третьем, использование Ingress контроллеров позволяет разворачивать поды вместе с сервисами в режиме NodeType, а также настраивать все внутреннее и внешнее сетевое общение на основе доменных имен.
- Существует единая точка для конфигурации, управления и мониторинга всего внешнего и внутреннего взаимодействия [9].
После конфигурации Ingress-контроллера необходимо развернуть локальный DNS-сервер. В качестве примера можно использовать популярный и проверенный DNS-сервер BIND9. Данный программный продукт очень легкий и работает на всех популярных операционных системах. После его установки и настройки необходимо добавить свою собственную зону (домен) и перенаправление на master ноды Kubernetes-сервера, где, в свою очередь, запросы уже будет перехватывать и обрабатывать Ingress-контроллер.
Рисунок 6 – Пример конфигурации DNS сервера BIND9
Заключение
Таким образом, используя описанные выше инструменты и решения проблем взаимодействия разработчиков с облачными инфраструктурами на базе Kubernetes, можно добиться существенного упрощения работы с кластерами Kubernetes в тестовых и продуктивных средах, к тому же, что очень важно отметить, чем больше кластеры и их количество, тем более эффективными окажутся мероприятия по внедрению Ansible и BIND9.
Описанные методы оптимизации работы со средами контейнеризации могут быть применены при разработке любых сетевых программных продуктов с большим количеством сервисов и серверных машин, а также для администрирования крупных сетей государственных и коммерческих предприятий.
Литература
- Ansible. URL: https://www.ansible.com/ (дата обращения: 01.02.2023).
- SSH Essentials: Working with SSH Servers, Clients, and Keys. URL: https://www.digitalocean.com/community/tutorials/ssh-essentials-working-with-ssh-servers-clients-and-keys (дата обращения: 03.02.2023).
- Установка HA Master Kubernetes кластера с помощью Kubespray. URL: https://habr.com/ru/post/344704/ (дата обращения: 05.02.2023).
- Kubespray — Deploy a Production Ready Kubernetes Cluster. URL: https://kubespray.io/ (дата обращения: 10.02.2023).
- Введение в современную сетевую балансировку и проксирование. URL: https://habr.com/ru/company/vk/blog/347026/ (дата обращения: 13.02.2023).
- Bare-metal considerations — NGINX Ingress Controller. URL: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/ (дата обращения: 14.02.2023).
- Создание сервиса для открытия доступа к приложению. URL: https://kubernetes.io/ru/docs/tutorials/kubernetes-basics/expose/expose-intro/ (дата обращения: 16.02.2023).
- Основы Kubernetes. URL: https://habr.com/ru/articles/258443/ (дата обращения: 16.02.2023).
- Маркелов А. Введение в технологии контейнеров и Kubernetes. М.: ДМК Пресс, 2019. С. 110?152.
- Bilgin Ibryam, Roland Hu?. Kubernetes Patterns. CA: O'Reilly Media, 2016. 42 с.