Гайд по настройке отказоустойчивого кластера SQL Server Always On в Kubernetes с помощью DH2i

Подробный гайд по настройке отказоустойчивого кластера SQL Server Always On в Kubernetes с помощью DH2i DxEnterprise. Автоматическое управление VIP и failover.

2026.08.20                  


Настройка отказоустойчивого кластера SQL Server Always On в Kubernetes с помощью DH2iНастройка отказоустойчивого кластера SQL Server Always On в Kubernetes с помощью DH2i Развертывание кластеров высокой доступности (Always On Availability Groups — AG) для SQL Server в Kubernetes с использованием DH2i DxEnterprise — это мощное решение. DxEnterprise берёт на себя управление виртуальным IP-адресом (VIP) для слушателя (Listener) и оркестрацию отказоустойчивости, что избавляет от необходимости использовать сложные внешние балансировщики или нативные K8s-операторы, которые часто ограничены в функционале.




Архитектура решения

В данной конфигурации мы используем:

  • StatefulSet для запуска подов SQL Server.
  • DxEnterprise работает либо как sidecar-контейнер, либо интегрирован в образ SQL Server (рекомендуемый подход DH2i).
  • Headless Service для внутренней DNS-резолвинга подов.
  • Service типа LoadBalancer (или управление "сырым" VIP через CNI) для предоставления единой точки входа (Listener) для клиентов.

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

  1. Кластер Kubernetes (версии 1.22+).
  2. Лицензии на SQL Server (Enterprise) и DH2i DxEnterprise.
  3. Утилиты: kubectl, доступ к кластеру, клиент dxcli (можно установить на любую машину с доступом к подам или использовать внутри пода).
  4. Хранилище: StorageClass для создания PersistentVolumeClaims (PVC) под данные SQL и конфигурацию DxEnterprise.

Шаг 1. Создание Secret и ConfigMap

Нам необходимо безопасно передать пароли и конфигурацию.

1. Секреты для паролей:

# Пароль для SA в SQL Server
kubectl create secret generic mssql-secret --from-literal=MSSQL_SA_PASSWORD='YourStrong!Passw0rd'

# Пароль администратора для кластера DxEnterprise
kubectl create secret generic dxenterprise-secret --from-literal=DX_PASSWORD='DxAdmin!Pass123'

2. ConfigMap для конфигурации DxEnterprise:

Создайте файл dxenterprise-cm.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: dxenterprise-config
data:
  dxenterprise.conf: |
    [CLUSTER]
    ClusterName=sql-ag-cluster
    VirtualIP=10.0.5.100  # IP, который будет "плавать" между нодами (Listener)
    VirtualMask=255.255.255.0
    # Если используете облако (AKS/EKS), VIP может управляться через LoadBalancer, 
    # тогда этот блок настраивается согласно документации DH2i для вашего CNI/Cloud.

Примените:

kubectl apply -f dxenterprise-cm.yaml

Шаг 2. Настройка хранилища (PVC)

SQL Server и DxEnterprise требуют персистентного хранилища.

Создайте файл pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mssql-data
spec:
  accessModes: [ "ReadWriteOnce" ]
  resources:
    requests:
      storage: 50Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dxenterprise-data
spec:
  accessModes: [ "ReadWriteOnce" ]
  resources:
    requests:
      storage: 5Gi

Примечание:

В реальном StatefulSet для каждого пода будут создаваться свои PVC через volumeClaimTemplates. Здесь упрощенный вид для понимания.


Шаг 3. Создание StatefulSet для SQL Server и DxEnterprise

Создайте файл sql-statefulset.yaml. Мы будем запускать 3 реплики (1 Primary, 2 Secondary).

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sql-ag
spec:
  serviceName: "sql-ag-headless"
  replicas: 3
  selector:
    matchLabels:
      app: sql-ag
  template:
    metadata:
      labels:
        app: sql-ag
    spec:
      containers:
      - name: mssql-dx
        # Используйте официальный образ DH2i или соберите свой, включающий SQL и DxEnterprise
        image: dh2i/dxenterprise-sql:2022-latest 
        ports:
        - containerPort: 1433 # SQL
        - containerPort: 7979 # DxEnterprise
        env:
        - name: MSSQL_SA_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mssql-secret
              key: MSSQL_SA_PASSWORD
        - name: MSSQL_PID
          value: "Developer" # Или "Enterprise"
        - name: ACCEPT_EULA
          value: "Y"
        - name: MSSQL_AGENT_ENABLED
          value: "true"
        # Включение Always On High Availability
        - name: MSSQL_ENABLE_HADR
          value: "1" 
        volumeMounts:
        - name: mssql-data
          mountPath: /var/opt/mssql
        - name: dx-data
          mountPath: /var/opt/dh2i
      - name: dxenterprise-sidecar # Если используется раздельная архитектура
        image: dh2i/dxenterprise:latest
        env:
        - name: DX_PASSWORD
          valueFrom:
            secretKeyRef:
              name: dxenterprise-secret
              key: DX_PASSWORD
        volumeMounts:
        - name: dx-config
          mountPath: /etc/dh2i
        - name: dx-data
          mountPath: /var/opt/dh2i
      volumes:
      - name: dx-config
        configMap:
          name: dxenterprise-config
  volumeClaimTemplates:
  - metadata:
      name: mssql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 50Gi
  - metadata:
      name: dx-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 5Gi



Примените:

kubectl apply -f sql-statefulset.yaml

Шаг 4. Создание Service (Headless и Listener)

1. Headless Service (для DNS подов: sql-ag-0.sql-ag-headless, sql-ag-1...):

apiVersion: v1
kind: Service
metadata:
  name: sql-ag-headless
spec:
  clusterIP: None
  selector:
    app: sql-ag
  ports:
  - port: 1433
    name: mssql
  - port: 7979
    name: dxenterprise

2. Service для Listener (Виртуальный IP)

В Kubernetes "плавающий" VIP от DxEnterprise чаще всего пробрасывается наружу через LoadBalancer.

apiVersion: v1
kind: Service
metadata:
  name: sql-ag-listener
  annotations:
    # Специфичные аннотации для вашего облака/CNI, если требуется привязка к конкретному IP
    service.beta.kubernetes.io/aws-load-balancer-internal: "true" 
spec:
  type: LoadBalancer
  selector:
    app: sql-ag
  ports:
  - port: 1433
    targetPort: 1433

Шаг 5. Инициализация кластера DxEnterprise и SQL AG

После того как поды перешли в статус Running, нужно инициализировать кластер.

Зайдите в первый под (он станет Primary):

kubectl exec -it sql-ag-0 -c dxenterprise-sidecar -- /bin/bash
# Если DxEnterprise интегрирован в один контейнер, просто: kubectl exec -it sql-ag-0 -- /bin/bash

1. Создание кластера DxEnterprise:

# Инициализация на первом узле
dxcli create-cluster -c sql-ag-cluster -p 'DxAdmin!Pass123'

# Добавление второго и третьего узлов (используйте DNS имена подов)
dxcli add-node -n sql-ag-1 -i sql-ag-1.sql-ag-headless -p 'DxAdmin!Pass123'
dxcli add-node -n sql-ag-2 -i sql-ag-2.sql-ag-headless -p 'DxAdmin!Pass123'

2. Настройка SQL Server и создание Availability Group:

Вам нужно подключиться к SQL Server на каждом узле и выполнить T-SQL скрипты.

Подключитесь к Primary (sql-ag-0):

-- Создание сертификатов и endpoints (упрощенный вариант, в продакшене используйте правильную криптографию)
CREATE ENDPOINT [Hadr_endpoint] 
STATE=STARTED 
AS TCP (LISTENER_PORT = 5022, LISTENER_IP = ALL)
FOR DATA_MIRRORING (ROLE = ALL, AUTHENTICATION = CERTIFICATE [auto_cert], ENCRYPTION = REQUIRED ALGORITHM AES);
GO

-- Создание Availability Group
CREATE AVAILABILITY GROUP [SQL-AG]
WITH (AUTOMATIC_CLUSTER_OPERATION = ON) -- Если используется DH2i, он сам управляет кворумом
FOR DATABASE [YourDatabase]
REPLICA ON 
N'sql-ag-0' WITH (ENDPOINT_URL = N'TCP://sql-ag-0.sql-ag-headless:5022', FAILOVER_MODE = AUTOMATIC, AVAILABILITY_MODE = SYNCHRONOUS_COMMIT, SEEDING_MODE = AUTOMATIC),
N'sql-ag-1' WITH (ENDPOINT_URL = N'TCP://sql-ag-1.sql-ag-headless:5022', FAILOVER_MODE = AUTOMATIC, AVAILABILITY_MODE = SYNCHRONOUS_COMMIT, SEEDING_MODE = AUTOMATIC),
N'sql-ag-2' WITH (ENDPOINT_URL = N'TCP://sql-ag-2.sql-ag-headless:5022', FAILOVER_MODE = AUTOMATIC, AVAILABILITY_MODE = SYNCHRONOUS_COMMIT, SEEDING_MODE = AUTOMATIC);
GO


На репликах sql-ag-1 и sql-ag-2 необходимо выполнить ALTER AVAILABILITY GROUP [SQL-AG] JOIN; и ALTER AVAILABILITY GROUP [SQL-AG] GRANT CREATE ANY DATABASE;.

3. Добавление Virtual IP в DxEnterprise:

Вернитесь в консоль dxcli и добавьте VIP, который будет слушать порт 1433 для клиентов:

dxcli add-virtual-ip -v 10.0.5.100 -m 255.255.255.0 -n sql-ag-0

(DxEnterprise автоматически настроит маршрутизацию и будет перемещать этот VIP на активную ноду при сбое).


Шаг 6. Проверка и тестирование отказоустойчивости

1. Проверка статуса кластера:

dxcli get-cluster-info
dxcli get-ag-info

Вы должны увидеть, что sql-ag-0 является Primary, а VIP привязан к нему.

2. Тестирование Failover:

Удалите под Primary, чтобы симулировать сбой:

kubectl delete pod sql-ag-0

Наблюдайте за логами DxEnterprise на оставшихся нодах:

kubectl logs -f sql-ag-1 -c dxenterprise-sidecar

DxEnterprise обнаружит потерю кворума/связи, переведет sql-ag-1 в роль Primary, запустит failover самой Availability Group (через интеграцию с SQL) и переместит Virtual IP на sql-ag-1.

3. Проверка подключения:

Попробуйте подключиться к базе данных, используя IP-адрес вашего LoadBalancer или "плавающий" VIP. Подключение должно восстановиться автоматически через несколько секунд после завершения failover.


Важные нюансы для Kubernetes (Денис Сергеевич, обратите на них внимание)

1. Управление VIP в CNI:

Если вы используете "голый" Kubernetes (Bare Metal) и стандартные CNI (Calico, Flannel), "плавающий" VIP на уровне L2 может не работать из коробки. DH2i рекомендует использовать их специализированные плагины для CNI или настраивать VIP через BGP (например, с использованием MetalLB в связке с DxEnterprise). Если вы в облаке (AWS, Azure, GCP), используйте type: LoadBalancer, а DxEnterprise будет балансировать трафик внутри кластера.

2. Задержки (Latency):

Убедитесь, что задержка между нодами K8s минимальна (обычно < 10 мс для синхронной репликации). Размещайте поды в разных зонах доступности (Availability Zones), но учитывайте, что (cross-region) задержка потребует изменения AVAILABILITY_MODE на ASYNCHRONOUS_COMMIT.

3. Resource Limits:

Обязательно задайте requests и limits для CPU и RAM в StatefulSet. SQL Server в контейнерах очень чувствителен к нехватке памяти (OOMKilled), что приведет к ложным срабатываниям failover.

4. Лицензирование:

DH2i DxEnterprise лицензируется по ядрам или по нодам. Убедитесь, что ваша лицензия покрывает количество используемых подов/нод.


Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.


Статью подготовил: Аверко Денис Сергеевич @Nymexis г. Омск (специалист по ЗИ)

Комментарии

Загрузка...
Если комментарии не загружаются, можете попробовать отключить блокировщик рекламы для этого сайта