Развёртывание кластера через Kubernetes Operator¶
Kubernetes Operator — рекомендуемый способ управления кластером Picodata в
Kubernetes для production-окружений. Оператор реализует reconcile-loop на
основе CRD PicoclusterDB и автоматически поддерживает желаемое состояние
кластера: создаёт и обновляет StatefulSet-ы, Service-ы, ConfigMap-ы, следит
за установкой и обновлением плагинов.
Требования¶
- Kubernetes 1.30+
- kubectl 1.28+
Установка оператора¶
Установка выполняется в два шага: сначала регистрируются CRD, затем разворачивается сам оператор.
Шаг 1. Установите CRD:
kubectl apply -f https://git.picodata.io/core/picodata-operator/-/raw/master/picodata-operator-deploy/crd.yaml
Шаг 2. Установите оператор:
kubectl apply -f https://git.picodata.io/core/picodata-operator/-/raw/master/picodata-operator-deploy/operator.yaml
Дождитесь готовности пода оператора:
kubectl rollout status deployment/picodata-operator-controller-manager \
-n picodata-operator-system
Создание namespace и секрета¶
Создайте namespace для кластера и секрет с паролем пользователя admin:
kubectl create namespace picodata
kubectl create secret generic picodata-admin-secret \
--namespace picodata \
--from-literal=password=<ваш-пароль>
Внимание!
Пароль должен соответствовать политике безопасности Picodata: не менее 8 символов, латинские буквы в верхнем и нижнем регистрах, цифры.
Описание ресурса PicoclusterDB¶
Кластер описывается ресурсом PicoclusterDB. Основные поля:
apiVersion: picodata.picodata.io/v1
kind: PicoclusterDB
metadata:
name: <имя-кластера>
namespace: <namespace>
spec:
image:
repository: docker.binary.picodata.io # реестр образов
tag: "picodata:26.1.2" # образ и версия Picodata
pullPolicy: IfNotPresent
clusterName: <имя-кластера> # имя кластера внутри Picodata
adminPassword:
secretName: picodata-admin-secret # Secret с паролем admin
key: password
cluster:
defaultReplicationFactor: 1 # фактор репликации по умолчанию для всех тиров
defaultBucketCount: 3000 # количество бакетов (шардов)
tiers: # список тиров кластера
- name: <имя-тира>
replicas: 1 # количество репликасетов в тире
replicationFactor: 1 # количество инстансов в каждом репликасете
canVote: true # участвует ли тир в Raft-голосовании
storage:
size: 1Gi
memtx:
memory: "128M"
pg:
enabled: true # включить протокол PostgreSQL
resources:
requests:
cpu: "100m"
memory: "128Mi"
Общее количество подов тира равно replicas × replicationFactor.
Имена подов строятся по шаблону: {тир}-{кластер}-{номер-репликасета}-{номер-инстанса}.
Развёртывание кластера¶
Минимальный кластер¶
Кластер из двух тиров: арбитр для Raft и основной тир для хранения данных. Пример минимальной конфигурации:
apiVersion: picodata.picodata.io/v1
kind: PicoclusterDB
metadata:
name: picodata
namespace: picodata
spec:
image:
repository: docker.binary.picodata.io
tag: "picodata:26.1.2"
pullPolicy: IfNotPresent
clusterName: picodata
adminPassword:
secretName: picodata-admin-secret
key: password
cluster:
defaultReplicationFactor: 1
defaultBucketCount: 3000
tiers:
- name: arbiter
replicas: 1
replicationFactor: 1
canVote: true
storage:
size: 1Gi
memtx:
memory: "64M"
pg:
enabled: false
resources:
requests:
cpu: "100m"
memory: "128Mi"
- name: default
replicas: 1
replicationFactor: 2
canVote: false
storage:
size: 10Gi
memtx:
memory: "512M"
pg:
enabled: true
resources:
requests:
cpu: "500m"
memory: "512Mi"
Примените манифест:
kubectl apply -f picodata-cluster.yaml
Наблюдение за запуском¶
Следите за готовностью подов:
kubectl get pods -n picodata -w
Ожидаемый результат (все поды 1/1 Running):
NAME READY STATUS RESTARTS AGE
arbiter-picodata-1-0 1/1 Running 0 3m
default-picodata-1-0 1/1 Running 0 3m
default-picodata-1-1 1/1 Running 0 2m
Проверьте состояние CR:
kubectl get picoclusterdb -n picodata
NAME READY AGE
picodata true 5m
Подключение к кластеру¶
Протокол PostgreSQL (psql)¶
Пробросьте pgproto-порт одного из подов тира default:
kubectl port-forward -n picodata pod/default-picodata-1-0 5432:5432
Подключитесь через psql:
psql "host=localhost port=5432 user=admin password=<пароль> dbname=picodata sslmode=disable"
Проверьте состояние инстансов через системную таблицу _pico_instance:
SELECT name, replicaset_name, current_state, tier
FROM _pico_instance;
Веб-интерфейс (Web UI)¶
Пробросьте HTTP-порт:
kubectl port-forward -n picodata svc/default-picodata 8081:8081
Откройте http://localhost:8081 для просмотра состояния кластера в веб-интерфейсе.
Внешний доступ¶
Ingress¶
Ingress обеспечивает доступ к веб-интерфейсу и метрикам (HTTP, порт 8081) через доменное имя. Требует установленного Ingress-контроллера (например, nginx).
Включите Ingress в манифесте тира:
tiers:
- name: default
ingress:
enabled: true
host: picodata.example.com
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
tls:
- secretName: picodata-tls
hosts:
- picodata.example.com
После применения манифеста веб-интерфейс будет доступен по адресу
https://picodata.example.com.
Примечание
Ingress даёт доступ только к HTTP-интерфейсу (порт 8081).
Для доступа по протоколу PostgreSQL (порт 5432) используйте externalService.
LoadBalancer / NodePort¶
Для доступа к PostgreSQL-интерфейсу (pgproto) снаружи кластера используйте
поле externalService:
tiers:
- name: default
externalService:
enabled: true
type: LoadBalancer # или NodePort
При type: LoadBalancer Kubernetes создаёт отдельный Service с внешним IP.
При type: NodePort pgproto будет доступен на фиксированном порту каждой ноды.
Получите внешний адрес:
kubectl get svc -n picodata -l picodata.io/service-type=external
Управление плагинами¶
Плагины объявляются на двух уровнях: кластера и тира.
На кластерном уровне задаётся версия плагина и параметры первичной миграции:
spec:
cluster:
shareDir: /usr/share/picodata # путь к директории с .so-файлами плагинов
plugins:
- name: radix
version: "1.0.0"
migrationContext:
tier_for_db_0: "default"
# ... остальные параметры
На уровне тира задаётся привязка сервисов плагина к тиру и listener-порт:
spec:
tiers:
- name: default
plugins:
- name: radix
services:
- name: radix
listenerPort: 8082
После применения манифеста оператор автоматически выполнит полный жизненный цикл
установки: CREATE PLUGIN → ADD SERVICE TO TIER → SET migration_context →
MIGRATE TO → ENABLE. Установка запускается только когда все поды тира готовы.
Статус установки плагина:
kubectl get picoclusterdb picodata -n picodata \
-o jsonpath='{.status.tiers[*].plugins}'
Подробнее: Управление плагинами
Обновление версии Picodata¶
Для обновления версии Picodata измените поле spec.image.tag в манифесте
и примените его:
spec:
image:
tag: "picodata:26.2.0"
kubectl apply -f picodata-cluster.yaml
Оператор выполнит безопасное обновление:
- Отключит (
DISABLE) все включённые плагины, несовместимые с новым образом - Дождётся фиксации изменения в Raft-кластере
- Обновит образ во всех StatefulSet-ах (rolling update)
- Установит и включит плагины для новой версии
Примечание
PVC (данные) при обновлении образа не затрагиваются.
Ребутстрап инстанса¶
Ребутстрап применяется когда инстанс не может вернуться в кластер после
потери данных или повреждения тома. Оператор исключает инстанс из кластера
(expel), стирает его данные и позволяет ему заново присоединиться как
новому члену репликасета.
Внимание!
Ребутстрап возможен только если репликасет содержит более одного инстанса (replicationFactor ≥ 2) и хотя бы один из оставшихся инстансов доступен.
Создайте ресурс PicoclusterInstanceRebootstrap:
apiVersion: picodata.picodata.io/v1
kind: PicoclusterInstanceRebootstrap
metadata:
name: rebootstrap-1
namespace: picodata
spec:
clusterRef:
name: picodata # имя PicoclusterDB
instanceName: default-picodata-1-0 # имя пода (инстанса)
kubectl apply -f rebootstrap.yaml
Следите за фазами выполнения:
kubectl get picoclusterinstancerebootstrap -n picodata -w
NAME INSTANCE PHASE AGE
rebootstrap-1 default-picodata-1-0 Expelling 10s
rebootstrap-1 default-picodata-1-0 Wiping 30s
rebootstrap-1 default-picodata-1-0 Rejoining 45s
rebootstrap-1 default-picodata-1-0 Succeeded 2m
После завершения ресурс PicoclusterInstanceRebootstrap можно удалить.
Резервное копирование¶
Экспериментальная функция
Резервное копирование и восстановление находятся в стадии эксперимента. Не используйте их в production без предварительного тестирования.
Настройка хранилища резервных копий¶
Добавьте в манифест кластера секцию backup с описанием тома для хранения
резервных копий:
spec:
backup:
mountPath: /pico/backup # путь внутри пода, куда монтируется том
volume:
# Для production используйте NFS или другой тип тома с ReadWriteMany.
# hostPath подходит только для одноузловых кластеров (minikube).
nfs:
server: nfs.example.com
path: /exports/picodata-backup
Ограничения резервного копирования¶
- Резервная копия запускается только если все поды кластера готовы (
1/1 Running). При недоступности хотя бы одного пода бэкап перейдёт в фазуFailed - Для одного кластера одновременно может выполняться только один
PicoclusterBackup. - Хранилище резервных копий должно быть доступно на запись со всех нод кластера. Для multi-node окружений используйте NFS или другой том с поддержкой ReadWriteMany. Оператор проверяет доступность тома перед запуском бэкапа (preflight-проверка)
- При перезапуске пода в ходе бэкапа консистентность резервной копии не гарантируется.
Факт перезапуска фиксируется в
status.podSnapshotsдля последующей диагностики - По истечении
spec.backupTimeoutоператор прерывает операцию черезpico.abort_ddl(). Прерванный бэкап не пригоден для восстановления
Создание резервной копии¶
Создайте ресурс PicoclusterBackup:
apiVersion: picodata.picodata.io/v1
kind: PicoclusterBackup
metadata:
name: backup-1
namespace: picodata
spec:
clusterRef:
name: picodata # имя PicoclusterDB
backupTimeout: 3600 # максимальное время ожидания (секунды)
kubectl apply -f backup.yaml
Следите за статусом:
kubectl get picoclusterbackup -n picodata -w
NAME CLUSTER STATUS AGE
backup-1 picodata Succeeded 5m
Путь к сохранённой резервной копии:
kubectl get picoclusterbackup backup-1 -n picodata \
-o jsonpath='{.status.backupDir}'
Ограничения восстановления¶
- Восстановление — деструктивная операция: оператор останавливает весь кластер (scale до 0), стирает данные каждого инстанса и заменяет их содержимым снапшота
- Для одного кластера одновременно может выполняться только одна операция восстановления
- При
backupRefссылаемыйPicoclusterBackupдолжен быть в фазеSucceeded. - Если восстановление завершилось с ошибкой, кластер остаётся остановленным (все StatefulSet масштабированы до 0) для ручного разбора причин. Автоматического отката нет.
- Хранилище резервных копий должно быть смонтировано в те же поды, что и при
создании бэкапа: оператор ожидает структуру
<mountPath>/<instanceName>/<backupDir>/
Восстановление из резервной копии¶
Создайте ресурс PicoclusterRestore:
apiVersion: picodata.picodata.io/v1
kind: PicoclusterRestore
metadata:
name: restore-1
namespace: picodata
spec:
clusterRef:
name: picodata # имя PicoclusterDB для восстановления
backupRef:
name: backup-1 # ссылка на ресурс PicoclusterBackup
Если ресурс PicoclusterBackup был удалён, укажите директорию напрямую:
spec:
clusterRef:
name: picodata
backupDir: "20260508T143720" # имя поддиректории в томе резервных копий
kubectl apply -f restore.yaml
Anti-affinity¶
По умолчанию оператор автоматически добавляет правило podAntiAffinity,
которое запрещает размещение двух подов одного репликасета на одном узле
Kubernetes. Это гарантирует отказоустойчивость при потере узла.
Для развёртывания на одноузловом кластере (minikube, dev-окружение) отключите anti-affinity для нужного тира:
tiers:
- name: default
disableAutoAntiAffinity: true
Внимание!
Не отключайте anti-affinity в production: при потере узла могут упасть сразу несколько инстансов одного репликасета.
PodDisruptionBudget¶
Оператор автоматически создаёт PodDisruptionBudget для тиров с фактором
репликации ≥ 3. PDB ограничивает количество одновременно недоступных подов
при плановых операциях (drain ноды, обновление кластера Kubernetes), сохраняя
кворум кластера.
При необходимости выполнить drain на кластере без свободных нод — когда Kubernetes не может переместить поды — временно отключите PDB:
tiers:
- name: default
disablePDB: true
После завершения drain верните значение в false (или удалите поле).
Внимание!
Не оставляйте PDB отключённым в production. Без PDB плановое обслуживание узлов может нарушить кворум кластера.
Удаление кластера¶
kubectl delete picoclusterdb picodata -n picodata
Удаление CR автоматически удаляет все связанные ресурсы (StatefulSet, Service, ConfigMap) через механизм ownerReference.
Внимание!
PVC (постоянные тома с данными) при удалении CR не удаляются — это защита от случайной потери данных. Для полного удаления данных выполните:
kubectl delete pvc -n picodata --all
Мониторинг¶
Оператор поддерживает сбор метрик через Prometheus Operator. Включите
ServiceMonitor в манифесте кластера:
spec:
serviceMonitor:
enabled: true
interval: "30s"
При наличии Prometheus Operator в кластере метрики каждого инстанса Picodata
будут автоматически обнаружены и собираться с эндпоинта /metrics.
Читайте далее: