Русский
Русский
English
Статистика
Реклама

Kubernetes operator

Простое создание Kubernetes-операторов с shell-operator прогресс проекта за год

10.07.2020 14:07:02 | Автор: admin


Kubernetes-операторы удобный механизм для расширения возможностей этой контейнерной платформы, по праву снискавший широкое признание в среде инженеров эксплуатации и им сочувствующих. О том, как они устроены и работают, мы рассказывали в уже далёком 2017-м. А в апреле прошлого года мы представили Open Source-проект shell-operator, который значительно упростил процесс создания Kubernetes-операторов.

Для этого был разработан фреймворк, позволяющий запускать произвольные скрипты (на Bash, Python и т.п.) в случае наступления определённых событий в K8s-кластере.

За минувшее время shell-operator обрёл свою пользовательскую базу (см. подробности в конце статьи) и, конечно, новые возможности. По случаю недавнего релиза v1.0.0-beta.11 (о бета-статусе см. дальше) мы решили рассказать о том, к чему проект пришёл за время своего существования, с момента анонса первой публичной версии.

Об устройстве и назначении


Но начнем с краткого пояснения, как работает shell-operator и для чего в принципе он может понадобиться.

Shell-operator запускается в podе Kubernetes-кластера. Он представлен там как:

  • Go-бинарник, который подписывается на события в K8s API и запускает хуки (передавая им подробности о случившемся);
  • набор хуков, каждый из которых скрипт на Bash, Python или любой другой исполняемый файл.

Хуки:

  • сами определяют, какие события и для каких объектов им нужны;
  • выполняют необходимые действия в случае наступления этих событий в K8s.

Таким образом, shell-operator это прослойка между событиями в Kubernetes API и скриптами для их обработки.

image

Зачем вообще был создан shell-operator? Операторы это стандарт для правильной автоматизации в рамках Kubernetes, однако их полноценная разработка (на Go с привлечением соответствующего SDK) не так проста. Наличие такого простого фреймворка, как shell-operator, значительно снижает порог вхождения в эту область, позволяя быстро и эффективно решать небольшие эксплуатационные задачи* внутри кластера. И, что не менее важно, делать это правильным путём.

О каких задачах идёт речь? Готовые примеры использования shell-operator можно найти в репозитории проекта. У нас же, в компании Флант, мы его применяем как библиотеку (да, так тоже можно было!). Он стал основой для addon-operator, управляющего дополнительными компонентами в Kubernetes.

NB: Анонс этого Open Source-проекта (addon-operator) можно найти здесь. А в докладе Расширяем и дополняем Kubernetes мы подробно рассказывали о причинах его появления, взаимосвязи с shell-operator и принципах функционирования.

Теперь о главных изменениях, представленных в shell-operator за последний год.

Основные новшества


В первых версиях shell-operator для хука был доступен только один объект тот, который связан с событием от кластера. Развитие хуков, используемых в рамках addon-operator, привело к тому, что хук подписывался на изменение объекта, но вызывал kubectl чтобы получить актуальный список других объектов. Чтобы убрать лишние вызовы kubectl и тем самым ускорить работу хуков, реализовано несколько возможностей получить доступ к актуальным спискам объектов:

  • Режим Synchronization + Event, когда хук при старте получает список актуальных объектов, а затем работает только с одним объектом. Этот режим включен по умолчанию можно сказать, что получился аналог reconcile loop из operator-sdk.
  • Режим с получением snapshot'ов, когда хук получает полные актуальные списки объектов при каждом запуске. (Snapshotы используются для кэширования объектов Kubernetes, используемых в хуках.)
  • Режим получения группы snapshot'ов. Может использоваться в случаях, когда хук подписан на разные типы ресурсов, а реагировать на изменения нужно на основе актуальной информации о всех ресурсах независимо от того, что изменилось.
  • Также появилась возможность следить за ресурсом, но не реагировать на его изменения, т.е. накапливать snapshot. Например, хук может реагировать на изменения в CustomResource и при этом получать актуальный объект ConfigMap без дополнительного вызова kubectl. (Для подробностей см. флаги executeHookOnSynchronization и executeHookOnEvent.)

Другие значительные нововведения:

  • Благодаря переходу на использование динамического клиента Kubernetes в shell-operator стало возможным подписываться на любой существующий kind (тип ресурса в Kubernetes API), в том числе и Custom Resources.
  • Хуки можно запускать в разных очередях (см. параметр queue). В дальнейшем для диагностики состояния очередей хуков была добавлена команда и соответствующие endpoints.
  • Добавлена возможность подписываться на несколько имён ресурсов.
  • Появилась подписка с динамическими пространствами имен, которая позволяет следить за ресурсами в namespaceах с указанными лейблами.
  • Хуки получили возможность экспортировать произвольные метрики для их дальнейшего scraping'а Prometheus'ом. Можно указать отдельный порт для этих метрик.
  • Добавлен специальный фреймворк, который упрощает написание хуков на shell.

Менее значимые изменения


  • Хук может возвращать конфигурацию в YAML-формате (в дополнение к JSON).
  • Добавлено логирование в формате JSON на базе logrus (см. LOG_TYPE в переменных окружения).
  • Добавлена настройка listen-address для возможности запуска в режиме hostNetwork: true.
  • Появились настройки rate limit (qps, burst) для клиента Kubernetes API.
  • Представлен флаг kube-server для указания адреса сервера Kubernetes API.
  • Убраны различные блокировки для ускорения параллельной работы хуков.
  • Выражения jqFilter теперь выполняются с помощью библиотеки libjq-go, не требуя запуска отдельного процесса jq.
  • Удалён zombie reaper, обрабатывающий сигнал SIGCHLD и устраняющий процессы-сироты, которые могут порождаться Bash-скриптами. Вместо внутренней реализации теперь используется внешняя tini.
  • Реализованы разные упрощения для подключения shell-operator как библиотеки.
  • Обновлена версия kubectl (с 1.13 до 1.17.4) и сделана сборка на основе alpine-3.11.

Статус и планы


Проект shell-operator всё ещё официально имеет статус бета-версии. Несмотря на это, как уже отмечалось выше, мы весьма интенсивно используем его как основу для addon-operator инструмента, который постоянно эксплуатируется во множестве (100+) K8s-кластеров.

Для стабильного релиза shell-operator как публичного проекта мы планируем (как минимум):

  • добавить e2e-тестирование (#63),
  • реализовать мульти-архитектурную сборку (#184),
  • обновить client-go до 0.18.0, внедрить context и окончательно разобраться с кэшированием объектов в client-go (#188).

Признание сообществом


За прошедшее время мы увидели явный интерес сообщества к shell-operator:

  • Проект упоминался не только в различных списках полезных утилит для Kubernetes (awesome-kubernetes, Cloud Zone), но и на специализированных вебинарах (Weaveworks), митапах (K8s Meetup Tokyo) и даже в книге.
  • Он нашёл свое практическое применение в реальных проектах (самый интересный из известных нам это инсталлятор для китайской K8s-платформы KubeSphere). На просторах GitHub можно найти множество простых операторов, реализованных на основе shell-operator (небольшую подборку из них мы приводили здесь).
  • У проекта появились сторонние контрибьюторы: их вклад пока не очень велик, но мы приветствуем всех желающих поучаствовать.
  • На GitHub собрано 600+ звёзд конечно, будем рады и новым! ;-)

Спасибо за интерес к shell-operator! Задавайте вопросы, если они у вас появились.

P.S.


Читайте также в нашем блоге:

Подробнее..

Как собрать гибридное облако с помощью Kubernetes, которое может заменить DBaaS

10.08.2020 18:20:12 | Автор: admin
Меня зовут Петр Зайцев, я генеральный директор, основатель Percona и хочу рассказать:

  • как мы от open source-решений пришли к Database as a Service;
  • какие существуют подходы к развертыванию баз данных в облаке;
  • как Kubernetes может заменить DBaaS, устранив зависимость от вендора и сохранив простоту СУБД как сервиса.

Статья подготовлена на основе доклада на @Databases Meetup by Mail.ru Cloud Solutions & Tarantool. Если не хотите читать, можно посмотреть:



Как от open source пришли к Database as a Service в облаке


Я занимаюсь open source с конца 90-х годов. Двадцать лет назад пользоваться open source, например базами данных, было не так просто. Надо было скачать исходники, пропатчить, скомпилировать и только потом использовать.

Затем open source пережил серию упрощений:

  • бинарники Tar.gz и INSTALL, которые нужно было компилировать;
  • пакеты с зависимостями типа .deb и.rpm, где нужно только установить набор пакетов;
  • репозитории пакетов вроде APT и YAM, с помощью которых установка происходит автоматически;
  • такие решения как Docker и Snap, позволяющие получать пакеты по инсталляции без внешних зависимостей.

В итоге использовать открытое программное обеспечение становится проще, а также снижается барьер входа в разработку таких приложений.

При этом, в отличие от ситуации 20 лет назад, когда все были экспертами по сборке, сейчас большинство разработчиков не могут собрать из исходников используемые инструменты.

На самом деле, это неплохо, так как:

  1. Мы можем использовать более сложное, но более удобное программное обеспечение. Например, браузер удобно использовать, но в него входит много open source-компонентов, его неудобно собирать с нуля.
  2. Больше людей могут стать разработчиками open source и другого программного обеспечения, больше ПО использует бизнес, выше потребность в нем.

Обратная сторона следующий шаг в упрощении связан с использованием облачных решений, а это приводит к определенному vendor lock-in, то есть привязке к одному поставщику. Мы используем простые решения и провайдеры используют open source-компоненты, но фактически они прибиты гвоздями к одному из крупных облаков. То есть самый простой и быстрый способ разворачивать open source (и совместимое с ним ПО) в облаках, используя проприетарный API.

Если говорить о базах данных в облаке, есть два подхода:

  1. Собрать инфраструктуру базы данных, как в обычном дата-центре. То есть взять стандартные компоновочные блоки: compute, storage и так далее, поставить на них Linux, базу данных, настроить.
  2. Использовать Database as a Service, где провайдер предлагает уже готовую базу данных внутри облака.

Сейчас DBaaS это быстро растущий рынок, потому что такой сервис позволяет разработчикам работать с базами данных напрямую и минимизирует рутинную работу. Провайдер берет на себя обеспечение High Availability (высокой доступности) и легкого масштабирования, патчинг базы данных, бэкапы, настройку производительности.

Два типа Database as a Service на основе open source и альтернатива в виде Kubernetes


Есть два типа Database as a Service для открытых баз данных:

  1. Стандартный open source-продукт, упакованный в бэкенд для администрирования, что упрощает развертывание и управление.
  2. Продвинутое коммерческое решение с разными дополнениями, совместимое с open source.

Оба варианта снижают возможность миграции между облаками, уменьшают портативность данных и приложений. Например, несмотря на то, что разные виды облаков поддерживают, по сути, тот же стандартный MySQL, между ними есть существенные отличия: в работе, производительности, бэкапировании и так далее. Мигрировать с одного облака на другое может быть непросто, особенно для сложных приложений.

И тут возникает вопрос можно ли получить удобство Database as a Service, но как простое open source-решение?

Плохая новость в том, что, к сожалению, пока таких решений на рынке нет. Хорошая новость есть Kubernetes, который позволяет такие решения реализовать.

Kubernetes это операционная система для облака или дата-центра, которая позволяет деплоить приложение и управлять им на множестве серверов кластера, а не на одном хосте.

Сейчас Kubernetes лидер в категории подобного ПО. Для таких задач было много разных решений, но именно он стал стандартом. Многие компании, которые раньше занимались альтернативными решениями, сейчас фокусируются на адаптации своих продуктов для поддержки Kubernetes.

Кроме того, Kubernetes универсальное решение, которое поддерживается в частных, общедоступных и гибридных облаках многих вендоров, например: AWS, Google Cloud, Microsoft Azure, Mail.ru Cloud Solutions.

Как Kubernetes работает с базами данных


Kubernetes изначально разработали для stateless-приложений, которые обрабатывают данные, но ничего не хранят, например, микросервисы или веб-приложения. Базы данных находятся на другом конце спектра, то есть это stateful-приложения. И Kubernetes для таких приложений изначально был не предназначен.

Однако есть фичи, которые появились в Kubernetes в последнее время и позволяют использовать базы данных и другие stateful-приложения:

  1. Концепт StatefulSet целая серия примитивов для обработки событий об остановке работы подов и осуществления Graceful Shutdown (предсказуемого завершения работы приложения).
  2. Persistent Volumes хранилища данных, которые связаны с подами, объектами управления Kubernetes.
  3. Operator Framework то есть возможность создавать компоненты для управления базами данных и другими stateful-приложениями, распределенными на многих узлах.

Уже сейчас в публичных облаках есть крупные Database as a Service, в бэкенде которых Kubernetes, например: CockroachCloud, InfluxDB, PlanetScale. То есть база данных на Kubernetes это не только то, что теоретически возможно, но и то, что работает на практике.

У Percona есть два open source решения для Kubernetes:

  1. Kubernetes Operator for Percona Server for MongoDB.
  2. Kubernetes Operator for XtraDB CLUSTER сервис, который совместим с MySQL, обеспечивает высокую доступность и консистентность. Также можно использовать single node, если высокая доступность не нужна, например для dev database.

Пользователей Kubernetes можно разделить на две группы. Одни используют Kubernetes Operators напрямую это, в основном, продвинутые пользователи, которые хорошо понимают, как работает технология. Другие запускают его на бэкенде таким пользователям интересно что-то вроде Database as a Service, они не хотят вникать в нюансы работы Kubernetes. Для второй группы пользователей у нас есть еще одно open source решение Percona DBaaS CLI Tool. Это экспериментальное решение для тех, кто хочет получить open source DBaaS на основе Kubernetes без глубокого понимания технологии.

Как запустить DBaaS от Percona на Google Kubernetes Engine


Google Kubernetes Engine, на мой взгляд, одна из самых функциональных реализаций технологии Kubernetes. Она доступно во многих регионах мира и обладает простым и удобным Command Line Tool (SDK), позволяющим создавать скрипты, а не управлять платформой вручную.

Для того чтобы наш DBaaS заработал, нужны следующие компоненты:

  1. Kubectl.
  2. Google Cloud SDK.
  3. Percona DBaaS CLI.

Устанавливаем kubectl


Устанавливаем пакет для вашей операционной системы, мы рассмотрим на примере Ubuntu. Подробнее тут.

sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.listsudo apt-get updatesudo apt-get install -y kubectl

Устанавливаем Google Cloud SDK


Аналогично устанавливаем пакет ПО. Подробнее тут.

# Add the Cloud SDK distribution URI as a package sourceecho "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list# Import the Google Cloud Platform public keycurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -# Update the package list and install the Cloud SDKsudo apt-get update && sudo apt-get install google-cloud-sdk

Устанавливаем Percona DBaaS CLI


Устанавливаем из репозиториев Percona. Percona DBaaS CLI Tool продукт пока экспериментальный, поэтому находится в экспериментальном репозитории, который нужно включить отдельно, даже если у вас уже установлены репозитории Percona.

Подробнее тут.

Алгоритм установки:

  1. Настройте репозитории Percona с помощью инструмента percona-release. Сначала вам нужно скачать и установить официальный пакет percona-release от Percona:

    wget https://repo.percona.com/apt/percona-release_latest.generic_all.debsudo dpkg -i percona-release_latest.generic_all.deb
    
  2. Включите экспериментальный компонент репозитория инструментов следующим образом:

    sudo percona-release enable tools experimental
    
  3. Установите percona-dbaas-cli пакет:

    sudo apt-get updatesudo apt-get install percona-dbaas-cli
    

Настраиваем работу компонентов


Подробнее о настройках тут.

Сначала нужно залогиниться в аккаунт Google. Дальше Google Cloud позволяет одному пользователю иметь много независимых проектов, поэтому требуется указать рабочий проект, используя код этого проекта:

gcloud auth logingcloud config set project hidden-brace-236921

Далее создаем кластер. Для демо я создал Kubernetes-кластер всего из трех нодов это минимум, который требуется для высокой доступности:

gcloud container clusters create --zone us-central1-a your-cluster-name --cluster-version 1.15 --num-nodes=3

Следующая команда kubectl дает нужные привилегии нашему текущему пользователю:

kubectl create clusterrolebinding cluster-admin-binding-$USER --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)

Затем мы создаем namespace и делаем его активным. Namespace это, грубо говоря, тоже как проект или environment, но уже внутри Kubernetes-кластера. Он независим от проектов Google Cloud:

kubectl create namespace my-namespacekubectl config set-context --current --namespace=my-namespace

Запускаем кластер


После того, как мы прошли через эти несколько шагов, можем запустить кластер из трех узлов вот такой простой командой:

# percona-dbaas mysql create-db exampleStarting ......................................... [done]Database started successfully, connection details are below:Provider:          k8sEngine:            pxcResource Name:     exampleResource Endpoint: example-proxysql.my-namespace.pxc.svc.localPort:              3306User:              rootPass:              Nt9YZquajW7nfVXTTrPStatus:            ready

Как подключиться к кластеру


По умолчанию он доступен только внутри Kubernetes. То есть с этого сервера, с которого вы запустили команду Создать, он не доступен. Чтобы он стал доступен, например для тестов с клиентом, нужно прокинуть порт через Port Mapping:

kubectl port-forward svc/example-proxysql 3306:3306 $

Потом подключаем ваш MySQL-клиент:

mysql -h 127.0.0.1 -P 3306 -uroot -pNt9YZquajW7nfVXTTrP

Продвинутые команды управления кластером


База данных на публичном IP


Если хочется более постоянного решения для доступности кластера, можно получить внешний IP-адрес. В этом случае база данных будет доступна откуда угодно. Это менее безопасно, но часто более удобно. Для внешнего IP используем следующую команду:

# percona-dbaas mysql create-db exposed --options="proxysql.serviceType=LoadBalancer"Starting ......................................... [done]Database started successfully, connection details are below:Provider:          k8sEngine:            pxcResource Name:     exposedResource Endpoint: 104.154.133.197Port:              3306User:              rootPass:              k0QVxTr8EVfgyCLYseStatus:            readyTo access database please run the following command:mysql -h 104.154.133.197 -P 3306 -uroot -pk0QVxTr8EVfgyCLYse

Явно задаем пароль


Вместо того, чтобы система генерировала пароль случайным образом, вы можете задать пароль явно:

# percona-dbaas mysql create-db withpw --password=mypasswordStarting ......................................... [done]Database started successfully, connection details are below:Provider:          k8sEngine:            pxcResource Name:     withpwResource Endpoint: withpw-proxysql.my-namespace.pxc.svc.localPort:              3306User:              rootPass:              mypasswordStatus:            ready

Я показываю вывод скриптов в читабельном формате, но также поддерживается формат JSON.

Выключаем высокую доступность


Следующей командой можно выключить высокую доступность, чтобы развернуть single node:

# percona-dbaas mysql create-db singlenode --options="proxysql.enabled=false, allowUnsafeConfigurations=true,pxc.size=1"Starting ......................................... [done]Database started successfully, connection details are below:Provider:          k8sEngine:            pxcResource Name:     singlenodeResource Endpoint: singlenode-pxc.my-namespace.pxc.svc.localPort:              3306User:              rootPass:              22VqFD96mvRnmPMGgStatus:            ready

Это решение для тестовых задач, чтобы максимально быстро и просто поднять MySQL, протестировать, а потом свернуть или использовать для разработки.

Инструмент Percona DBaaS CLI помогает получить решение на Kubernetes, подобное DBaaS. При этом мы продолжаем работать над его функционалом и юзабилити.

Этот доклад впервые прозвучал на @Databases Meetup by Mail.ru Cloud Solutions&Tarantool. Смотрите видео других выступлений и подписывайтесь на анонсы мероприятий в Telegram Вокруг Kubernetes в Mail.ru Group.

Что еще почитать по теме:

  1. Базы данных в современной IIoT-платформе.
  2. Как выбрать базу данных для проекта, чтобы не выбирать снова.
Подробнее..

Краткий обзор операторов PostgreSQL для Kubernetes, наш выбор и опыт

25.09.2020 10:10:53 | Автор: admin


Всё чаще от клиентов поступают такие запросы: Хотим как Amazon RDS, но дешевле; Хотим как RDS, но везде, в любой инфраструктуре. Чтобы реализовать подобное managed-решение на Kubernetes, мы посмотрели на текущее состояние наиболее популярных операторов для PostgreSQL (Stolon, операторы от Crunchy Data и Zalando) и сделали свой выбор.

Эта статья полученный нами опыт и с теоретической точки зрения (обзор решений), и с практической стороны (что было выбрано и что из этого получилось). Но для начала давайте определимся, какие вообще требования предъявляются к потенциальной замене RDS

Что же такое RDS


Когда люди говорят про RDS, по нашему опыту, они подразумевают управляемый (managed) сервис СУБД, которая:

  1. легко настраивается;
  2. имеет возможность работы со снапшотами и восстанавливаться из них (желательно с поддержкой PITR);
  3. позволяет создавать топологии master-slave;
  4. имеет богатый список расширений;
  5. предоставляет аудит и управление пользователями/доступами.

Если говорить вообще, то подходы к реализации поставленной задачи могут быть весьма разными, однако путь с условным Ansible нам не близок. (К схожему выводу пришли и коллеги из 2GIS в результате своей попытки создать инструмент для быстрого развертывания отказоустойчивого кластера на основе Postgres.)

Именно операторы общепринятый подход для решения подобных задач в экосистеме Kubernetes. Подробнее о них применительно к базам данных, запускаемым внутри Kubernetes, уже рассказывал техдир Фланта, distol, в одном из своих докладов.

NB: Для быстрого создания несложных операторов рекомендуем обратить внимание на нашу Open Source-утилиту shell-operator. Используя её, можно это делать без знаний Go, а более привычными для сисадминов способами: на Bash, Python и т.п.

Для PostgreSQL существует несколько популярных K8s-операторов:

  • Stolon;
  • Crunchy Data PostgreSQL Operator;
  • Zalando Postgres Operator.

Посмотрим на них более внимательно.

Выбор оператора


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

  • деплой из Git и с Custom Resources;
  • поддержку pod anti-affinity;
  • установку node affinity или node selector;
  • установку tolerations;
  • наличие возможностей тюнинга;
  • понятные технологии и команды.

Не вдаваясь в детали по каждому из пунктов (спрашивайте в комментариях, если останутся вопросы по ним после прочтения всей статьи), отмечу в целом, что эти параметры нужны для более тонкого описания специализации узлов кластера с тем, чтобы заказывать их под конкретные приложения. Так мы можем добиться оптимального баланса в вопросах производительности и стоимости.

Теперь к самим операторам PostgreSQL.

1. Stolon


Stolon от итальянской компании Sorint.lab в уже упомянутом докладе рассматривался как некий эталон среди операторов для СУБД. Это довольно старый проект: первый его публичный релиз состоялся еще в ноябре 2015 года, а GitHub-репозиторий может похвастать почти 3000 звёздами и 40+ контрибьюторами.

И действительно, Stolon отличный пример продуманной архитектуры:



С устройством этого оператора в подробностях можно ознакомиться в докладе или документации проекта. В целом же, достаточно сказать, что он умеет всё описанное: failover, прокси для прозрачного доступа клиентов, бэкапы. Причем прокси предоставляют доступ через один сервис endpoint в отличие от двух других решений, рассмотренных дальше (у них по два сервиса для доступа к базе).

Однако у Stolon нет Custom Resources, из-за чего его нельзя так деплоить, чтобы просто и быстро как горячие пирожки создавать экземпляры СУБД в Kubernetes. Управление осуществляется через утилиту stolonctl, деплой через Helm-чарт, а пользовательские пароли задаются через ConfigMap.

С одной стороны, получается, что оператор не очень-то является оператором (ведь он не использует CRD). Но с другой это очень гибкая система, которая позволяет настраивать ресурсы в K8s так, как вам удобно.

Но лично для нас не показался оптимальным путь заводить отдельный чарт под каждую БД. Поэтому мы стали искать альтернативы.

2. Crunchy Data PostgreSQL Operator


Оператор от Crunchy Data, молодого американского стартапа, выглядел логичной альтернативой. Его публичная история начинается с первого релиза в марте 2017 года, с тех пор GitHub-репозиторий получил чуть менее 1300 звёзд и 50+ контрибьюторов. Последний релиз от сентября был протестирован на работу с Kubernetes 1.151.18, OpenShift 3.11+ и 4.4+, GKE и VMware Enterprise PKS 1.3+.

Архитектура Crunchy Data PostgreSQL Operator также соответствует нашим требованиям:



Управление происходит через утилиту pgo, однако она в свою очередь генерирует Custom Resources для Kubernetes. Поэтому с точки зрения потенциальных пользователей оператор нас порадовал:

  • есть управление через CRD;
  • удобное управление пользователями (тоже через CRD);
  • интеграция с другими компонентами Crunchy Data Container Suite специализированной коллекции образов контейнеров для PostgreSQL и утилит для работы с ней (включая pgBackRest, pgAudit, расширения из contrib и т.д.).

Однако попытки начать использовать оператор выявили несколько проблем:

  • Не оказалось возможности tolerations предусмотрен только nodeSelector.
  • Создаваемые podы были частью Deploymentа, несмотря на то, что мы деплоили stateful-приложение. В отличие от StatefulSet, Deploymentы не умеют создавать диски.

Последний недостаток приводит к забавным моментам: на тестовой среде удалось запустить 3 реплики с одним диском localstorage, в результате чего оператор сообщал, что 3 реплики работают (хотя это было не так).

Еще одной особенностью этого оператора является его готовая интеграция с различными вспомогательными системами. Например, легко установить поставить pgAdmin и pgBounce, а в документации рассматриваются преднастроенные Grafana и Prometheus. В недавнем релизе 4.5.0-beta1 отдельно отмечается улучшенная интеграция с проектом pgMonitor, с которой оператор предлагает визуализацию метрик по PgSQL из коробки.

Тем не менее, странный выбор генерируемых Kubernetes-ресурсов привел нас к необходимости найти иное решение.

3. Zalando Postgres Operator


Продукты Zalando нам известны давно: есть опыт использования Zalenium и, конечно, мы пробовали Patroni их популярное HA-решение для PostgreSQL. О подходе компании к созданию Postgres Operator рассказывал один из его авторов Алексей Клюкин в эфире Postgres-вторника 5, и нам он приглянулся.

Это самое молодое решение из рассматриваемых в статье: первый релиз состоялся в августе 2018 года. Однако, даже несмотря на небольшое количество формальных релизов, проект прошёл большой путь, уже опередив по популярности решение от Crunchy Data (1300+ звёзд на GitHub) и максимальное число контрибьюторов (70+). Под капотом этого оператора используются решения, проверенные временем: Patroni и Spilo для управления, WAL-E для бэкапов, PgBouncer в качестве пула подключений.

Вот как представлена архитектура оператора от Zalando:



Оператор полностью управляется через Custom Resources, автоматически создает StatefulSet из контейнеров, которые затем можно кастомизировать, добавляя в pod различные sidecarы. Всё это значительный плюс в сравнении с оператором от Crunchy Data.

Поскольку именно решение от Zalando мы выбрали среди 3 рассматриваемых вариантов, дальнейшее описание его возможностей будет представлено ниже, сразу вместе с практикой применения.

Практика с Postgres Operator от Zalando


Деплой оператора происходит очень просто: достаточно скачать актуальный релиз с GitHub и применить YAML-файлы из директории manifests. Как вариант, можно также воспользоваться OperatorHub.

После установки стоит озаботиться настройкой хранилищ для логов и бэкапов. Она производится через ConfigMap postgres-operator в пространстве имен, куда вы установили оператор. Когда хранилища настроены, можно развернуть первый кластер PostgreSQL.

Например, стандартный деплой у нас выглядит следующим образом:

apiVersion: acid.zalan.do/v1kind: postgresqlmetadata: name: staging-dbspec: numberOfInstances: 3 patroni:   synchronous_mode: true postgresql:   version: "12" resources:   limits:     cpu: 100m     memory: 1Gi   requests:     cpu: 100m     memory: 1Gi sidecars: - env:   - name: DATA_SOURCE_URI     value: 127.0.0.1:5432   - name: DATA_SOURCE_PASS     valueFrom:       secretKeyRef:         key: password         name: postgres.staging-db.credentials   - name: DATA_SOURCE_USER     value: postgres   image: wrouesnel/postgres_exporter   name: prometheus-exporter   resources:     limits:       cpu: 500m       memory: 100Mi     requests:       cpu: 100m       memory: 100Mi teamId: staging volume:   size: 2Gi

Данный манифест деплоит кластер из 3 экземпляров с sidecar в виде postgres_exporter, с которого мы снимаем метрики приложения. Как видите, всё очень просто, и при желании можно сделать буквально неограниченное количество кластеров.

Стоит обратить внимание и на веб-панель для администрирования postgres-operator-ui. Она поставляется вместе с оператором и позволяет создавать и удалять кластеры, а также позволяет работать с бэкапами, которые делает оператор.


Список кластеров PostgreSQL


Управление бэкапами

Другой интересной особенностью является поддержка Teams API. Данный механизм автоматически создаёт роли в PostgreSQL, исходя из полученного списка имён пользователей. После этого API позволяет вернуть список пользователей, для которых автоматически создаются роли.

Проблемы и их решение


Однако использование оператора вскоре выявило несколько весомых недостатков:

  1. отсутствие поддержки nodeSelector;
  2. невозможность отключить бэкапы;
  3. при использовании функции создания баз не создаются привилегии по умолчанию;
  4. периодически не хватает документации или же она находится в неактуальном состоянии.

К счастью, многие из них могут быть решены. Начнём с конца проблем с документацией.

Скорее всего вы столкнетесь с тем, что не всегда ясно, как прописать бэкап и как подключить бэкапный бакет к Operator UI. Об этом в документации говорится вскользь, а реальное описание есть в PR:

  1. нужно сделать секрет;
  2. передать его оператору в параметр pod_environment_secret_name в CRD с настройками оператора или в ConfigMap (зависит от того, как вы решили устанавливать оператор).

Однако, как оказалось, на текущий момент это невозможно. Именно поэтому мы собрали свою версию оператора с некоторыми дополнительными сторонними наработками. Подробнее о ней см. ниже.

Если передавать оператору параметры для бэкапа, а именно wal_s3_bucket и ключи доступа в AWS S3, то он будет бэкапить всё: не только базы в production, но и staging. Нас это не устроило.

В описании параметров к Spilo, что является базовой Docker-обёрткой для PgSQL при использовании оператора, выяснилось: можно передать параметр WAL_S3_BUCKET пустым, тем самым отключив бэкапы. Более того, к большой радости нашёлся и готовый PR, который мы тут же приняли в свой форк. Теперь достаточно просто добавить enableWALArchiving: false в ресурс кластера PostgreSQL.

Да, была возможность сделать иначе, запустив 2 оператора: один для staging (без бэкапов), а второй для production. Но так мы смогли обойтись одним.

Ок, мы научились передавать в базы доступ для S3 и бэкапы начали попадать в хранилище. Как заставить работать страницы бэкапов в Operator UI?



В Operator UI потребуется добавить 3 переменные:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

После этого управление бэкапами станет доступно, что в нашем случае упростит работу со staging, позволив доставлять туда срезы с production без дополнительных скриптов.

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

Почему так? Несмотря на то, что в коде есть необходимые GRANT, они применяются далеко не всегда. Есть 2 метода: syncPreparedDatabases и syncDatabases. В syncPreparedDatabases несмотря на то, что в секции preparedDatabases есть есть условие defaultRoles и defaultUsers для создания ролей, права по умолчанию не применяются. Мы в процессе подготовки патча, чтобы данные права автоматически применялись.

И последний момент в актуальных для нас доработках патч, добавляющий Node Affinity в создаваемый StatefulSet. Наши клиенты зачастую предпочитают сокращать расходы, используя spot-инстансы, а на них явно не стоит размещать сервисы БД. Этот вопрос можно было бы решить и через tolerations, но наличие Node Affinity даёт большую уверенность.

Что получилось?


По итогам решения перечисленных проблем мы форкнули Postgres Operator от Zalando в свой репозиторий, где он собирается со столь полезными патчами. А для пущего удобства собрали и Docker-образ.

Список PR, принятых в форк:


Будет здорово, если сообщество поддержит эти PR, чтобы они попали в следующую версию оператора (1.6).

Бонус! История успеха с миграцией production


Если вы используете Patroni, на оператор можно мигрировать живой production с минимальным простоем.

Spilo позволяет делать standby-кластеры через S3-хранилища с Wal-E, когда бинарный лог PgSQL сначала сохраняется в S3, а затем выкачивается репликой. Но что делать, если у вас не используется Wal-E в старой инфраструктуре? Решение этой проблемы уже было предложено на хабре.

На помощь приходит логическая репликация PostgreSQL. Однако не будем вдаваться в детали, как создавать публикации и подписки, потому что наш план потерпел фиаско.

Дело в том, что в БД было несколько нагруженных таблиц с миллионами строк, которые, к тому же, постоянно пополнялись и удалялись. Простая подписка с copy_data, когда новая реплика копирует всё содержимое с мастера, просто не успевала за мастером. Копирование контента работало неделю, но так и не догнало мастер. В итоге, разобраться с проблемой помогла статья коллег из Avito: можно перенести данные, используя pg_dump. Опишу наш (немного доработанный) вариант этого алгоритма.

Идея заключается в том, что можно сделать выключенную подписку, привязанную к конкретному слоту репликации, а затем исправить номер транзакции. В наличии были реплики для работы productionа. Это важно, потому что реплика поможет создать консистентный dump и продолжить получать изменения из мастера.

В последующих командах, описывающих процесс миграции, будут использоваться следующие обозначения для хостов:

  1. master исходный сервер;
  2. replica1 потоковая реплика на старом production;
  3. replica2 новая логическая реплика.

План миграции


1. Создадим на мастере подписку на все таблицы в схеме public базы dbname:

psql -h master -d dbname -c "CREATE PUBLICATION dbname FOR ALL TABLES;"

2. Cоздадим слот репликации на мастере:

psql -h master -c "select pg_create_logical_replication_slot('repl', 'pgoutput');"

3. Остановим репликацию на старой реплике:

psql -h replica1 -c "select pg_wal_replay_pause();"

4. Получим номер транзакции с мастера:

psql -h master -c "select replay_lsn from pg_stat_replication where client_addr = 'replica1';"

5. Снимем dump со старой реплики. Будем делать это в несколько потоков, что поможет ускорить процесс:

pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump/ dbname

6. Загрузим dump на новый сервер:

pg_restore -h replica2 -F d -j 8 -d dbname dump/

7. После загрузки дампа можно запустить репликацию на потоковой реплике:

psql -h replica1 -c "select pg_wal_replay_resume();"

7. Создадим подписку на новой логической реплике:

psql -h replica2 -c "create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');"

8. Получим oid подписки:

psql -h replica2 -d dbname -c "select oid, * from pg_subscription;"

9. Допустим, был получен oid=1000. Применим номер транзакции к подписке:

psql -h replica2 -d dbname -c "select pg_replication_origin_advance('pg_1000', 'AA/AAAAAAAA');"

10. Запустим репликацию:

psql -h replica2 -d dbname -c "alter subscription oldprod enable;"

11. Проверим статус подписки, репликация должна работать:

psql -h replica2 -d dbname -c "select * from pg_replication_origin_status;"psql -h master -d dbname -c "select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;"

12. После того, как репликация запущена и базы синхронизированы, можно совершать переключение.

13. После отключения репликации надо исправить последовательности. Это хорошо описано в статье на wiki.postgresql.org.

Благодаря такому плану переключение прошло с минимальными задержками.

Заключение


Операторы Kubernetes позволяют упростить различные действия, сведя их к созданию K8s-ресурсов. Однако, добившись замечательной автоматизации с их помощью, стоит помнить, что она может принести и ряд неожиданных нюансов, поэтому подходите к выбору операторов с умом.

Рассмотрев три самых популярных Kubernetes-оператора для PostgreSQL, мы остановили свой выбор на проекте от Zalando. И с ним пришлось преодолеть определенные трудности, но результат действительно порадовал, так что мы планируем расширить этот опыт и на некоторые другие инсталляции PgSQL. Если у вас есть опыт использования схожих решений будем рады увидеть подробности в комментариях!

P.S.


Читайте также в нашем блоге:

Подробнее..

Обзор операторов PostgreSQL для Kubernetes. Часть 2 дополнения и итоговое сравнение

13.11.2020 10:21:32 | Автор: admin


На прошлую статью, где мы рассмотрели три оператора PostgreSQL для Kubernetes (Stolon, Crunchy Data и Zalando), поделились своим выбором и опытом эксплуатации, поступила отличная обратная связь от сообщества*.

Продолжая эту тему, мы добавили в обзор два других решения, на которые нам указали в комментариях: StackGres и KubeDB, и сделали сводную таблицу сравнения. Также за время эксплуатации оператора от Zalando у нас появились новые интересные кейсы спешим поделиться и ими.

* Первую часть статьи заметили даже разработчики Zalando, благодаря чему(?) они решили активизироваться в приёме некоторых PR. Это не может не радовать!



Итак, сначала дополним обзор ещё двумя решениями

KubeDB




Оператор KubeDB разрабатывается командой AppsCode c 2017 года и хорошо известен в Kubernetes-сообществе. Он претендует на звание платформы для запуска различных stateful-сервисов в Kubernetes и поддерживает:

  • PostgreSQL;
  • Elasticsearch;
  • MySQL;
  • MongoDB;
  • Redis;
  • Memcache.

Однако в контексте статьи мы рассмотрим только PostgreSQL.

В KubeDB реализован интересный подход с использованием нескольких CRD, которые содержат в себе различные настройки, такие как:

  • версия с образом базы и вспомогательными утилитами за это отвечает ресурс postgresversions.catalog.kubedb.com;
  • параметры восстановления ресурс бэкапа <codesnapshots.kubedb.com

собственно, корневой ресурс postgreses.kubedb.com, который собирает в себе все эти ресурсы и запускает кластер PostgreSQL.

Особой кастомизации KubeDB не предоставляет (в отличие от оператора Zalando), но вы всегда можете управлять конфигом PostgreSQL через ConfigMap.

Интересной особенностью является ресурс dormantdatabases.kubedb.com, который предоставляет защиту от дурака: все удалённые базы сначала переводятся в такое архивное состояние и могут быть легко восстановлены в случае необходимости. Жизненный цикл БД в KubeDB описывается следующей схемой:



Что же касается самого технологического стека, то тут используются свои наработки для управления кластерами, а не знакомые всем Patroni или Repmgr. Хотя для полинга соединений используется pgBouncer, который также создается отдельным CRD (pgbouncers.kubedb.com). Кроме того, разработчики предоставляют плагин для kubectl, который позволяет удобно управлять базами через всем привычную утилиту, и это огромный плюс на фоне Stolon или Crunchy Data.

KubeDB интегрируется с другими решениями AppsCode, чем напоминает Crunchy Data. Если вы везде используете решения этого вендора, то KubeDB, безусловно, отличный выбор.

Наконец, хочется отметить отличную документацию этого оператора, которая находится в отдельном репозитории GitHub. В ней есть развернутые примеры использования, включая полные примеры конфигураций CRD.

Есть минусы у KubeDB. Многие возможности: бэкапы, полинг соединений, снапшоты, dormant-базы доступны только в enterprise-версии, а для её использования требуется купить подписку у AppsCode. Кроме того, самой старшей поддерживаемой версией PostgreSQL из коробки является 11.x. Перечеркивают ли эти моменты изящную архитектуру KubeDB решать вам.

StackGres




В твиттере и в комментариях к предыдущей статье нам резонно указали на оператор StackGres. Разработка данного оператора началась совсем недавно, в мае 2019 году. В нем используются известные и проверенные технологии: Patroni, PgBouncer, WAL-G и Envoy.

Общая схема оператора выглядит так:



Кроме того, в комплекте с оператором можно установить:

  • веб-панель, как в Zalando;
  • систему сбора логов;
  • систему мониторинга, аналогичную Crunchy Data, о которой мы говорили в первой части;
  • систему сбора бэкапов на основе MinIO, хотя можно подключить и внешнее хранилище.

В целом же, данный оператор использует подход, очень схожий с KubeDB: он предоставляет сразу несколько ресурсов для описания компонентов кластера, создания конфигов и задания ресурсов.

Вкратце про все CRD:

  • sgbackupconfigs.stackgres.io, sgpgconfigs.stackgres.io, sgpoolconfigs.stackgres.io описание кастомных конфигов;
  • sginstanceprofiles.stackgres.io размер инстанса Postgres, который будет использоваться как limit/request для контейнера с PostgreSQL/Patroni. Для остальных контейнеров лимитов нет;
  • sgclusters.stackgres.io когда есть конфигурации для базы, пула коннектов и бэкапа, можно создать кластер PostgreSQL, который описывается этим CRD;
  • sgbackups.stackgres.io ресурс, схожий со snapshot у KubeDB и позволяющий обратиться к конкретному бэкапу из кластера K8s.

Однако оператор не позволяет использовать свои кастомные сборки образов или же несколько вспомогательных sidecar для сервера баз данных. Pod c Postgres содержит 5 контейнеров:



Из них мы можем отключить экспортер метрик, пулер коннектов и контейнер со вспомогательными утилитами администратора (psql, pg_dump и так далее). Да, оператор позволяет при инициализации кластера баз данных подключить скрипты с SQL-кодом для инициализации БД или создания пользователей, но не более того. Это сильно ограничивает нас в кастомизации, например, в сравнении с тем же оператором Zalando, где можно добавлять нужные sidecar с Envoy, PgBouncer и любыми другими вспомогательными контейнерами (хороший пример подобной связки будет ниже).

Подводя итог, можно сказать, что этот оператор понравится тем, кто хочет просто управлять PostgreSQL в кластере Kubernetes. Отличный выбор для тех, кому нужен инструмент с простой документацией, покрывающей все аспекты работы оператора, и кому не нужно делать сложные связки контейнеров и баз.

Итоговое сравнение


Мы знаем, что наши коллеги нежно любят сводные таблицы, поэтому приводим подобную для Postgres-операторов в Kubernetes.

Забегая вперед: после рассмотрения двух дополнительных кандидатов мы остаёмся при мнении, что решение от Zalando оптимальный для нашего случая продукт, так как позволяет реализовывать очень гибкие решения, имеет большой простор для кастомизации.

В таблице первая часть посвящена сравнению основных возможностей работы с БД, а вторая более специфичным особенностям, следуя нашему пониманию об удобстве работы с оператором в Kubernetes.

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

Stolon Crunchy Data Zalando KubeDB StackGres
Текущая версия 0.16.0 4.5.0 1.5.0 0.13 0.9.2
Версии PostgreSQL 9.49.6, 10, 11, 12 9.5, 9.6, 10, 11, 12 9.6, 10, 11, 12 9.6, 10, 11 11, 12
Общие возможности
Кластеры PgSQL
Теплый и горячий резерв
Синхронная репликация
Потоковая репликация
Автоматический failover
Непрерывное архивирование
Инициализация: из WAL-архива
Бэкапы: мгновенные, по расписанию
Бэкапы: управляемость из кластера
Инициализация: из снапшота, со скриптами
Специализированные возможности
Встроенная поддержка Prometheus
Кастомная конфигурация
Кастомный Docker-образ
Внешние CLI-утилиты
(kubectl-плагин)
Конфигурация через CRD
Кастомизация Pod'ов
NodeSelector и NodeAffinity
(через патчи)
Tolerations
Pod anti-affinity

Бонусы про оператор от Zalando


Ежедневно пользуясь решением от Zalando, мы столкнулись с некоторыми сложностями, и этим опытом хотелось бы поделиться с сообществом.

1. Приватные репозитории


Недавно нам потребовалось запустить через оператор наряду с PostgreSQL контейнер с SFTP, который позволил бы получать выгрузки из базы в формате CSV. Сам SFTP-сервер со всеми нужными параметрами был собран в закрытом registry.

И тут стало ясно, что оператор не умеет работать с registry secrets. К счастью, с такой проблемой мы были не одни с такой проблемой: все легко решилось коллегами на GitHub. Оказалось, что достаточно добавить в описание ServiceAccount имя с доступами в registry:

pod_service_account_definition: '{ "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "name": "zalando-postgres-operator" }, "imagePullSecrets": [ { "name": "my-fine-secret" } ] }'

2. Дополнительные хранилища и init-контейнеры


Для работы SFTP нам также требовалось корректно выставлять права на директории, чтобы заработал chroot. Возможно, не все знают, но OpenSSH-сервер требует особых привилегий на директории. Например, чтобы пользователь видел только свой /home/user, необходимо, чтобы /home принадлежал root с правами 755, а уже /home/user был доступен пользователю. Соответственно, мы решили использовать init-контейнер, который исправлял бы права на директории.

Но оператор не умеет пробрасывать дополнительные диски в init-контейнеры! Благо, есть подходящий PR, которым мы и дополнили свою сборку оператора.

3. Перезапуск PgSQL при проблемах с control plane


В процессе эксплуатации кластеров на основе Patroni в Kubernetes мы получили от клиента странную проблему: ровно в 4 часа ночи по Москве обрывались все подключения PostgeSQL. Разбираясь в ситуации, мы обнаружили следующее в логах Spilo:

2020-10-21 01:01:10,538 INFO: Lock owner: production-db-0; I am production-db-02020-10-21 01:01:14,759 ERROR: failed to update leader lock2020-10-21 01:01:15,236 INFO: demoted self because failed to update leader lock in DCS2020-10-21 01:01:15,238 INFO: closed patroni connection to the postgresql cluster2020-10-21 01:01:15 UTC [578292]: [1-1] 5f8f885b.8d2f4 0     LOG:  Auto detecting pg_stat_kcache.linux_hz parameter...

Согласно issue на GitHub, это означает, что Patoni не смог обработать ошибку Kubernetes API и упал с ошибкой. А проблемы с API были связаны с тем, что в 4 часа стартовали сразу 50 CronJob, что приводило к проблемам в etcd:

2020-10-21 01:01:14.589198 W | etcdserver: read-only range request "key:\"/registry/deployments/staging/db-worker-db1\" " with result "range_response_count:1 size:2598" took too long (3.688609392s) to execute

Ситуация исправлена в версии Patroni 2.0. По этой причине мы собрали версию Spilo из мастера. При сборке стоит учитывать, что требуется взять PR с исправлениями сборки, который на данный момент уже принят в мастер.

4. Пересоздание контейнеров


Напоследок, еще одна интересная проблема. В последнем релизе в оператор была добавлена возможность делать sidecar-контейнеры с их полным описанием в CRD оператора. Разработчики заметили, что базы периодически перезапускаются. В логах оператора было следующее:

time="2020-10-28T20:58:25Z" level=debug msg="spec diff between old and new statefulsets: \nTemplate.Spec.Volumes[2].VolumeSource.ConfigMap.DefaultMode: &int32(420) != nil\nTemplate.Spec.Volumes[3].VolumeSource.ConfigMap.DefaultMode: &int32(420) != nil\nTemplate.Spec.Containers[0].TerminationMessagePath: \"/dev/termination-log\" != \"\"\nTemplate.Spec.Containers[0].TerminationMessagePolicy: \"File\" != \"\"\nTemplate.Spec.Containers[1].Ports[0].Protocol: \"TCP\" != \"\"\nTemplate.Spec.Containers[1].TerminationMessagePath: \"/dev/termination-log\" != \"\"\nTemplate.Spec.Containers[1].TerminationMessagePolicy: \"File\" != \"\"\nTemplate.Spec.RestartPolicy: \"Always\" != \"\"\nTemplate.Spec.DNSPolicy: \"ClusterFirst\" != \"\"\nTemplate.Spec.DeprecatedServiceAccount: \"postgres-pod\" != \"\"\nTemplate.Spec.SchedulerName: \"default-scheduler\" != \"\"\nVolumeClaimTemplates[0].Status.Phase: \"Pending\" != \"\"\nRevisionHistoryLimit: &int32(10) != nil\n" cluster-name=test/test-psql pkg=cluster worker=0

Ни для кого не секрет, что при создании контейнера и podа добавляются директивы, которые не обязательно описывать. К ним относятся:

  • DNSPolicy;
  • SchedulerName;
  • RestartPolicy;
  • TerminationMessagePolicy;

Логично предположить, чтобы такое поведение учитывалось в операторе, однако, как оказалось, он плохо воспринимает секцию портов:

    ports:    - name: sftp      containerPort: 22

При создании podа автоматически добавляется протокол TCP, что не учитывается оператором. Итог: чтобы решить проблему, надо или удалить порты, или добавить протокол.

Заключение


Управление PostgreSQL в рамках Kubernetes нетривиальная задача. Пожалуй, на текущий момент на рынке нет оператора, который покрывал бы все потребности DevOps-инженеров. Однако среди уже существующих инструментов есть продвинутые и довольно зрелые варианты, из которых можно выбрать то, что лучше всего соответствует имеющимся потребностям.

Наш опыт говорит о том, что не стоит ждать стремительного и магического решения всех проблем. Тем не менее, мы в целом довольны имеющимся результатом, пусть он и требует периодического внимания с нашей стороны.

Говоря же об операторах, рассмотренных в этой части статьи (KubeDB и StackGres), стоит отметить, что они оснащены уникальными функциями для управления бэкапами из кластера, что может стать одним из факторов роста их популярности в ближайшем будущем.

P.S.


Читайте также в нашем блоге:

Подробнее..

Прогресс shell-operator и addon-operator хуки как admission webhooks, Helm 3, OpenAPI, хуки на Go и многое другое

18.01.2021 10:10:41 | Автор: admin

Shell-operator и addon-operator Open Source-проекты компании Флант для администраторов Kubernetes, представленные в апреле 2019 года. Первый призван упростить создание K8s-операторов: для этого с ним достаточно писать простые скрипты (на Bash, Python и т.п.) или любые бинарники, которые будут вызываться в случае наступления определённых событий в Kubernetes API. Второй (addon-operator) его старший брат, цель которого упростить установку Helm-чартов в кластер, используя для их настройки хуки shell-operatorа.

В последний раз мы рассказывали о возможностях shell-operator по состоянию на релиз v1.0.0-beta.11 (летом прошлого года), если не считать последовавшего доклада на KubeCon EU2020, который знакомил с проектом тех, кто о нём ещё не знает. (К слову, этот доклад мы по-прежнему рекомендуем всем желающим разобраться, как shell-operator облегчает жизнь при создании операторов, и увидеть наглядные примеры его применения.)

За минувшее время и shell-operator, и addon-operator получили множество интересных новшеств, которым и посвящена эта статья.

Изменения в shell-operator v1.0.0-rc1

Хуки для shell-operator теперь можно использовать как обработчики для ValidatingWebhookConfiguration одного из вариантов admission webhook. Т.е. хук может проверить ресурс Kubernetes во время создания или редактирования и отклонить операцию, если ресурс не соответствует каким-то правилам. Таким правилом может быть такая политика: можно создавать только ресурсы с образом из repo.example.com. Пример реализации подобной политики можно посмотреть в директории 204-validating-webhook. Shell-operator поддерживает такие хуки для кластеров Kubernetes с версией не ниже 1.16.

Иллюстрация того, как происходит конфигурация такого хука (фрагмент shell-хука из примера выше):

function __config__(){    cat <<EOFconfigVersion: v1kubernetesValidating:- name: private-repo-policy.example.com  namespace:    labelSelector:      matchLabels:        # helm adds a 'name' label to a namespace it creates        name: example-204  rules:  - apiGroups:   ["stable.example.com"]    apiVersions: ["v1"]    operations:  ["CREATE", "UPDATE"]    resources:   ["crontabs"]    scope:       "Namespaced"EOF}

Другое новшество группу произвольных метрик теперь можно удалить, вернув ключ action:

{"group":"group_name_1", "action":"expire"}

Это удобно, когда пропадают объекты, сведения о которых были в метриках. Подробный пример разобран в документации.

Остальные значимые нововведения в shell-operator разбиты на категории:

1. Улучшения в потреблении ресурсов и производительности

  • Период ресинхронизации информеров теперь случайно распределён во времени. Без распределения все информеры одновременно обращались к API-серверу, что периодически создавало лишнюю нагрузку.

  • Введена экспоненциально возрастающая задержка между повторными запусками ошибочного хука.

  • В операциях на чтение в очередях сделаны read-only-локи вместо общего лока и на запись, и на чтение.

  • Добавлены метрики с процессорным временем и с потреблением памяти для каждого хука (см. shell_operator_hook_run_sys_cpu_seconds в METRICS).

2. Изменения в сборке образа

  • Теперь flant/shell-operator это образ с поддержкой архитектур AMD64, ARM и ARM64 (привет любителям Raspberry Pi!).

  • Бинарный файл shell-operator собирается статически и должен работать в любом Linux-дистрибутиве.

  • Образ flant/shell-operator с Bash, kubectl и jq теперь только на основе Alpine. Если требуется другой дистрибутив, то бинарный файл можно взять из основного образа, а Dockerfile есть в примерах.

  • Убрана директория .git, попавшая в образ по ошибке.

  • Обновлены версии инструментов: Alpine 3.12, kubectl 1.19.4, Go 1.15.

  • Бинарный файл jq собран из того же коммита, что и libjq*, чтобы устранить проблемы производительности jq-1.6 (#206).

* Кстати, libjq-go это наш небольшой Open Source-проект, предлагающий CGO bindings для jq. Он был создан для нужд shell-operator, но недавно мы встретили и другой пример его использования в проекте Xbus. Это платформа французской компании для интеграции enterprise-систем, построенная поверх NATS. Здорово видеть, когда Open Source сам делает своё полезное дело даже в небольших проектах, от которых ничего особого не ожидаешь.

3. Менее значимые изменения

  • В лог при старте записываются предупреждения про файлы хуков без флага исполнения (+x).

  • Проект можно собирать без включения CGO. Теперь удобно использовать shell-operator в других проектах, если быстрый обработчик jqFilter не нужен.

  • Добавлен shell_lib.sh, чтобы подключать shell framework одной строкой. Пример использования этой библиотеки мы демонстрировали в уже упомянутом докладе на KubeCon.

Новости addon-operator

Последний релиз addon-operator состоялся в начале прошлого года, с тех пор в нем было по-настоящему много изменений.

Одно из главных поддержка схем OpenAPI для values. Можно задавать контракты для values, которые нужны для Helm, и для config values, которые хранятся в ConfigMap и используются для конфигурации модулей пользователем.

Например, такая схема определяет два обязательных поля для глобальных values (project и clusterName), а также два опциональных поля (строка clusterHostname и объект discovery без ограничений по ключам):

# /global/openapi/config-values.yamltype: objectadditionalProperties: falserequired:  - project  - clusterNameminProperties: 2properties:  project:    type: string  clusterName:    type: string  clusterHostname:    type: string  discovery:    type: object

Подробнее см. в документации.

Ещё одно знаковое событие экспериментальная поддержка написания хуков на языке Go. Для их работы придётся компилировать свой addon-operator, добавив импорты с путями к хукам. Пример их использования можно найти в каталоге 700-go-hooks.

Иллюстрация глобального хука на Go из примера выше:

package global_hooksimport "github.com/flant/addon-operator/sdk"var _ = sdk.Register(&GoHook{})type GoHook struct {sdk.CommonGoHook}func (h *GoHook) Metadata() sdk.HookMetadata {return h.CommonMetadataFromRuntime()}func (h *GoHook) Config() *sdk.HookConfig {return h.CommonGoHook.Config(&sdk.HookConfig{YamlConfig: `configVersion: v1onStartup: 10`,MainHandler: h.Main,})}func (h *GoHook) Main(input *sdk.BindingInput) (*sdk.BindingOutput, error) {input.LogEntry.Infof("Start Global Go hook")return nil, nil}

Реализация соответствующего SDK пока находится на уровне альфа-версии и не может похвастать достаточной документацией, но если вас заинтересовала такая возможность смело спрашивайте в комментариях, а лучше приходите в Tg-канал @kubeoperator.

Среди других ключевых изменений в addon-operator выделим следующие:

  • Поддержка установки модулей с помощью Helm 3.

  • Введены понятия сходимости и сходимости при старте это название цикла рестарта всех модулей. Добавлен endpoint для readiness-пробы: Pod addon-operatorа переводится в состояние Ready, когда прошёл первый старт всех модулей, т.е. сходимость при старте достигнута.

  • Возможность включать модули из глобальных хуков, благодаря чему теперь проще регулировать состав модулей (ранее отключить модуль можно было только enabled-скриптом самого модуля).

  • Запуск информеров и запуск Synchronization для Kubernetes-хуков теперь производится в отдельных очередях, а также появилась возможность отключить ожидание выполнения таких хуков при старте.

  • Сборка образа изменена аналогично shell-operatorу: Alpine в качестве основы, мультиплатформенный образ, статический бинарный файл и т.д.

  • Доступно больше метрик для мониторинга состояния подробнее в METRICS.

Также в addon-operator перекочевали многие улучшения из shell-operator, была актуализирована документация и сделаны другие мелкие правки. В данный момент заканчиваются работы по поддержке схем OpenAPI, после чего будет опубликован релиз v1.0.0-rc1.

Новые применения shell-operator

За минувшее время shell-operator обрёл не только новые возможности, но и новых пользователей. Среди них отметим следующие известные нам проекты:

  • В Confluent сделали проект Kafka DevOps. В нём реализована модель production-окружения, в котором запущено streaming-приложение, пишущее в Apache Kafka на Confluent Cloud. Это окружение построено на основе Kubernetes, приложения и ресурсы в котором управляются в духе декларативной инфраструктуры. В частности, для этого реализованы операторы (Confluent Cloud Operator и Kafka Connect Operator) на основе на shell-operator. Подробнее об этом проекте можно почитать в блоге авторов, а совсем недавно они даже выпустили подкаст, где рассказывают о своём Kafka DevOps.

  • Образовательный проект edukates подготовил практическое занятие по shell-operator, однако его дальнейшая судьба осталась для нас под вопросом (найти его в опубликованном виде на сайте проекта нам не удалось).

  • Docker Captain из Германии создал специальный контроллер для обновления DNS-записей при рестарте podа с Traefik. Вскоре после этого он узнал про shell-operator и перевел свою разработку на его использование.

  • Solution Architect из Red Hat занялся созданием r53-operator оператора для кастомных доменов, который управляет доменами Ingress в AWS Route 53.

Если у вас тоже есть опыт применения shell-operator, будем рады соответствующим рассказам в GitHub Discussions проекта: собирая такие примеры, мы надеемся помочь широкому сообществу инженеров. Случаи использования addon-operator гораздо более редкое явление, так что им мы будем рады вдвойне.

Заключение

Shell-operator и addon-operator давно используются нами в ежедневной работе. Основные проблемы изучены и устранены, а сейчас в проекты преимущественно добавляются новые возможности. В ближайших планах для shell-operator поддержка conversion webhook и возможность писать хуки без побочных эффектов, т.е. не вызывать kubectl для изменений в кластере, а возвращать в shell-operator набор действий (см. #94, #239).

Фактически оба проекта давно вышли из статуса beta, поэтому мы решили синхронизироваться с реальностью и представляем их версии rc1, а следующий релиз shell-operator в этом году может стать окончательным v1.0.0.

P.S. В ноябре прошлого года shell-operator преодолел рубеж в 1000 звёзд на GitHub, а addon-operator более скромные 250. Спасибо всем, кто заинтересовался проектами!

P.P.S.

Читайте также в нашем блоге:

Подробнее..

Эксплуатация MongoDB в Kubernetes решения, их плюсы и минусы

26.03.2021 10:08:08 | Автор: admin

MongoDB одна из самых популярных NoSQL/документоориентированных баз данных в мире веб-разработки, поэтому многие наши клиенты используют её в своих продуктах, в том числе и в production. Значительная их часть функционирует в Kubernetes, так что хотелось бы поделиться накопленным опытом: какие варианты для запуска Mongo в K8s существуют? В чем их особенности? Как мы сами подошли к этому вопросу?

Ведь не секрет: несмотря на то, что Kubernetes предоставляет большое количество преимуществ в масштабировании и администрировании приложений, если делать это без должного планирования и внимательности, можно получить больше неприятностей, чем пользы. То же самое касается и MongoDB в Kubernetes.

Главные вызовы

В частности, при размещении Mongo в кластере важно учитывать:

  1. Хранилище. Для гибкой работы в Kubernetes для Mongo лучше всего подойдут удаленные хранилища, которые можно переключать между узлами, если понадобится переместить Mongo при обновлении узлов кластера или их удалении. Однако удаленные диски обычно предоставляются с более низким показателем iops (в сравнении с локальными). Если база является высоконагруженной и требуются хорошие показания по latency, то на это стоит обратить внимание в первую очередь.

  2. Правильные requests и limits на podах с репликами Mongo (и соседствующих с ними podами на узле). Если не настроить их правильно, то поскольку Kubernetes более приветлив к stateless-приложениям можно получить нежелательное поведение, когда при внезапно возросшей нагрузке на узле Kubernetes начнет убивать podы с репликами Mongo и переносить их на соседние, менее загруженные. Это вдвойне неприятно по той причине, что перед тем, как pod с Mongo поднимется на другом узле, может пройти значительное время. Всё становится совсем плохо, если упавшая реплика была primary, т.к. это приведет к перевыборам: вся запись встанет, а приложение должно быть к этому готово и/или будет простаивать.

  3. В дополнение к предыдущему пункту: даже если случился пик нагрузки, в Kubernetes есть возможность быстро отмасштабировать узлы и перенести Mongo на узлы с большими ресурсами. Потому не стоит забывать про podDisruptionBudget, что не позволит удалять или переносить podы разом, старательно поддерживая указанное количество реплик в рабочем состоянии.

Решив эти вызовы для своего случая, вы получите быстро масштабируемую вертикально и горизонтально базу, которая будет находиться в одной среде с приложениями и удобно управляться общими механизмами Kubernetes. В плане надежности все зависит лишь от того, насколько хорошо спланировано размещение базы внутри кластера с учетом основных негативных сценариев при её использовании.

К счастью, на данный момент практически любой провайдер может предоставить любой тип хранилища на ваш выбор: от сетевых дисков до локальных с внушительным запасом по iops. Для динамического расширения кластера MongoDB подойдут только сетевые диски, но мы должны учитывать, что они всё же проигрывают в производительности локальным. Пример из Google Cloud:

А также они могут зависеть от дополнительных факторов:

В AWS картина чуть лучше, но всё ещё далека от производительности, что мы видим для локального варианта:

В нашем практике ещё ни разу не понадобилось добиваться такой производительности для MongoDB: в большинстве случаев хватает того, что предоставляют провайдеры.

Каким образом можно поднять MongoDB в Kubernetes?

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

1. Helm-чарт от Bitnami

И первое, что привлекает внимание, это Helm-чарт от Bitnami. Он довольно популярен, создан и поддерживается значительно долгое время.

Чарт позволяет запускать MongoDB несколькими способами:

  1. standalone;

  2. Replica Set (здесь и далее по умолчанию подразумевается терминология MongoDB; если речь пойдет про ReplicaSet в Kubernetes, на это будет явное указание);

  3. Replica Set + Arbiter.

Используется свой (т.е. неофициальный) образ.

Чарт хорошо параметризован и документирован. Обратная сторона медали: из-за обилия функций в нём придется посидеть и разобраться, что вам действительно нужно, потому использование этого чарта очень сильно напоминает конструктор, который позволяет собрать самому конфигурацию которая вам нужна.

Минимальная конфигурация, которая понадобится для поднятия, это:

1. Указать архитектуру (Values.yaml#L58-L60). По умолчанию это standalone, но нас интересует replicaset:

...architecture: replicaset...

2. Указать тип и размер хранилища (Values.yaml#L442-L463):

...persistence:  enabled: true  storageClass: "gp2" # у нас это general purpose 2 из AWS  accessModes:    - ReadWriteOnce  size: 120Gi...

После этого через helm install мы получаем готовый кластер MongoDB с инструкцией, как к нему подключиться из Kubernetes:

NAME: mongobitnamiLAST DEPLOYED: Fri Feb 26 09:00:04 2021NAMESPACE: mongodbSTATUS: deployedREVISION: 1TEST SUITE: NoneNOTES:** Please be patient while the chart is being deployed **MongoDB(R) can be accessed on the following DNS name(s) and ports from within your cluster:    mongobitnami-mongodb-0.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017    mongobitnami-mongodb-1.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017    mongobitnami-mongodb-2.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017To get the root password run:    export MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace mongodb mongobitnami-mongodb -o jsonpath="{.data.mongodb-root-password}" | base64 --decode)To connect to your database, create a MongoDB(R) client container:    kubectl run --namespace mongodb mongobitnami-mongodb-client --rm --tty -i --restart='Never' --env="MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD" --image docker.io/bitnami/mongodb:4.4.4-debian-10-r0 --command -- bashThen, run the following command:    mongo admin --host "mongobitnami-mongodb-0.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017,mongobitnami-mongodb-1.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017,mongobitnami-mongodb-2.mongobitnami-mongodb-headless.mongodb.svc.cluster.local:27017" --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD

В пространстве имен увидим готовый кластер с арбитром (он enabled в чарте по умолчанию):

Но такая минимальная конфигурация не отвечает главным вызовам, перечисленным в начале статьи. Поэтому советую включить в неё следующее:

1. Установить PDB (по умолчанию он выключен). Мы не хотим терять кластер в случае drainа узлов можем позволить себе недоступность максимум 1 узла (Values.yaml#L430-L437):

...pdb:  create: true  maxUnavailable: 1...

2. Установить requests и limits (Values.yaml#L350-L360):

...resources:  limits:    memory: 8Gi  requests:     cpu: 4    memory: 4Gi...

В дополнение к этому можно повысить приоритет у podов с базой относительно других podов (Values.yaml#L326).

3. По умолчанию чарт создает нежесткое anti-affinity для podов кластера. Это означает, что scheduler будет стараться не назначать podы на одни и те же узлы, но если выбора не будет, то начнет размещать туда, где есть место.

Если у нас достаточно узлов и ресурсов, стоит сделать так, чтобы ни в коем случае не выносить две реплики кластера на один и тот же узел (Values.yaml#L270):

...podAntiAffinityPreset: hard...

Сам же запуск кластера в чарте происходит по следующему алгоритму:

  1. Запускаем StatefulSet с нужным числом реплик и двумя init-контейнерами: volume-permissions и auto-discovery.

  2. Volume-permissions создает директорию для данных и выставляет права на неё.

  3. Auto-discovery ждёт, пока появятся все сервисы, и пишет их адреса в shared_file, который является точкой передачи конфигурации между init-контейнером и основным контейнером.

  4. Запускается основной контейнер с подменой command, определяются переменные для entrypointа и run.sh.

  5. Запускается entrypoint.sh, который вызывает каскад из вложенных друг в друга Bash-скриптов с вызовом описанных в них функций.

  6. В конечном итоге инициализируется MongoDB через такую функцию:

      mongodb_initialize() {        local persisted=false        info "Initializing MongoDB..."        rm -f "$MONGODB_PID_FILE"        mongodb_copy_mounted_config        mongodb_set_net_conf        mongodb_set_log_conf        mongodb_set_storage_conf        if is_dir_empty "$MONGODB_DATA_DIR/db"; then                info "Deploying MongoDB from scratch..."                ensure_dir_exists "$MONGODB_DATA_DIR/db"                am_i_root && chown -R "$MONGODB_DAEMON_USER" "$MONGODB_DATA_DIR/db"                mongodb_start_bg                mongodb_create_users                if [[ -n "$MONGODB_REPLICA_SET_MODE" ]]; then                if [[ -n "$MONGODB_REPLICA_SET_KEY" ]]; then                        mongodb_create_keyfile "$MONGODB_REPLICA_SET_KEY"                        mongodb_set_keyfile_conf                fi                mongodb_set_replicasetmode_conf                mongodb_set_listen_all_conf                mongodb_configure_replica_set                fi                mongodb_stop        else                persisted=true                mongodb_set_auth_conf                info "Deploying MongoDB with persisted data..."                if [[ -n "$MONGODB_REPLICA_SET_MODE" ]]; then                if [[ -n "$MONGODB_REPLICA_SET_KEY" ]]; then                        mongodb_create_keyfile "$MONGODB_REPLICA_SET_KEY"                        mongodb_set_keyfile_conf                fi                if [[ "$MONGODB_REPLICA_SET_MODE" = "dynamic" ]]; then                        mongodb_ensure_dynamic_mode_consistency                fi                mongodb_set_replicasetmode_conf                fi        fi        mongodb_set_auth_conf        }

2. Устаревший чарт

Если поискать чуть глубже, можно обнаружить еще и старый чарт в главном репозитории Helm. Ныне он deprecated (в связи с выходом Helm 3 подробности см. здесь), но продолжает поддерживаться и использоваться различными организациями независимо друг от друга в своих репозиториях например, здесь им занимается норвежский университет UiB.

Этот чарт не умеет запускать Replica Set + Arbiter и использует маленький сторонний образ в init-контейнерах, но в остальном достаточно прост и отлично выполняет задачу деплоя небольшого кластера.

Мы стали использовать его в своих проектах задолго до того, как он стал deprecated (а это произошло не так давно 10 сентября 2020 года). За минувшее время чарт сильно изменился, однако в то же время сохранил основную логику работы. Для своих задач мы сильно урезали чарт, сделав его максимально лаконичным и убрав всё лишнее: шаблонизацию и функции, которые неактуальны для наших задач.

Минимальная конфигурация сильно схожа с предыдущим чартом, поэтому подробно останавливаться на ней не буду только отмечу, что affinity придется задавать вручную (Values.yaml#L108):

      affinity:        podAntiAffinity:          requiredDuringSchedulingIgnoredDuringExecution:          - labelSelector:              matchLabels:               app: mongodb-replicaset

Алгоритм его работы схож с чартом от Bitnami, но менее нагружен (нет такого нагромождения маленьких скриптов с функциями):

1. Init-контейнер copyconfig копирует конфиг из configdb-readonly (ConfigMap) и ключ из секрета в директорию для конфигов (emptyDir, который будет смонтирован в основной контейнер).

2. Секретный образ unguiculus/mongodb-install копирует исполнительный файл peer-finder в work-dir.

3. Init-контейнер bootstrap запускает peer-finder с параметром /init/on-start.sh этот скрипт занимается поиском поднятых узлов кластера MongoDB и добавлением их в конфигурационный файл Mongo.

4. Скрипт /init/on-start.sh отрабатывает в зависимости от конфигурации, передаваемой ему через переменные окружения (аутентификация, добавление дополнительных пользователей, генерация SSL-сертификатов), плюс может исполнять дополнительные кастомные скрипты, которые мы хотим запускать перед стартом базы.

5. Список пиров получают как:

          args:            - -on-start=/init/on-start.sh            - "-service=mongodb"log "Reading standard input..."while read -ra line; do    if [[ "${line}" == *"${my_hostname}"* ]]; then        service_name="$line"    fi    peers=("${peers[@]}" "$line")done

6. Выполняется проверка по списку пиров: кто из них primary, а кто master.

  • Если не primary, то пир добавляется к primary в кластер.

  • Если это самый первый пир, он инициализирует себя и объявляется мастером.

7. Конфигурируются пользователи с правами администратора.

8. Запускается сам процесс MongoDB.

3. Официальный оператор

В 2020 году вышел в свет официальный Kubernetes-оператор community-версии MongoDB. Он позволяет легко разворачивать, обновлять и масштабировать кластер MongoDB. Кроме того, оператор гораздо проще чартов в первичной настройке.

Однако мы рассматриваем community-версию, которая ограничена в возможностях и не подлежит сильной кастомизации опять же, если сравнивать с чартами, представленными выше. Это вполне логично, учитывая, что существует также и enterprise-редакция.

Архитектура оператора:

В отличие от обычной установки через Helm в данном случае понадобится установить сам оператор и CRD (CustomResourceDefinition), что будет использоваться для создания объектов в Kubernetes.

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

  1. Оператор создает StatefulSet, содержащий podы с контейнерами MongoDB. Каждый из них член ReplicaSetа в Kubernetes.

  2. Создается и обновляется конфиг для sidecar-контейнера агента, который будет конфигурировать MongoDB в каждом podе. Конфиг хранится в Kubernetes-секрете.

  3. Создается pod с одним init-контейнером и двумя основными.

    1. Init-контейнер копирует бинарный файл хука, проверяющего версию MongoDB, в общий empty-dir volume (для его передачи в основной контейнер).

    2. Контейнер для агента MongoDB выполняет управление основным контейнером с базой: конфигурация, остановка, рестарт и внесение изменений в конфигурацию.

  4. Далее контейнер с агентом на основе конфигурации, указанной в Custom Resource для кластера, генерирует конфиг для самой MongoDB.

Вся установка кластера укладывается в:

---apiVersion: mongodb.com/v1kind: MongoDBCommunitymetadata:  name: example-mongodbspec:  members: 3  type: ReplicaSet  version: "4.2.6"  security:    authentication:      modes: ["SCRAM"]  users:    - name: my-user      db: admin      passwordSecretRef: # ссылка на секрет ниже для генерации пароля юзера        name: my-user-password      roles:        - name: clusterAdmin          db: admin        - name: userAdminAnyDatabase          db: admin      scramCredentialsSecretName: my-scram# учетная запись пользователя генерируется из этого секрета# после того, как она будет создана, секрет больше не потребуется---apiVersion: v1kind: Secretmetadata:  name: my-user-passwordtype: OpaquestringData:  password: 58LObjiMpxcjP1sMDW

Преимущество данного оператора в том, что он способен масштабировать количество реплик в кластере вверх и вниз, а также выполнять upgrade и даже downgrade, делая это беспростойно. Также он умеет создавать кастомные роли и пользователей.

Но в то же время он уступает предыдущим вариантам тем, что у него нет встроенной возможности отдачи метрик в Prometheus, а вариант запуска только один Replica Set (нельзя создать арбитра). Кроме того, данный способ развертывания не получится сильно кастомизировать, т.к. практически все параметры регулируются через кастомную сущность для поднятия кластера, а сама она ограничена.

На момент написания статьи community-версия оператора имеет очень краткую документацию, не описывающую конфигурацию в подробностях, и это вызывает множество проблем при дебаге тех или иных случаев.

Как уже упоминалось, существует и enterprise-версия оператора, которая предоставляет большие возможности в том числе, установку не только Replica Setов, но и shared-кластеров с настройками шардирования, конфигурации для доступа извне кластера (с указанием имен, по которым он будет доступен извне), дополнительные способы аутентификации т.д. И, конечно же, документация к нему описана гораздо лучше.

Заключение

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

У разных вариантов запуска MongoDB есть разные плюсы. Чарты легко модифицировать под ваши нужды, но вы столкнетесь с проблемами при обновлении MongoDB или при добавлении узлов, т.к. всё равно потребуются ручные операции с кластером. Способ с оператором в этом смысле лучше, но ограничен по другим параметрам (по крайней мере, в своей community-редакции). Также мы не нашли ни в одном из описанных вариантов возможность из коробки запускать скрытые реплики.

Наконец, не стоит забывать, что есть и managed-решения для Mongo, однако мы в своей практике стараемся не привязываться к определенным провайдерам и предпочитаем варианты для чистого Kubernetes. Мы также не рассматривали Percona Kubernetes Operator for PSMDB, потому что он ориентирован на вариацию MongoDB от одноимённой компании (Percona Server for MongoDB).

P.S.

Читайте также в нашем блоге:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru