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

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

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

    Проблема

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

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

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

    Решение

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

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

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

    Требуемые operators

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

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

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

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

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

    INFO

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

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

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

    Все operators должны иметь статус Succeeded в столбце PHASE.

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

    • Для 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, чтобы отличать его от динамического провиженера Rancher local-path. Вы можете использовать любое имя, но должны последовательно ссылаться на него на последующих шагах.

    Шаг 2: Подготовьте локальные PersistentVolumes

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

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

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

    # Выполните на каждом worker-узле или используйте привилегированный 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 или другие пути на уровне root — они завершатся ошибкой read-only file system. Вместо этого используйте /opt/local-pv/.
    • Права доступа: chmod 777 — это временный обходной вариант, поскольку контейнеры MySQL запускаются от имени пользователя без root-прав, чей UID/GID может не совпадать с хостом. Без прав на запись mysqld --initialize завершится ошибкой Permission denied. В production-средах вместо 777 рассмотрите вариант назначения владельца с конкретным UID, который использует контейнер MySQL (обычно 999:999).
    • Старые данные: если вы переиспользуете каталоги 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 -l '!pv-is-managed' | grep mgr-local-pv

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

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

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

    INFO

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

    Плагин query-analytics развертывает ClickHouse, используя PV с host directory. По умолчанию 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. Создайте CR MySQL с локальным 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 обязательно. Используйте "8.0" для MySQL 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.

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

    # Check PV status
    kubectl get pv | grep mgr-local-pv
    # Check PVC events for details
    kubectl describe pvc -n <namespace> <pvc-name>
    # Verify StorageClass name matches between PV and PVC
    kubectl get pv <pv-name> -o jsonpath='{.spec.storageClassName}'

    Pod'ы MySQL застряли в CrashLoopBackOff

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

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

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

    # On the node where the pod is scheduled
    chmod 777 /opt/local-pv/pvN

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

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

    Причина: В каталоге PV остались старые данные от предыдущего развертывания.

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

    # On the node, or via a 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>
    # Then recreate following Step 2

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

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

    Причина: В цикле reconcile operator возникла ошибка конфликта при обновлении статуса CR.

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

    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.

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

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