- PVSM.RU - https://www.pvsm.ru -
С базой данных Apache Cassandra и необходимостью её эксплуатации в рамках инфраструктуры на базе Kubernetes мы сталкиваемся регулярно. В этом материале поделимся своим видением необходимых шагов, критериев и существующих решений (включая обзор операторов) для миграции Cassandra в K8s.
Кто же такая Cassandra? Это распределенная система хранения, предназначенная для управления большими объемами данных, при этом обеспечивающая высокую доступность без единой точки отказа. Проект вряд ли нуждается в длинном представлении, поэтому приведу лишь основные особенности Cassandra, что будут актуальны в разрезе конкретной статьи:
Теперь — к собственно потенциальному переезду в Kubernetes.
Говоря о миграции Cassandra в Kubernetes, мы надеемся, что с переездом управлять ей станет удобнее. Что для этого потребуется, что в этом поможет?
Как уже уточнялось, часть данных Cassanda хранит в оперативной памяти — в Memtable. Но есть и другая часть данных, которая сохраняется на диск, — в виде SSTable. К этим данным добавляется сущность Commit Log — записи обо всех транзакциях, которые тоже сохраняются на диск.
Схема транзакций записи в Cassandra
В Kubernetes мы можем использовать для хранения данных PersistentVolume. Благодаря отработанным механизмам, работать с данными в Kubernetes с каждым годом становится всё проще.
Каждому pod’у с Cassandra мы выделим свой PersistentVolume
Важно отметить, что Cassandra сама по себе подразумевает репликацию данных, предлагая для этого встроенные механизмы. Поэтому, если вы собираете кластер Cassandra из большого числа узлов, то нет необходимости использовать для хранения данных распределенные системы вроде Ceph или GlusterFS. В этом случае логично будет хранить данные на диске узла при помощи локальных персистентных дисков [1] или монтирования hostPath
.
Другой вопрос, если вы хотите создавать для каждой feature-ветки отдельное окружение для разработчиков. В этом случае правильным подходом будет поднимать один узел Cassandra, а данные хранить в распределенном хранилище, т.е. упомянутые Ceph и GlusterFS станут вашей опцией. Тогда разработчик будет уверен, что не потеряет тестовые данные даже при потере одного из узлов Kuberntes-кластера.
Практически безальтернативным выбором для реализации мониторинга в Kubernetes является Prometheus (подробно мы об этом рассказывали в соответствующем докладе [2]). Как дела у Cassandra с экспортерами метрик для Prometheus? И, что в чем-то даже главнее, с подходящими к ним dashboard’ами для Grafana?
Пример внешнего вида графиков в Grafana для Cassandra
Экспортеров всего два: jmx_exporter [3] и cassandra_exporter [4].
Мы выбрали для себя первый, потому что:
-javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180
.Согласно вышеизложенной структуре кластера Cassandra, попробуем перевести всё, что там описано, в терминологию Kubernetes:
Получается, что не хватает какой-то дополнительной сущности, чтобы управлять всем кластером Cassandra сразу. Но если чего-то нет, мы можем это создать! В Kubernetes для этого предназначен механизм определения собственных ресурсов — Custom Resource Definitions [6].
Объявление дополнительных ресурсов для логов и оповещений
Но сам по себе Custom Resource ничего не значит: ведь для него нужен контроллер. Возможно, придется прибегнуть к помощи Kubernetes-оператора [7]…
Пунктом выше мы согласились, что один узел Cassandra будет равняться одному pod’у в Kubernetes. Но IP-адреса у pod’ов каждый раз будут разными. А идентификация узла в Cassandra происходит именно на основе IP-адреса… Получается, что после каждого удаления pod’а кластер Cassandra будет добавлять в себя новый узел.
Выход есть, и даже не один:
hostNetwork: true
. Данный метод накладывает определённые ограничения:
Мы хотим сохранять полную версию данных одного узла Cassandra по расписанию. Kubernetes предоставляет удобную возможность с использованием CronJob [9], но тут палки в колеса нам вставляет сама Cassandra.
Напомню, что часть данных Cassandra хранит в памяти. Чтобы сделать полный бэкап, нужно данные из памяти (Memtables) перенести на диск (SSTables). В этот момент узел Cassandra перестает принимать соединения, полностью выключаясь из работы кластера.
После этого снимается бэкап (snapshot) и сохраняется схема (keyspace). И тут выясняется, что просто бэкап нам ничего не дает: нужно сохранить идентификаторы данных, за которые отвечал узел Cassandra, — это специальные токены.
Распределение токенов для идентификации, за какие данные отвечают узлы Cassandra
Пример скрипта для снятия бэкапа Cassandra от Google в Kubernetes можно найти по этой ссылке [10]. Единственный момент, который скрипт не учитывает, — это сброс данных на узел перед снятием snapshot’а. То есть бэкап выполняется не для текущего состояния, а состояния чуть ранее. Но это помогает не выводить узел из работы, что видится очень логичным.
set -eu
if [[ -z "$1" ]]; then
info "Please provide a keyspace"
exit 1
fi
KEYSPACE="$1"
result=$(nodetool snapshot "${KEYSPACE}")
if [[ $? -ne 0 ]]; then
echo "Error while making snapshot"
exit 1
fi
timestamp=$(echo "$result" | awk '/Snapshot directory: / { print $3 }')
mkdir -p /tmp/backup
for path in $(find "/var/lib/cassandra/data/${KEYSPACE}" -name $timestamp); do
table=$(echo "${path}" | awk -F "[/-]" '{print $7}')
mkdir /tmp/backup/$table
mv $path /tmp/backup/$table
done
tar -zcf /tmp/backup.tar.gz -C /tmp/backup .
nodetool clearsnapshot "${KEYSPACE}"
Пример bash-скрипта для снятия бэкапа с одного узла Cassandra
Что вообще сейчас используют для разворачивания Cassandra в Kubernetes и что из этого больше всего подходит под заданные требования?
Использовать базовые функции StatefulSets для запуска кластера Cassandra — хороший вариант. При помощи Helm-чарта и шаблонов Go можно предоставить пользователю гибкий интерфейс для разворачивания Cassandra.
Обычно это работает нормально… пока не случится что-то неожиданное — например, выход узла из строя. Стандартные средства Kubernetes просто не могут учесть все вышеописанные особенности. Кроме того, данный подход очень ограничен в том, насколько он может быть расширен для более сложного использования: замены узлов, резервного копирования, восстановления, мониторинга и т.д.
Представители:
Оба чарта одинаково хороши, но при этом подвержены описанным выше проблемам.
Такие опции более интересны, потому что предоставляют широкие возможности по управлению кластером. Для проектирования оператора Cassandra, как и любой другой базы данных, хороший паттерн выглядит как Sidecar <-> Controller <-> CRD:
Схема управления узлами в правильно спроектированном операторе Cassandra
Рассмотрим существующие операторы.
Это действительно очень многообещающий и активно развивающийся проект от компании, которая предлагает управляемые развертывания Cassandra. Он, как и описано выше, использует sidecar-контейнер, который принимает команды через HTTP. Написан на Java, поэтому иногда ему не хватает более продвинутой функциональности библиотеки client-go. Также оператор не поддерживает разные Racks для одного Datacenter.
Зато у оператора есть такие плюсы, как поддержка мониторинга, высокоуровневого управления кластером при помощи CRD и даже документация по снятию бэкапов.
Оператор, предназначенный для развертывания DB-as-a-Service. На данный момент поддерживает две базы данных: Elasticsearch и Cassandra. Имеет в себе такие интересные решения, как контроль доступа к базе данных через RBAC (для этого поднимается свой отдельный navigator-apiserver). Интересный проект, к которому стоило бы присмотреться, однако последний коммит был сделан полтора года назад, что явно снижает его потенциал.
Рассматривать его «всерьёз» не стали, так как последний коммит в репозиторий был больше года назад. Разработка оператора заброшена: последняя версия Kubernetes, заявленная как поддерживаемая, — это 1.9.
Оператор, развитие которого идет не так быстро, как хотелось бы. Имеет продуманную структуру CRD для управления кластером, решает проблему с идентификацией узлов при помощи Service с ClusterIP (тот самый «хак»)… но пока что это всё. Мониторинга и бэкапов из коробки сейчас нет (кстати, за мониторинг мы взялись сами [17]). Интересный момент, что при помощи этого оператора можно также развернуть ScyllaDB.
NB: Данный оператор с небольшими доработками мы использовали в одном из наших проектов. Проблем в работе оператора за все время эксплуатации (~4 месяца работы) замечено не было.
Самый молодой оператор в списке: первый коммит был сделан 23 мая 2019 года. Уже сейчас он имеет в своем арсенале большое количество фич из нашего списка, подробнее с которыми можно ознакомиться в репозитории проекта. Оператор построен на базе популярного operator-sdk. Поддерживает мониторинг «из коробки». Главным отличием от других операторов является использование плагина CassKop [19], реализованного на Python и используемого для коммуникации между узлами Cassandra.
Количество подходов и возможных вариантов переноса Cassandra в Kubernetes говорит само за себя: тема востребована.
На данном этапе пробовать что-то из вышеописанного можно на свой страх и риск: ни один из разработчиков не гарантирует 100%-ую работу своего решения в production-среде. Но уже сейчас многие продукты выглядят многообещающе, чтобы попробовать использовать их в стендах для разработки.
Думаю, в будущем эта женщина на корабле придется к месту!
Читайте также в нашем блоге:
Автор: Набоких Максим
Источник [24]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/337162
Ссылки в тексте:
[1] локальных персистентных дисков: https://kubernetes.io/docs/concepts/storage/volumes/#local
[2] соответствующем докладе: https://habr.com/ru/company/flant/blog/412901/
[3] jmx_exporter: https://github.com/prometheus/jmx_exporter
[4] cassandra_exporter: https://github.com/criteo/cassandra_exporter
[5] адекватный dashboad: https://grafana.com/grafana/dashboards/5408
[6] Custom Resource Definitions: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[7] Kubernetes-оператора: https://habr.com/ru/company/flant/blog/326414/
[8] балансировка на базе IPVS: https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/
[9] CronJob: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
[10] этой ссылке: https://github.com/GoogleCloudPlatform/click-to-deploy/blob/master/k8s/cassandra/scripts/backup.sh
[11] Чарт из основного репозитория Helm: https://github.com/helm/charts/tree/master/incubator/cassandra
[12] Чарт от bitnami: https://github.com/bitnami/charts/tree/master/bitnami/cassandra
[13] GitHub: https://github.com/instaclustr/cassandra-operator
[14] GitHub: https://github.com/jetstack/navigator
[15] GitHub: https://github.com/vgkowski/cassandra-operator
[16] GitHub: https://github.com/rook/rook/blob/master/Documentation/cassandra.md
[17] взялись сами: https://github.com/rook/rook/pull/3228
[18] GitHub: https://github.com/Orange-OpenSource/cassandra-k8s-operator
[19] плагина CassKop: https://github.com/Orange-OpenSource/cassandra-k8s-operator/blob/2f13639c07f8da485ee246796766897852f6e9d6/plugins/kubectl-casskop
[20] Беспростойная миграция MongoDB в Kubernetes: https://habr.com/ru/company/flant/blog/461149/
[21] Беспростойная миграция RabbitMQ в Kubernetes: https://habr.com/ru/company/flant/blog/450662/
[22] Базы данных и Kubernetes (обзор и видео доклада): https://habr.com/ru/company/flant/blog/431500/
[23] K8s tips & tricks: Ускоряем bootstrap больших баз данных: https://habr.com/ru/company/flant/blog/417509/
[24] Источник: https://habr.com/ru/post/475036/?utm_source=habrahabr&utm_medium=rss&utm_campaign=475036
Нажмите здесь для печати.