На сегодня Go – фактический монополист в реализации Kubernetes-операторов. Вот почему так сложилось:
-
– это мощный фреймворк, который создан специально для реализации операторов на Go. и Kubernetes реализованы на Go, и это меняет правила игры. Оператор, реализованный на Go, позволяет взаимодействовать со всей экосистемой.
- В языке Go есть простой механизм использования параллельности, поэтому приложения получаются высокопроизводительными.
Наверняка вам не захочется учить Go, если вы уже знаете Python. Поэтому мы сделаем надёжный оператор, используя язык программирования Python.
Мы напишем простой оператор, спроектированный, чтобы копировать ConfigMap, когда появляется новое пространство имён или при изменении состояния объектов ConfigMap, Secret. Нашим оператором удобно производить массовые обновления настроек приложения, а также сбрасывать им секреты, например, ключи репозитория образов Docker (когда Secret добавлен в пространство имён).
Так какие функции должен выполнять хороший оператор Kubernetes? Вот они:
- Взаимодействие с оператором производится с помощью Custom Resource Definitions (далее CRD).
- Оператор поддерживает настройку. Мы можем использовать флаги в командной строке и переменные окружения для настройки.
- Образ Docker и чарты Helm создаются с учётом облегчения установки для пользователей (обычно одной командой) в их кластер Kubernetes.
Чтобы оператор знал, где и какие ресурсы искать, нужно настроить некоторые правила. Каждое правило будет представлено как особый CRD-объект. Какие поля должен иметь CRD-объект?
- Тип ресурсов, которые нам интересны (ConfigMap или Secret).
- Список пространств имён, хранящих ресурсы.
- Селектор, который помогает нам искать ресурсы в конкретном пространстве.
Давайте определим наш CRD:
И немедленно добавим простое правило для выбора ConfigMaps с метками, совпадающими с copyrator: “true” в пространстве имён по умолчанию:
Отлично! Теперь нам нужно как-то получить информацию о наших правилах. Пришло время признаться: мы не будем делать запросы API нашего кластера вручную. Для этих целей есть Python библиотека – kubernetes-client:
Выполнив код выше, получим следующий результат:
Здорово! Теперь у нас есть особое правило для оператора. Важно, что мы смогли сделать это принятым для Kubernetes способом.
Пришло время приступить к базовой настройке оператора. Есть два главных подхода к настройке приложений:
- с помощью параметров командной строки;
- с помощью переменных окружения.
С помощью параметров командной строки вы сможете извлекать настройки с большей гибкостью и с поддержкой проверки типов данных. Используем модуль argparser из стандартной библиотеки Python. Детали и примеры использования доступны в официальной документации Python.
Вот пример настройки поиска флагов командной строки, адаптированных для нашего случая:
С другой стороны, вы можете легко передать служебную информацию о модуле в контейнер с помощью переменных окружения в Kubernetes. Например, вы можете получить информацию о пространстве имён, в котором запущен модуль с помощью следующей структуры:
Давайте используем специальные карты для разделения методов работы с ConfigMap и Secret. Они позволят нам определиться с методом, необходимым для отслеживания и создания объектов:
Затем вы должны получать события от сервера API. Мы реализуем эту функциональность следующим образом:
После получения события мы приступаем к основной логике обработки:
Базовая логика завершена! Теперь нужно упаковать её в единый пакет Python. Создаём setup.py и добавляем туда метаданные о проекте:
Сейчас наш проект имеет следующую структуру:
Результирующий Dockerfile до смешного прост: мы берём базовый образ python-alpine и устанавливаем наш пакет (давайте отложим его оптимизацию на лучшее время):
Развернуть Copyrator тоже очень легко:
Наконец, создаём соответствующую роль для оператора с необходимыми разрешениями:
В этой статье мы показали, как создать ваш собственный оператор Kubernetes на Python. Конечно, он ещё сыроват: вы можете обогатить его возможностями обработки нескольких правил, самостоятельным мониторингом изменений в своих CRD, извлечь выгоду из возможностей параллелизма.