Поделиться через


Развертывание контейнеров SQL Server Linux в Kubernetes с помощью StatefulSets

Область применения: SQL Server — Linux

В этой статье содержатся рекомендации и рекомендации по запуску контейнеров SQL Server в Kubernetes с помощью StatefulSets. Мы рекомендуем развернуть один контейнер SQL Server (экземпляр) для каждого модуля pod в Kubernetes. Таким образом, в кластере Kubernetes развернут один экземпляр SQL Server.

Аналогичным образом, рекомендация по скрипту развертывания заключается в развертывании одного экземпляра replicas SQL Server путем задания значения 1. Если ввести число больше 1 replicas значения, вы получите, что многие экземпляры SQL Server со связанными именами. Например, в приведенном ниже сценарии, если вы назначили номер в качестве значения 2 replicas, необходимо развернуть два модуля pod SQL Server с именами mssql-0 и mssql-1 соответственно.

Другая причина, по которой рекомендуется использовать один sql Server для каждого сценария развертывания, заключается в том, чтобы разрешить изменения значений конфигурации, выпусков, флагов трассировки и других параметров для каждого развернутого экземпляра SQL Server.

В следующем примере имя рабочей нагрузки StatefulSet должно соответствовать .spec.template.metadata.labels значению, которое в данном случае является mssql. Дополнительные сведения см. в разделе StatefulSets.

Внимание

Переменная среды SA_PASSWORD является нерекомендуемой. Вместо этого используйте MSSQL_SA_PASSWORD.

apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql # name of the StatefulSet workload, the SQL Server instance name is derived from this. We suggest to keep this name same as the .spec.template.metadata.labels, .spec.selector.matchLabels and .spec.serviceName to avoid confusion.
spec:
 serviceName: "mssql" # serviceName is the name of the service that governs this StatefulSet. This service must exist before the StatefulSet, and is responsible for the network identity of the set.
 replicas: 1 # only one pod, with one SQL Server instance deployed.
 selector:
  matchLabels:
   app: mssql  # this has to be the same as .spec.template.metadata.labels
 template:
  metadata:
   labels:
    app: mssql # this has to be the same as .spec.selector.matchLabels, as documented [here](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/):
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql # container name within the pod.
     image: mcr.microsoft.com/mssql/server:2022-latest
     ports:
     - containerPort: 1433
       name: tcpsql
     env:
     - name: ACCEPT_EULA
       value: "Y"
     - name: MSSQL_ENABLE_HADR
       value: "1"
     - name: MSSQL_AGENT_ENABLED
       value: "1"
     - name: MSSQL_SA_PASSWORD
       valueFrom:
         secretKeyRef:
          name: mssql
          key: MSSQL_SA_PASSWORD
     volumeMounts:
     - name: mssql
       mountPath: "/var/opt/mssql"
 volumeClaimTemplates:
   - metadata:
      name: mssql
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi

Если вы по-прежнему решили развернуть несколько реплик экземпляра SQL Server с помощью одного развертывания, этот сценарий рассматривается в следующем разделе. Однако это отдельные независимые экземпляры SQL Server, а не реплики (в отличие от реплик групп доступности в SQL Server).

Выбор типа рабочей нагрузки

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

Рабочие нагрузки StatefulSet

SQL Server — это приложение базы данных, поэтому в основном следует развертывать как тип рабочей нагрузки StatefulSet . Развертывание рабочих нагрузок в качестве StatefulSet помогает предоставлять такие функции, как уникальные сетевые идентификации, постоянное и стабильное хранилище и многое другое. Дополнительные сведения об этом типе рабочей нагрузки см. в документации Kubernetes.

При развертывании нескольких реплик контейнеров SQL Server с использованием того же скрипта развертывания YAML, что и рабочая нагрузка StatefulSet, важно учитывать политики управления pod, то есть .spec.podManagementPolicy.

Для этого параметра возможны два значения:

  • OrderedReady: это значение по умолчанию, и поведение, как описано в гарантиях развертывания и масштабирования.

  • Параллельно. Это альтернативная политика, которая создает и запускает модули pod (в данном случае sql Server pod) параллельно, не ожидая создания других модулей pod аналогично, все модули pod удаляются параллельно во время завершения. Этот параметр можно использовать при развертывании экземпляров SQL Server, которые не зависят друг от друга, и если вы не планируете выполнять порядок запуска или удаления экземпляров SQL Server.

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mssql
    spec:
      serviceName: "mssql"
      replicas: 2 # two independent SQL Server instances to be deployed
      podManagementPolicy: Parallel
      selector:
        matchLabels:
          app: mssql
      template:
        metadata:
          labels:
            app: mssql
        spec:
          securityContext:
            fsGroup: 10001
          containers:
            - name: mssql
              image: mcr.microsoft.com/mssql/server:2022-latest
              ports:
                - containerPort: 1433
                  name: tcpsql
              env:
                - name: ACCEPT_EULA
                  value: "Y"
                - name: MSSQL_ENABLE_HADR
                  value: "1"
                - name: MSSQL_AGENT_ENABLED
                  value: "1"
                - name: MSSQL_SA_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: mssql
                      key: MSSQL_SA_PASSWORD
              volumeMounts:
                - name: mssql
                  mountPath: "/var/opt/mssql"
      volumeClaimTemplates:
        - metadata:
            name: mssql
          spec:
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 8Gi
    

Так как модули pod SQL Server, развернутые в Kubernetes, не зависят друг от друга, Parallel обычно используется для podManagementPolicy.

В следующем примере приведен пример выходных данных для kubectl get allсразу после создания модулей pod с помощью параллельной политики:

NAME          READY   STATUS              RESTARTS   AGE
pod/mssql-0   0/1     ContainerCreating   0          4s
pod/mssql-1   0/1     ContainerCreating   0          4s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   201.0.0.1    <none>        443/TCP   61d

NAME                     READY   AGE
statefulset.apps/mssql   1/1     4s

Рабочие нагрузки развертывания

Тип развертывания для SQL Server можно использовать в сценариях, в которых требуется развернуть контейнеры SQL Server в качестве приложений базы данных без отслеживания состояния, например если сохраняемость данных не является критической. Некоторые из таких примеров предназначены для целей тестирования/QA или CI/CD.

Изоляция через пространства имен

Пространства имен предоставляют механизм изоляции групп ресурсов в одном кластере Kubernetes. Дополнительные сведения о пространствах имен и их использовании см. в разделе "Пространства имен".

С точки зрения SQL Server, если вы планируете запускать модули pod SQL Server в кластере Kubernetes, который также размещает другие ресурсы, следует запускать модули pod SQL Server в собственном пространстве имен, чтобы упростить управление и администрирование. Например, рассмотрите возможность совместного использования нескольких отделов в одном кластере Kubernetes, и вы хотите развернуть экземпляр SQL Server для группы продаж и другую для группы маркетинга. Вы создадите два пространства sales имен и marketing, как показано в следующем примере:

kubectl create namespace sales
kubectl create namespace marketing

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

NAME              STATUS   AGE
default           Active   39d
kube-node-lease   Active   39d
kube-public       Active   39d
kube-system       Active   39d
marketing         Active   7s
sales             Active   26m

Теперь можно развернуть контейнеры SQL Server в каждом из этих пространств имен с помощью примера YAML, показанного в следующем примере. Обратите внимание, что метаданные namespace , добавленные в YAML развертывания, поэтому все контейнеры и службы этого развертывания развертываются в sales пространстве имен.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azure-disk
provisioner: kubernetes.io/azure-disk
parameters:
  storageAccountType: Standard_LRS
  kind: Managed
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mssql-sales
  namespace: sales
  labels:
    app: mssql-sales
spec:
  serviceName: "mssql-sales"
  replicas: 1
  selector:
    matchLabels:
      app: mssql-sales
  template:
    metadata:
      labels:
        app: mssql-sales
    spec:
      securityContext:
        fsGroup: 10001
      containers:
        - name: mssql-sales
          image: mcr.microsoft.com/mssql/server:2022-latest
          ports:
            - containerPort: 1433
              name: tcpsql
          env:
            - name: ACCEPT_EULA
              value: "Y"
            - name: MSSQL_ENABLE_HADR
              value: "1"
            - name: MSSQL_AGENT_ENABLED
              value: "1"
            - name: MSSQL_SA_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mssql
                  key: MSSQL_SA_PASSWORD
          volumeMounts:
            - name: mssql
              mountPath: "/var/opt/mssql"
  volumeClaimTemplates:
    - metadata:
        name: mssql
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 8Gi
---
apiVersion: v1
kind: Service
metadata:
  name: mssql-sales-0
  namespace: sales
spec:
  type: LoadBalancer
  selector:
    statefulset.kubernetes.io/pod-name: mssql-sales-0
  ports:
    - protocol: TCP
      port: 1433
      targetPort: 1433
      name: tcpsql

Чтобы просмотреть ресурсы, можно выполнить kubectl get all команду с указанным пространством имен, чтобы просмотреть следующие ресурсы:

kubectl get all -n sales
NAME                READY   STATUS    RESTARTS   AGE
pod/mssql-sales-0   1/1     Running   0          17m

NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/mssql-sales-0   LoadBalancer   10.0.251.120   20.23.79.52   1433:32052/TCP   17m

NAME                           READY   AGE
statefulset.apps/mssql-sales   1/1     17m

Пространства имен также можно использовать для ограничения ресурсов и модулей pod, созданных в пространстве имен, с помощью диапазонов ограничений и (или) политик квот ресурсов для управления общими ресурсами в пространстве имен.

Настройка качества обслуживания pod

При развертывании нескольких модулей pod в одном кластере Kubernetes необходимо совместно использовать ресурсы, чтобы обеспечить эффективное выполнение кластера Kubernetes. Вы можете настроить модули pod таким образом, чтобы они назначили определенное качество обслуживания (QoS).

Kubernetes использует классы качества обслуживания для принятия решений о планировании и вытеснения модулей pod. Дополнительные сведения о различных классах качества обслуживания см. в разделе "Настройка качества обслуживания для модулей Pod".

С точки зрения SQL Server рекомендуется развертывать модули pod SQL Server с помощью QoS Guaranteed для рабочих нагрузок на основе рабочих нагрузок. Учитывая, что модуль pod SQL Server имеет только один экземпляр контейнера SQL Server, работающий для обеспечения гарантированного качества обслуживания для этого модуля, необходимо указать запросы ЦП и памяти для контейнера, который должен быть равен ограничениям памяти и ЦП. Это гарантирует, что узлы предоставляют и фиксируют необходимые ресурсы, указанные во время развертывания, и имеют прогнозируемую производительность для модулей pod SQL Server.

Ниже приведен пример развертывания YAML, который развертывает один контейнер SQL Server в пространстве имен по умолчанию, и так как запросы ресурсов не указаны, но ограничения были указаны в соответствии с рекомендациями в примере гарантированного качества обслуживания , мы видим, что модуль pod, созданный в следующем примере, имеет значение GuaranteedQoS. Если запросы ресурсов не указаны, Kubernetes учитывает ограничения ресурсов, равные запросам ресурсов.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
     name: azure-disk
provisioner: kubernetes.io/azure-disk
parameters:
  storageaccounttype: Standard_LRS
  kind: Managed
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql
 labels:
  app: mssql
spec:
 serviceName: "mssql"
 replicas: 1
 selector:
  matchLabels:
   app: mssql
 template:
  metadata:
   labels:
    app: mssql
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql
     command:
       - /bin/bash
       - -c
       - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
     image: mcr.microsoft.com/mssql/server:2022-latest
     resources:
      limits:
       memory: 2Gi
       cpu: '2'
     ports:
     - containerPort: 1433
     env:
     - name: ACCEPT_EULA
       value: "Y"
     - name: MSSQL_ENABLE_HADR
       value: "1"
     - name: MSSQL_SA_PASSWORD
       valueFrom:
         secretKeyRef:
          name: mssql
          key: MSSQL_SA_PASSWORD
     volumeMounts:
     - name: mssql
       mountPath: "/var/opt/mssql"
     - name: userdata
       mountPath: "/var/opt/mssql/userdata"
     - name: userlog
       mountPath: "/var/opt/mssql/userlog"
     - name: tempdb
       mountPath: "/var/opt/mssql/tempdb"
     - name: mssql-config-volume
       mountPath: "/var/opt/config"
   volumes:
     - name: mssql-config-volume
       configMap:
        name: mssql
 volumeClaimTemplates:
   - metadata:
      name: mssql
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: userdata
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: userlog
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi
   - metadata:
      name: tempdb
     spec:
      accessModes:
      - ReadWriteOnce
      resources:
       requests:
        storage: 8Gi

Вы можете запустить команду kubectl describe pod mssql-0 , чтобы просмотреть QoS как Guaranteedи выходные данные, аналогичные приведенному ниже фрагменту кода.

...
QoS Class:                 Guaranteed
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...

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

Пример с возможностью ускорения качества обслуживания

Чтобы определить Burstable пример YAML, укажите запросы ресурсов, а не ограничения ресурсов, или укажите ограничения, которые выше, чем запросы. Следующий код отображает только разницу в предыдущем примере, чтобы определить рабочая нагрузка с возможностью ускорения .

apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: mssql
 labels:
  app: mssql
spec:
 serviceName: "mssql"
 replicas: 1
 selector:
  matchLabels:
   app: mssql
 template:
  metadata:
   labels:
    app: mssql
  spec:
   securityContext:
     fsGroup: 10001
   containers:
   - name: mssql
     command:
       - /bin/bash
       - -c
       - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
     image: mcr.microsoft.com/mssql/server:2022-latest
     resources:
      requests:
       memory: 2Gi
       cpu: '2'

Вы можете запустить команду kubectl describe pod mssql-0 , чтобы просмотреть QoS как Burstableи выходные данные, аналогичные приведенному ниже фрагменту кода.

...
QoS Class:                 Burstable
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...

Лучший пример качества обслуживания

Чтобы определить BestEffort пример YAML, удалите запросы ресурсов и ограничения ресурсов. В конечном итоге вы получите лучшие усилия QoS, как определено в разделе "Создание pod", который получает назначенный класс QoS bestEffort. Как и раньше, следующий код отображает только разницу от Guaranteed примера, чтобы определить оптимальную рабочую нагрузку. Это наименее рекомендуемые варианты для модулей pod SQL Server, так как они, вероятно, будут первыми, которые должны быть завершены в случае состязания ресурсов. Даже в сценариях тестирования и качества обслуживания рекомендуется использовать параметр "Ускорение" для SQL Server.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mssql
  labels:
    app: mssql
spec:
  serviceName: "mssql"
  replicas: 1
  selector:
    matchLabels:
      app: mssql
  template:
    metadata:
      labels:
        app: mssql
    spec:
      securityContext:
        fsGroup: 10001
      containers:
        - name: mssql
          command:
            - /bin/bash
            - -c
            - cp /var/opt/config/mssql.conf /var/opt/mssql/mssql.conf && /opt/mssql/bin/sqlservr
          image: mcr.microsoft.com/mssql/server:2022-latest
          ports:
            - containerPort: 1433

Вы можете запустить команду kubectl describe pod mssql-0 , чтобы просмотреть QoS как BestEffortи выходные данные, аналогичные приведенному ниже фрагменту кода.

...
QoS Class:                 BestEffort
Node-Selectors:            <none>
Tolerations:               node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                           node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                           node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
...