• Русский
  • Развертывание MySQL-MGR без TopoLVM

    В этом руководстве приведены инструкции по развертыванию экземпляров MySQL Group Replication (MGR) в кластерах, где TopoLVM недоступен, например в кластерах с MicroOS (SUSE Linux Enterprise Micro) или в других средах, использующих альтернативные provisioner’ы хранилища.

    Общая информация

    Проблема

    MySQL-MGR обычно полагается на TopoLVM для динамического выделения томов. Однако некоторые среды не поддерживают TopoLVM:

    • Кластеры MicroOS: корневая файловая система доступна только для чтения, и TopoLVM может быть не установлен.
    • Bare-metal-кластеры: некоторые кластеры используют локальное хранилище с ручным выделением PV.
    • Тестовые/оценочные среды: облегченные развертывания без TopoLVM.

    Без корректной настройки хранилища pod’ы MySQL не смогут запуститься из-за ошибок связывания PVC или проблем с правами доступа.

    Решение

    Используйте локальный StorageClass с вручную выделенными PersistentVolume (PV). В этом руководстве рассматриваются:

    • Установка зависимостей: убедитесь, что все необходимые operator’ы установлены перед развертыванием MySQL-MGR.
    • Создание StorageClass: настройте локальный StorageClass с привязкой WaitForFirstConsumer.
    • Выделение PV: создайте локальные PV с корректными путями, правами доступа и политиками очистки.
    • Исправление хранилища ClickHouse (необязательно): устраните ошибку read-only file system, вызванную жестко заданным host path плагина query-analytics.
    • Создание экземпляра: разверните MySQL-MGR, используя локальный StorageClass.

    Предварительные требования

    Необходимые operator’ы

    Перед развертыванием MySQL-MGR убедитесь, что в кластере установлены следующие основные operator’ы:

    OperatorНазначение
    application-services-coreОсновные службы платформы (включая etcd-sync, log-agent, стек мониторинга и т. д.)
    rds-operatorOperator службы реляционных баз данных

    Если вам нужны функции query analytics (логирование медленных запросов, анализ запросов), также потребуются следующие operator’ы:

    OperatorНазначение
    clickhouse-operatorOperator базы данных ClickHouse (используется query analytics)
    query-analytics-operatorАнализ запросов и логирование медленных запросов
    WARNING

    В файловых системах только для чтения (например, MicroOS) вы должны настроить путь хранения ClickHouse в RdsInstaller CR до установки query-analytics-operator. В противном случае operator немедленно создаст PV ClickHouse по пути по умолчанию /cpaas/ck, и это завершится ошибкой read-only file system. Подробности см. в Шаге 3.

    INFO

    Если ваш кластер использует TopoLVM, также потребуется topolvm-operator. Поскольку это руководство описывает развертывание без TopoLVM, он здесь не нужен.

    Вы можете проверить, что operator’ы установлены, просмотрев их CSV:

    kubectl get csv -A | grep -E "application-services-core|rds-operator|clickhouse-operator|query-analytics-operator"

    Во всех operator’ах в столбце PHASE должно отображаться значение Succeeded.

    Требования к кластеру

    • Для production-развертываний рекомендуется как минимум 3 worker-узла (MySQL-MGR требует 3 участников для кворума group replication). Для тестирования возможны развертывания с одним участником.
    • Достаточный объем CPU и памяти на каждом узле.
    • Доступный для записи путь каталога на всех узлах (например, /opt/local-pv/ в MicroOS).

    Шаг 1: Создайте локальный StorageClass

    Если в вашем кластере еще нет подходящего StorageClass, создайте его:

    kubectl apply -f - <<EOF
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: mgr-local-pv
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    EOF
    WARNING

    volumeBindingMode: WaitForFirstConsumer требуется, чтобы PV связывались только после того, как pod будет запланирован на конкретный узел. Это обеспечивает локальность данных.

    INFO

    Имя StorageClass произвольное. В этом руководстве используется mgr-local-pv, чтобы отличать его от динамического provisioner’а Rancher local-path. Вы можете использовать любое имя, но в последующих шагах должны ссылаться на него последовательно.

    Шаг 2: Выделите локальные PersistentVolume

    Каждому участнику MySQL-MGR требуется один PV. Для кластера с 3 участниками создайте как минимум 3 PV, распределив их по разным узлам.

    Создайте каталоги на узлах

    В MicroOS корневая файловая система доступна только для чтения. Используйте /opt/local-pv/ в качестве базового пути:

    # Запустите на каждом worker-узле или используйте privileged pod
    for i in $(seq 1 9); do
      mkdir -p /opt/local-pv/pv$i
      chmod 777 /opt/local-pv/pv$i
    done
    WARNING
    • Путь: в MicroOS не используйте /data или другие пути на уровне корня — это завершится ошибкой read-only file system. Вместо этого используйте /opt/local-pv/.
    • Права доступа: chmod 777 — это удобный обходной вариант, потому что контейнеры MySQL запускаются от имени пользователя non-root с UID/GID, которые могут не совпадать с хостом. Без прав на запись mysqld --initialize завершится ошибкой Permission denied. Для production-сред рекомендуется назначать владельцем конкретный UID, используемый контейнером MySQL (обычно 999:999), вместо использования 777.
    • Устаревшие данные: если вы повторно используете каталоги PV, сначала удалите все существующие файлы с помощью rm -rf /opt/local-pv/pvN/*. Инициализация MySQL завершается с ошибкой, если каталог данных не пуст.

    Создайте ресурсы PV

    Сначала определите имена узлов:

    kubectl get nodes -o wide

    Затем создайте PV, сопоставив каждый с конкретным узлом. Для кластера с 3 участниками на 3 узлах:

    # Определите имена узлов
    NODE1=<node1-hostname>
    NODE2=<node2-hostname>
    NODE3=<node3-hostname>
    
    # Создайте 3 PV на каждый узел (всего 9), чтобы обеспечить масштабирование и повторное выделение
    nodes=("$NODE1" "$NODE2" "$NODE3")
    for n in "${!nodes[@]}"; do
      node="${nodes[$n]}"
      for i in 1 2 3; do
        idx=$(( n * 3 + i ))
        kubectl apply -f - <<EOF
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: local-pv-$idx
    spec:
      capacity:
        storage: 20Gi
      volumeMode: Filesystem
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Delete
      storageClassName: mgr-local-pv
      local:
        path: /opt/local-pv/pv$idx
      nodeAffinity:
        required:
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                    - $node
    EOF
      done
    done

    Проверьте, что все PV созданы и доступны:

    kubectl get pv | grep mgr-local-pv

    Перед продолжением все PV должны иметь статус Available.

    INFO
    • Используйте persistentVolumeReclaimPolicy: Delete вместо Retain. При Retain PV после удаления PVC переходят в состояние Released и не могут быть повторно использованы без ручной очистки.
    • Обратите внимание, что для вручную выделенных локальных PV удаление объекта PV не очищает данные на диске автоматически. Перед повторным использованием вам все равно может понадобиться вручную очистить каталоги.
    • Создавайте больше PV, чем минимально требуется, чтобы обеспечить масштабирование и повторное выделение. Однако дополнительные PV не помогают при отказоустойчивости: если узел будет потерян, привязанные к нему PV не могут быть перенесены. Восстановление после потери узла требует ручного повторного выделения и повторной синхронизации данных.

    Шаг 3 (необязательно): Настройте путь хранения ClickHouse в файловых системах только для чтения

    INFO

    Этот шаг нужен только если вы планируете использовать функции query analytics (логирование медленных запросов, анализ запросов). Если query analytics не используется, пропустите этот шаг — экземпляры MySQL-MGR будут работать нормально и без него.

    Плагин query-analytics разворачивает ClickHouse с помощью PV на каталоге хоста. По умолчанию host path — /cpaas/ck. В MicroOS или других системах с корневой файловой системой только для чтения это приводит к тому, что pod’ы ClickHouse завершаются с ошибкой:

    mkdir /cpaas: read-only file system
    WARNING

    Вы должны настроить hostPath до установки query-analytics-operator. Слияние RdsInstaller → QueryAnalyticsInstaller выполняется только при первом создании CR QueryAnalyticsInstaller (qai). После установки operator’а CR qai уже существует, и последующие изменения в RdsInstaller не будут применены. Чтобы восстановить уже существующее развертывание, см. Исправление существующего развертывания.

    Настройте hostPath перед установкой query-analytics-operator

    1. Сначала установите rds-operator (если он еще не установлен). CR RdsInstaller создается rds-operator во время инициализации.

    2. Найдите ресурс RdsInstaller:

      kubectl get rdsinstaller -A
    3. Отредактируйте RdsInstaller, чтобы переопределить host path ClickHouse:

      kubectl edit rdsinstaller <name> -n <namespace>

      Установите spec.slowSQLCK.hostPath в путь на узле, доступный для записи:

      spec:
        slowSQLCK:
          hostPath: /opt/local-pv/ck
      INFO

      В MicroOS используйте путь внутри /opt/ (например, /opt/local-pv/ck). Каталог будет создан автоматически с типом DirectoryOrCreate.

    4. Теперь установите clickhouse-operator и query-analytics-operator. PV ClickHouse будет создан с использованием настроенного пути вместо значения по умолчанию /cpaas/ck.

    Исправление существующего развертывания с неправильным hostPath

    Если query-analytics-operator уже установлен с путем по умолчанию, а pod’ы ClickHouse не запускаются, одного изменения RdsInstaller.spec.slowSQLCK.hostPath недостаточно — слияние в QueryAnalyticsInstaller выполняется только при первом создании qai. Вам также нужно принудительно пересоздать qai (или отредактировать qai напрямую).

    Вариант A — пересоздать qai, чтобы слияние выполнилось повторно:

    1. Обновите RdsInstaller, как описано в процедуре перед установкой выше:

      kubectl edit rdsinstaller <name> -n <namespace>
      # set spec.slowSQLCK.hostPath: /opt/local-pv/ck
    2. Удалите установку ClickHouse и старый PV:

      kubectl delete chi pxc-ck -n <clickhouse-namespace>
      kubectl get pv | grep pxc-ck
      kubectl delete pv <pv-name>
    3. Удалите CR QueryAnalyticsInstaller. query-analytics-operator пересоздаст его, объединив обновленные настройки RdsInstaller:

      kubectl delete qai qai
    4. Проверьте новый hostPath:

      kubectl get qai qai -o jsonpath='{.spec.slowSQL.hostPath}{"\n"}'
      kubectl get pv pxc-ck-pv -o jsonpath='{.spec.hostPath.path}{"\n"}'

      В обоих случаях должен отображаться настроенный путь (например, /opt/local-pv/ck).

    Вариант B — отредактировать qai напрямую (быстрее, но RdsInstaller будет расходиться с qai до следующего пересоздания):

    kubectl edit qai qai
    # set spec.slowSQL.hostPath: /opt/local-pv/ck
    kubectl delete chi pxc-ck -n <clickhouse-namespace>
    kubectl delete pv <old-pv-name>

    query-analytics-operator пересоздаст установку ClickHouse и PV, используя путь, заданный в qai.

    Шаг 4: Создайте экземпляр MySQL-MGR

    1. Создайте secret с паролем:

      kubectl -n ${namespace} create secret generic mgr-${instance_name}-password \
        --from-literal=clusterchecker=${password} \
        --from-literal=exporter=${password} \
        --from-literal=manage=${password} \
        --from-literal=root=${password}
    2. Создайте MySQL CR с локальным StorageClass:

      kubectl apply -n ${namespace} -f - <<EOF
      apiVersion: middleware.alauda.io/v1
      kind: Mysql
      metadata:
        labels:
          mysql/arch: mgr
        name: ${instance_name}
      spec:
        mgr:
          enableStorage: true
          members: 3
          monitor:
            enable: true
          resources:
            server:
              limits:
                cpu: "2"
                memory: 4Gi
              requests:
                cpu: "2"
                memory: 4Gi
          router:
            replicas: 2
            resources:
              limits:
                cpu: 800m
                memory: 640Mi
              requests:
                cpu: 800m
                memory: 640Mi
            svcRO:
              type: ClusterIP
            svcRW:
              type: ClusterIP
          volumeClaimTemplate:
            spec:
              resources:
                requests:
                  storage: 20Gi
              storageClassName: mgr-local-pv
        params:
          mysql:
            mysqld:
              character_set_server: utf8mb4
              default_storage_engine: InnoDB
              default_time_zone: "+08:00"
        version: "8.0"
      EOF
      INFO
      • Secret с паролем должен соответствовать соглашению об именовании mgr-${instance_name}-password. Operator обнаруживает его автоматически по этому имени.
      • Укажите storageClassName: mgr-local-pv (или имя вашего StorageClass) в секции volumeClaimTemplate. Это заменяет значение по умолчанию sc-topolvm.
      • Поле version обязательно. Для MySQL 8.0 используйте "8.0".
    3. Отслеживайте состояние экземпляра:

      kubectl get mysql ${instance_name} -n ${namespace} -w

      Дождитесь, пока поле STATE станет ready.

    4. Проверьте привязку PVC и размещение pod’ов:

      kubectl get pvc -n ${namespace}
      kubectl get pod -n ${namespace} -o wide | grep ${instance_name}

      Убедитесь, что каждый PVC привязан к PV и что pod’ы распределены по разным узлам.

    Устранение неполадок

    PVC застряли в состоянии Pending

    Симптом: PVC остаются в состоянии Pending, а pod’ы не планируются.

    Причина: Нет доступных PV, соответствующих имени StorageClass или node affinity, либо PV находятся в состоянии Released.

    Исправление:

    # Проверьте статус PV
    kubectl get pv | grep mgr-local-pv
    # Проверьте события PVC для подробностей
    kubectl describe pvc -n <namespace> <pvc-name>
    # Убедитесь, что имя StorageClass совпадает у PV и PVC
    kubectl get pv <pv-name> -o jsonpath='{.spec.storageClassName}'

    MySQL pod’ы застряли в CrashLoopBackOff

    Симптом: pod’ы MySQL аварийно завершаются с Permission denied во время инициализации.

    Причина: У каталогов PV нет прав на запись для non-root пользователя MySQL.

    Исправление:

    # На узле, где запланирован pod
    chmod 777 /opt/local-pv/pvN

    MySQL pod’ы завершаются с ошибкой "data directory has files in it"

    Симптом: mysqld --initialize завершается с ошибкой, потому что каталог данных не пуст.

    Причина: Каталог PV содержит устаревшие данные от предыдущего развертывания.

    Исправление:

    # На узле или через privileged pod
    rm -rf /opt/local-pv/pvN/*

    PV застряли в состоянии Released

    Симптом: PV имеют статус Released и не могут быть привязаны к новым PVC.

    Причина: PV были созданы с persistentVolumeReclaimPolicy: Retain.

    Исправление: Удалите PV в состоянии Released и создайте их заново с persistentVolumeReclaimPolicy: Delete:

    kubectl delete pv <pv-name>
    # Затем пересоздайте, следуя Шагу 2

    Экземпляр застрял в состоянии ErrorReconcile

    Симптом: У экземпляра MySQL отображается условие ErrorReconcile, а поле STATE имеет значение available вместо ready, хотя все pod’ы запущены.

    Причина: Цикл reconcile operator’а столкнулся с ошибкой конфликта при обновлении статуса CR.

    Исправление: Добавьте аннотацию в MySQL CR, чтобы инициировать повторную reconciliation:

    kubectl annotate mysql ${instance_name} -n ${namespace} \
      force-reconcile="$(date +%s)" --overwrite

    Pod’ы ClickHouse завершаются с ошибкой "read-only file system"

    Симптом: Pod’ы ClickHouse не запускаются и завершаются с ошибкой mkdir /cpaas: read-only file system.

    Причина: Host path ClickHouse по умолчанию в плагине query-analytics (/cpaas/ck) не существует в файловых системах только для чтения.

    Исправление: Следуйте Шагу 3, чтобы задать в CR RdsInstaller значение spec.slowSQLCK.hostPath на путь, доступный для записи.