DIY: Ваше собственное облако на базе Kubernetes (часть 3)
Вот мы и подобрались к самому интересному — запуску Kubernetes в Kubernetes. В этой статье мы поговорим о таких технологиях как Kamaji и Cluster API, а так же о том как интегрировать их с KubeVirt.
В прошлых статьях мы уже рассказывали как мы готовим Kubernetes на bare metal, и о том как превратить Kubernetes в средство запуска виртуальных машин. Эта статья завершает серию, объясняя как используя всё вышеперечисленное можно построить полноценный managed Kubernetes и запуск виртуальных Kubernetes-кластеров по клику.
И начнём мы, пожалуй с Cluster API.
Cluster API
Cluster API является расширением для Kubernetes, которое дает возможность управлять Kubernetes-кластерами как custom resources внутри другого Kubernetes-кластера.
Основная задача Cluster API — предоставить унифицированный интерфейс для описания основных сущностей Kubernetes-кластера и управлять их жизненным циклом. Это позволяет автоматизировать процессы создания, обновления, и удаления кластеров, упрощая масштабирование и управление инфраструктурой.
В контексте Cluster API есть два типа понятия: management кластер и tenant кластер.
Management кластер представляет собой Kubernetes кластер, который используется для развертывания и управления другими кластерами. Этот кластер содержит все необходимые компоненты Cluster API и отвечает за описание, создание, и обновление tenant кластеров и зачастую используется только для этого.
Tenant кластеры — это пользовательские кластеры или кластеры, развернутые с помощью Cluster API. Их создание происходит путем описания соответствующих ресурсов в management кластере. Уже они используются для развертывания приложений и сервисов конечными пользователями.
Важно понимать, что физически tenant кластера не обязательно должны запускаться на инфраструктуре management-кластера, а чаще запускаются как раз наоборот где-то в другом месте.
Для своей работы Cluster API использует концепцию «провайдеров», под которыми понимаются отдельные контроллеры, отвечающие за конкретные компоненты создаваемого кластера. В рамках Cluster API существует множество типов провайдеров. Основные из них это:
Infrastructure Provider, который отвечает за предоставление вычислительной инфраструктуры, такой как виртуальные машины или физические сервера.
Control Plane Provider, который предоставляет Kubernetes control plane, а именно компоненты kube-apiserver, kube-scheduler и kube-controller-manager.
Bootstrap Provider, который используется для генерации cloud-init конфигов для создаваемых виртуальных машин и серверов.
Для начала, вам потребуется установить сам Cluster API и по одному провайдеру каждого типа. Полный список поддерживаемых провайдеров вы можете найти в документации проекта.
Для установки можно использовать утилиту clusterctl, или более декларативный метод с помощью Cluster API Operator.
Наш выбор
Infrastructure Provider
Мы выбрали KubeVirt в качестве Infrastructure Provider — потому что в нашей мы используем KubeVirt и хотим запускать виртуальные машины для воркеров прямо внутри нашего management-кластера.
Control Plane Provider
Проект Kamaji предлагает готовое решение для запуска control-plane Kubernetes для tenant-кластеров в виде контейнеров внутри management-кластера. Этот подход имеет ряд весомых преимуществ:
Экономичность: Запуск control-plane в контейнерах позволяет избежать использования отдельных control-plane нод для каждого кластера, тем самым существенно уменьшая затраты на инфраструктуру.
Стабильность: Упрощение архитектуры за счет исключения сложной многоуровневой схемы развертывания. Вместо последовательного запуска виртуальной машины и последующей установкой etcd и компонентов Kubernetes внутри неё, у вас есть простой control-plane, который разворачивается и запускается как обычное приложение внутри Kubernetes и управляется оператором.
Безопасность: control-plane кластера скрыт от конечного пользователя что уменьшает возможность вывода из строя его компонентов, а также исключает доступ пользователя к хранилищу сертификатов кластера. Такой подход организации невидимого пользователю control-plane часто применяется облачными провайдерами.
Bootstrap Provider
Kubeadm в качестве Bootstrap Provider — как стандартный способ подготовки кластеров в Cluster API. Этот провайдер развивается как часть самого Cluster API. Для своей работы он требует только наличие подготовленного образа системы с установленным kubelet и kubeadm и позволяет генерировать конфиги в формате cloud-init и ignition.
В целом мы довольно много колебались между выбором Talos Linux и Kamaji+Kubeadm для запуска кластеров в Cluster API, но всё-таки решили сделать в пользу второго решения. Преимущественно из-за возможности запуска control-plane в контейнерах, а не отдельных виртуальных машинах.
Как с этим работать
Основным объектом в Cluster API является ресурс Cluster, который является родительским для всех остальных. Как правило этот ресурс ссылается на два других: ресурс описывающий control plane и ресурс описывающий infrastructure, каждый из них управляется отдельным провайдером.
В отличие от Cluster эти два ресурса не стандартизированы и их kind зависит от конкретного используемого вами провайдера:
В рамках Cluster API существует также ресурс под названием MachineDeployment, который описывает группу узлов (нод), будь то физические сервера или виртуальные машины. Этот ресурс работает аналогично стандартным Kubernetes ресурсам, таким как Deployment, ReplicaSet и Pod, предоставляя механизм для декларативного описания группы узлов и автоматического масштабирования.
Другими словами ресурс MachineDeployment позволяет вам декларативно описывать ноды для вашего кластера, автоматизируя их создание, удаление и обновление в соответствии с заданными параметрами и запрошенным числом реплик.
Для создания машин, MachineDeployment ссылается на шаблон для генерации самой машины и шаблон для генерации её cloud-init конфига:
Таким образом чтобы развернуть новый Kubernetes-кластер с помощью Cluster API, вам потребуется подготовить следующий набор ресурсов:
Общий ресурс Cluster
Ресурс KamajiControlPlane, отвечающий за control-plane запускаемый Kamaji
Ресурс KubevirtCluster, описывающий конфигурацию кластера в KubeVirt
Ресурс KubevirtMachineTemplate, отвечающий за темплейт виртуалки
Ресурс KubeadmConfigTemplate, отвечающий за генерацию токенов и cloud-init
Как минимум один MachineDeployment для создания хоть каких-то воркеров
В большинстве случаев этого достаточно, но в зависимости от используемых провайдеров, вам могут понадобиться и другие ресурсы. Примеры создаваемых ресурсов для провайдеров каждого типа вы можете найти в документации проекта Kamaji
Доводим кластер до ума
На этом этапе у вас уже есть готовый tenant Kubernetes кластер, но пока что в нём нет ещё ничего кроме API воркеров и нескольких core-плагинов, которые стандартно включены при установке любого Kubernetes-кластера: это kube-proxy и coredns. Для полноценной интеграции вам потребуется установить в него ещё несколько компонентов:
Для установки дополнительных компонентов вы можете воспользоваться отдельным Cluster API Add-on Provider for Helm, или всё тем же FluxCD.
При создании ресурсов в FluxCD есть возможность указать целевой кластер сославшись на kubeconfig сгенерированный Cluster API. Тогда установка будет выполняться непосредственно в него. Таким образом, FluxCD становится универсальным инструментом для управления ресурсами как в management-кластере, так и в пользовательских tenant-кластерах.
О каких компонентах идёт речь? В общем случае их набор следующий:
CNI Plugin
Чтобы обеспечить связь между подами в tenant-Kubernetes кластере, необходимо развернуть CNI-плагин. Этот плагин формирует виртуальную сеть, позволяющую подам взаимодействовать друг с другом, и традиционно разворачивается как Daemonset на рабочих узлах кластера. Вы можете выбрать и установить любой CNI-плагин, который сочтете подходящим.
Cloud Controller Manager
Основная задача Cloud Controller Manager (CCM) — это интеграция Kubernetes с облачной инфраструктурой провайдера (в нашем случае — её роль выполняет родительский Kubernetes-кластер в котором запускаются все виртуальные машины дочернего Kubernetes-кластера), вот несколько задач которые он выполняет:
Когда создается сервис с типом LoadBalancer, CCM инициирует процесс создания облачного балансировщика нагрузки, который направляет трафик на ваш Kubernetes-кластер.
Если из облачной инфраструктуры удаляется нода, CCM обеспечивает её удаление и из вашего кластера, поддерживая актуальное состояние кластера.
При использовании CCM, ноды добавляются в кластер со специальныи таинтом node.cloudprovider.kubernetes.io/uninitialized что позволяет обрабатывать дополнительную бизнес-логику при необоходимости. После успешной инициализации с ноды этот таинт снимается.
В зависимости от облачного провайдера CCM может работать как внутри, так и вне tenant-кластера.
KubeVirt Cloud Provider спроектирован так, чтобы устанавливается во внешнем родительском management-кластере. Таким образом создание сервисов типа LoadBalancer в tenant-кластере инициирует создание сервисов типа LoadBalancer в родительском кластере, которые направляют трафик внутрь tenant-кластера.
CSI-драйвер
Container Storage Interface (CSI) разделяется на две основные части для взаимодействия с хранилищем в Kubernetes:
csi-controller: Этот компонент отвечает за взаимодействие с API облачного провайдера для создания, удаления, подключения, отключения и изменения размера томов.
csi-node: Этот компонент запускается на каждой ноде и обеспечивает монтирование томов к подам по требованию kubelet.
В контексте использования CSI KubeVirt Driver, возникает уникальная возможность. Поскольку виртуальные машины (ВМ) в KubeVirt запускаются внутри management Kubernetes-кластера, где доступен полноценный Kubernetes API, это открывает путь для запуска csi-controller за пределами пользовательского tenant-кластера. Такой подход популярен в сообществе KubeVirt и предлагает несколько ключевых преимуществ:
Безопасность: Этот метод скрывает внутренний API облака от конечного пользователя, предоставляя доступ к ресурсам исключительно через интерфейс Kubernetes. Таким образом, уменьшается риск непосредственного доступа к управляющему кластеру из пользовательских кластеров.
Простота и удобство: Пользователям не нужно управлять дополнительными контроллерами в своих кластерах, что упрощает архитектуру и уменьшает нагрузку на управление.
При этом CSI-node обязательно должен запускаться внутри tenant-кластера, так как он напрямую взаимодействует с kubelet на каждой ноде. Этот компонент обеспечивает монтирование и демонтирование томов в поды, что требует тесной интеграции с процессами, происходящими непосредственно на нодах кластера.
CSI KubeVirt Driver выступает в роли прокси для заказа томов. При создании PVC внутри tenant-кластера, создаётся PVC в management-кластере, затем PV созданные подключается в виртуальную машину
Cluster Autoscaler
Cluster Autoscaler является универсальным компонентом, который может работать с разнообразными облачными API, и его интеграция с Cluster-API — лишь одна из доступных функций. Для корректной настройки ему требуется доступ к двум кластерам: к tenant-кластеру, для отслеживания подов и определения необходимости добавления новых нод, и к управляющему Kubernetes-кластеру (management kubernetes cluster), где он взаимодействует с ресурсом MachineDeployment и корректирует количество реплик.
Хотя обычно Cluster Autoscaler запускают внутри tenant Kubernetes кластера, в данной ситуации мы предлагаем устанавливать его снаружи. Это связано по тем же причинам что мы описывали и выше. Это проще и безопаснее, мы не хотим чтобы пользователи tenant кластеров имели какой-либо доступ к management API management-кластера.
Konnectivity
Есть ещё один дополнительный компонент о котором я хотел бы упомянуть — это Konnectivity. Он, скорее всего понадобится вам чуть позже, для того чтобы у вас заработали вебхуки и API aggregation layer в tenant Kubernetes кластере. Эта тема подробно рассмотрена в одной из моих предыдущих статей.
В отличие от вышепредставленных компонентов. Kamaji, позволяет легко включить Konnectivity и управлять им как одним из core компонентов вашего tenant-кластера, на ряду с kube-proxy и coredns.
Теперь у вас есть полноценный Kubernetes-кластер с возможностью динамического масштабирования, автоматического провижининга томов и балансировщиков нагрузки.
В дальнейшем вы можете рассмотреть вопросы сбора метрик и логов с ваших tenant-кластеров, но это уже выходит за рамки этой статьи.
Разумеется все перечисленные компоненты, необходимые для деплоя Kubernetes-кластера вы можете упаковать в единый Helm-чарт и деплоить как единое приложение. Именно так мы и организуем деплой manged Kubernetes-кластеров по кнопке в нашей свободной PaaS-платформе Cozystack, где вы можете попробовать все описанные в статье технологии совершенно бесплатно.