В продолжение к недавнему релизу CSI-драйвера для Яндекс.Облака мы публикуем ещё один Open Source-проект для этого облака — Cloud Controller Manager. CCM необходим не только для кластера в целом, но и собственно CSI-драйвера. Подробности о его предназначении и некоторые особенности реализации — под катом.
Введение
Зачем это?
Мотивы, побудившие нас к разработке CCM для Яндекс.Облака, полностью совпадают с уже описанными в анонсе CSI-драйвера. Мы обслуживаем множество Kubernetes-кластеров у разных облачных провайдеров, для чего используем единый инструмент. Он реализует многочисленные удобства «в обход» managed-решений этих провайдеров. Да, у нас довольно специфичный случай и потребности, однако созданные из-за них наработки могут пригодиться и другим пользователям.
Что вообще такое CCM?
Как правило, мы подготавливаем окружающую нас среду для кластера извне — например, с помощью Terraform. Но иногда есть необходимость управлять окружающей нас облачной средой из кластера. Такая возможность предусмотрена, и именно её реализует CCM.
В частности, Cloud Controller Manager обеспечивает пять основных типов взаимодействия:
- Instances – реализует связь 1:1 между объектом узла в Kubernetes (
Node
) и виртуальной машиной в облачном провайдере. Для этого мы:- заполняем поле
spec.providerID
в объектеNode
. К примеру, для OpenStack CCM это поле имеет следующий формат:openstack:///d58a78bf-21b0-4682-9dc6-2132406d2bb0
. Можно видеть имя облачного провайдера и уникальный UUID server’а (виртуальная машина в OpenStack) объекта; - дополняем
nodeInfo
в объектеNode
информацией о виртуальной машине. Например, указываем instance type в AWS; - проверяем наличие виртуальной машины в облаке. К примеру, если объект
Node
перешёл в состояниеNotReady
, можно проверить, существует ли вообще виртуальная машина в облачном провайдере поproviderID
. Если её нет — удаляем объектNode
, который в противном случае остался бы в кластере навечно;
- заполняем поле
- Zones – задаёт failure domain для объекта
Node
, чтобы планировщик мог выбрать узел для Pod’а согласно регионам и зонам в облачном провайдере; - LoadBalancer – при создании объекта
Service
с типомLoadBalancer
создаёт некий балансировщик, который направит трафик извне к узлам кластера. Например, в Yandex.Cloud можно использоватьNetworkLoadBalancer
иTargetGroup
для этих целей; - Route – строит сеть между узлами, т.к. по требованиям Kubernetes каждый pod должен иметь свой IP-адрес и иметь возможность достучаться до любого другого pod’а. Для этих целей можно использовать оверлейную сеть (VXLAN, GENEVE) или задать таблицу маршрутизации прямо в виртуальной сети облачного провайдера:
- Volume – позволяет динамически заказывать PV, используя PVC и SC. Изначально этот функционал являлся частью CCM, но ввиду большой сложности был вынесен в отдельный проект Container Storage Interface (CSI). Про CSI мы не раз писали и, как уже говорилось, даже выпустили CSI-драйвер.
Ранее весь код, взаимодействующий с облаком, лежал в основном Git-репозитории проекта Kubernetes по адресу k8s.io/kubernetes/pkg/cloudprovider/providers
, но от этого решили отказаться из-за неудобства работы с большой кодовой базой. Все старые реализации были вынесены в отдельный репозиторий. Для удобства дальнейшей поддержки и разработки все общие компоненты тоже были вынесены в отдельный репозиторий.
Как и в случае с CSI, многие крупные поставщики облачных услуг уже разработали свои CCM для использования облаков в Kubernetes. Если же CCM у поставщика нет, но все необходимые функции доступны через API, то можно реализовать CCM самостоятельно.
Чтобы написать свою реализацию CCM, достаточно реализовать нужные Go-интерфейсы.
Реализация
Как пришли к этому
Разработку (а точнее — даже использование) мы начали с готового(!) CCM для Yandex.Cloud годовой давности.
Однако в этой реализации нам не хватало:
- аутентификации через JWT IAM-токен;
- поддержки Service controller’а.
По согласованию с автором (dlisin) в Telegram, мы форкнули yandex-cloud-controller-manager и дописали недостающие функции.
Основные возможности
На текущий момент CCM поддерживает следующие интерфейсы:
- Instances;
- Zones;
- LoadBalancer.
В будущем, когда Yandex.Cloud начнёт работать с продвинутыми возможностями VPC, мы добавим и интерфейс Routes.
LoadBalanacer как главный вызов
Изначально мы пробовали, как у других реализаций CCM, создавать пару из LoadBalancer
и TargetGroup
для каждого Service
с типом LoadBalancer
. Однако у Yandex.Cloud обнаружилось одно интересное ограничение: нельзя использовать TargetGroups
с пересекающимися Targets
(пара SubnetID
— IpAddress
).
Поэтому внутри созданного CCM запускается контроллер, который при изменении объектов Node
собирает информацию обо всех интерфейсах на каждой виртуальной машине, группирует их по принадлежности к определённым NetworkID
, создаёт по TargetGroup
на NetworkID
, а также следит за актуальностью. Впоследствии, при создании объекта Service
с типом LoadBalanacer
мы просто прикрепляем заранее созданную TargetGroup
к новым NetworkLoadBalanacer
'ам.
Как начать пользоваться?
CCM поддерживает Kubernetes версии 1.15 и выше. В кластере для его работы требуется, чтобы флаг --cloud-provider=external
был установлен в значение true
для kube-apiserver, kube-controller-manager, kube-scheduler и всех kubelet’ов.
Все необходимые шаги по самой установке описаны в README. Инсталляция сводится к созданию объектов в Kubernetes из манифестов.
Для использования CCM также понадобится:
- указать в манифесте идентификатор каталога (
folder-id
) Яндекс.Облака; - сервисный аккаунт для взаимодействия с API Яндекс.Облака. В манифесте
Secret
необходимо передать авторизованные ключи от сервисного аккаунта. В документации описано, как создать сервисный аккаунт и получить ключи.
Будем рады обратной связи и новым issues, если столкнетесь с какими-то проблемами!
Итоги
Реализованный CCM мы используем в пяти Kubernetes-кластерах на протяжении двух последних недель и планируем расширить их число до 20 в ближайший месяц. Использовать CCM для больших и критических инсталляций K8s в настоящий момент не рекомендуем.
Как и в случае с CSI, будем рады, если разработчики Яндекса возьмут на себя развитие и поддержку этого проекта — мы готовы передать репозиторий по их просьбе, чтобы заниматься более профильными для нас задачами.
P.S.
Читайте также в нашем блоге:
- «Наш опыт разработки CSI-драйвера в Kubernetes для Яндекс.Облака»;
- «Готовить Kubernetes-кластер просто и удобно? Анонсируем addon-operator»;
- «Расширяем и дополняем Kubernetes (обзор и видео доклада)».
Автор: Андрей Климентьев