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

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

К сожалению, у пользовательских контроллеров есть серьёзная проблема: по ряду причин они не способны эффективно обрабатывать большие объёмы данных. Всё хранилище данных в Kubernetes построено на базе ETCD, что ограничивает масштабируемость, гибкость и производительность при работе со сложными или объёмными рабочими нагрузками. О каких именно проблемах идёт речь?

  • ETCD изначально был спроектирован для хранения конфигурационных данных, а размер кластера остаётся весьма ограниченным.

  • В используемой модели согласованности ETCD не поддерживает шардирование — все узлы являются полными репликами, и Kubernetes взаимодействует только с лидером.

  • ETCD не может выполнять фильтрацию данных на уровне хранилища, поэтому API-сервер Kubernetes вынужден загружать все записи и фильтровать их на клиентской стороне.

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

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

На этом этапе стоит упомянуть проект Kine. Kine предлагает альтернативу ETCD — вместо него можно использовать MySQL или PostgreSQL, самые популярные реляционные СУБД. Это решение помогает решить проблему с масштабированием хранилища, но не устраняет другие ограничения, описанные выше.

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

Проблема решаема…

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

Ограничение

Описание

Конечная согласованность

Обновления могут не сразу стать видимыми во всей системе

Отсутствие транзакций

Отсутствие поддержки транзакций с гарантией ACID

Ограниченные возможности фильтрации данных

Отсутствие расширенных возможностей запросов и фильтрации данных внутри Kubernetes

Реляционная логика

Нет поддержки сложных связей и объединений между сущностями

Большие объёмы данных

Хранение и обслуживание больших объёмов данных в масштабе невозможно

Пора познакомиться с HariKube. HariKube — это прослойка (middleware), которая прозрачно распределяет нагрузку между несколькими независимыми от вендора базами данных, обеспечивая низкую задержку, высокую пропускную способность и облачную архитектуру, оптимизированную для разработки. Благодаря распределению данных и оптимизированной маршрутизации запросов к базам данных HariKube достигает выдающейся производительности. Перенаправляя ресурсоёмкие рабочие нагрузки с ETCD на другие хранилища данных, он обеспечивает стабильную отзывчивость и эффективную работу в масштабе.

HariKube обеспечивает изоляцию данных между пространствами имён (namespace), типами ресурсов и сервисами, что помогает компаниям соблюдать требования безопасности и соответствия (compliance), не жертвуя масштабируемостью и производительностью. И, наконец, он упрощает рабочий процесс разработчиков, скрывая инфраструктурную сложность. Вам остаётся сосредоточиться только на структурах данных и бизнес-логике — платформа сама позаботится о маршрутизации и хранении данных.

HariKube полностью прозрачен: Kubernetes «не замечает», что работает не с ETCD. HariKube используется в продакшене для обработки больших объёмов данных и их распределения между хранилищами.

Как это работает?

  1. Пользователь инициирует операцию CRUD для ресурса Kubernetes (например, для пользовательского ресурса).

  2. Запрос направляется на API-сервер Kubernetes, который перенаправляет его через прослойку.

  3. HariKube перехватывает запрос и определяет, где следует хранить данные, согласно заданным правилам маршрутизации.

  4. Если найдено соответствующее правило маршрутизации, запрос направляется в определённую базу данных (например, в MySQL).

  5. Если соответствующее правило маршрутизации не найдено, запрос обрабатывается в ETCD — хранилище данных по умолчанию в Kubernetes.

  6. Соответствующее хранилище (MySQL или ETCD) выполняет операцию CRUD.

  7. Когда бэкенд возвращает ответ, он проходит обратно через ту же цепочку до пользователя.

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

База данных

Фильтрация на уровне хранилища*

Изоляция данных

Снижение задержки

Повышение пропускной способности

Поддержка больших объёмов данных*

ETCD

NATS

MariaDB

MySQL

TiDB

PostgreSQL

CockRoachDB

YugabyteDB

SQLite

*Поддержка работы с большими объёмами данных с использованием фильтрации на уровне хранилища недоступна в стандартной (vanilla) версии Kubernetes. Для этого необходимо перекомпилировать Kubernetes. Подробнее об этом мы расскажем далее.

Теперь давайте перейдём к практике.

Для начала настроим базы данных в файле docker-compose.yml.

version: '3.8'
services:
  etcd2479:
    image: bitnami/etcd:3.5
    container_name: etcd2479
    network_mode: "host"
    environment:
      - ETCD_LISTEN_CLIENT_URLS=http://127.0.0.1:2479
      - ETCD_LISTEN_PEER_URLS=http://127.0.0.1:2480
      - ETCD_INITIAL_CLUSTER=default=http://127.0.0.1:2480
      - ETCD_ADVERTISE_CLIENT_URLS=http://127.0.0.1:2479
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://127.0.0.1:2480
    command: etcd --auto-compaction-mode=revision --auto-compaction-retention=5m

  etcd2579:
    image: bitnami/etcd:3.5
    container_name: etcd2579
    network_mode: "host"
    environment:
      - ETCD_LISTEN_CLIENT_URLS=http://127.0.0.1:2579
      - ETCD_LISTEN_PEER_URLS=http://127.0.0.1:2580
      - ETCD_INITIAL_CLUSTER=default=http://127.0.0.1:2580
      - ETCD_ADVERTISE_CLIENT_URLS=http://127.0.0.1:2579
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://127.0.0.1:2580
    command: etcd --auto-compaction-mode=revision --auto-compaction-retention=5m

  mysql3306:
    image: linuxserver/mariadb:10.11.8
    container_name: mysql3306
    network_mode: "host"
    environment:
      - MYSQL_ROOT_PASSWORD=passwd

  pgsql5432:
    image: postgres:17-alpine3.20
    container_name: pgsql5432
    network_mode: "host"
    environment:
      - POSTGRES_PASSWORD=passwd

После этого выполните команду docker-compose up -d для запуска баз данных

Теперь создадим файл конфигурации маршрутизации данных — назовём его topology.yml

backends:
- name: rbac
  endpoint: http://127.0.0.1:2579
  regexp:
    prefix: (clusterrolebindings|clusterroles|rolebindings|roles|serviceaccounts)
    key: (clusterrolebindings|clusterroles|rolebindings|roles|serviceaccounts)
- name: kube-system
  endpoint: mysql://root:passwd@tcp(127.0.0.1:3306)/kube_system
  namespace:
    namespace: kube-system
- name: pods
  endpoint: postgres://postgres:passwd@127.0.0.1:5432/pods
  prefix:
    prefix: pods
- name: shirts
  endpoint: sqlite://./db/shirts.db?_journal=WAL&cache=shared
  customresource:
    group: stable.example.com
    kind: shirts

Разберём конфигурацию маршрутизации

  • ETCD с маршрутизацией по регулярным выражениям: направляет ресурсы RBAC Kubernetes в хранилище ETCD.

  • Маршрутизация MySQL по namespace: все объекты в пространстве имён kube-system направляются в MySQL-бэкенд. Поддерживаются только встроенные типы ресурсов; для пользовательских необходимо создать отдельное правило.

  • Маршрутизация PostgreSQL по префиксу: все ресурсы pods (кроме тех, что в kube-system) направляются в PostgreSQL-бэкенд.

  • Точка подключения SQLite для пользовательских ресурсов: все ресурсы типа shirts из группы stable.example.com направляются во встроенную легковесную базу данных SQLite.

  • Остальные объекты сохраняются в базе данных по умолчанию.

Когда окружение настроено, можно запускать middleware.

docker login registry.harikube.info*
docker run -d \
  --name harikube \
  --net=host \
  -e TOPOLOGY_CONFIG=/topology.yml \
  -v $(pwd)/topology.yml:/topology.yml \
  -v harikube_data:/db \
  registry.harikube.info/harikube/middleware:beta-v1.0.0-3 \
  --listen-address=0.0.0.0:2379 --endpoint=multi://http://localhost:2479

*Docker-образы пока не опубликованы — для получения пробной версии обратитесь через сайт проекта.

Заключительный шаг — запуск кластера Kubernetes. Как уже упоминалось, HariKube полностью совместим с Kubernetes и работает с ним без дополнительных настроек. Однако для поддержки работы с большими объёмами данных потребуется перекомпиляция компонентов API Server и Controller Manager. Инструкции по перекомпиляции можно найти по ссылке (будет приведена далее), но для упрощения в этом руководстве используется Kind с базовой версией Kubernetes.

Создайте конфигурационный файл Kind — kind-config.yml.

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "CustomResourceFieldSelectors": true
  "WatchList": true
  "WatchListClient": true
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: ClusterConfiguration
    apiServer:
        extraArgs:
          storage-media-type: application/json
          etcd-servers: "http://<PUBLIC_IP_OF_HOST>:2379"

Запустите кластер, выполнив команду:

kind create cluster --name harikube-cluster --config kind-config.yml

Убедитесь, что HariKube распределил данные согласно файлу topology.yml:

  • etcdctl --endpoints=http://127.0.0.1:2479 get / --prefix --keys-only 
    База данных по умолчанию для остальных объектов

  • etcdctl --endpoints=http://127.0.0.1:2579 get / --prefix --keys-only
    Только объекты, связанные с RBAC

  • docker exec -t mysql3306 mysql -uroot -ppasswd -Dkube_system -e "select name from kine" 
    Объекты из пространства имён kube-system

  • docker exec -it pgsql5432 su postgres -c "psql -d pods -c 'select name from kine'" 
    Все pod'ы, за исключением тех, что в kube-system

Теперь можно создать первый пользовательский ресурс. Для начала примените файл с определением ресурса, выполнив следующую команду:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/customresourcedefinition/shirt-resource-definition.yaml

Затем создайте несколько экземпляров ресурса.

cat | kubectl apply -f - <<EOF
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example1
spec:
  color: blue
  size: S
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example2
spec:
  color: blue
  size: M
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example3
spec:
  color: green
  size: M
EOF

Проверьте, что HariKube сохранил все ресурсы типа shirt в базе данных SQLite:

  • docker run -it --rm -v harikube_data:/data alpine/sqlite /data/shirts.db -cmd "select name from kine"
    Все 3 объекта типа shirt, которые мы создали

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

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

Спасибо за внимание! Делитесь мыслями в комментариях.


Если проблемы масштабируемости в Kubernetes, обработка больших объемов данных и оптимизация инфраструктуры — это те вопросы, с которыми вы сталкиваетесь регулярно, возможно, вам уже стоит задуматься о новых подходах к решению этих задач. Мы подготовили несколько открытых уроков, которые помогут вам эффективно справиться с этим и улучшить производительность ваших систем:

Все открытые уроки по всем IT-направлениям уже собраны в календаре.

Комментарии (0)