Развертывание контейнеров SQL Server Linux в Kubernetes с помощью StatefulSets
Область применения: SQL Server — Linux
В этой статье содержатся лучшие практики и рекомендации по запуску контейнеров SQL Server в Kubernetes с помощью StatefulSets. Мы рекомендуем развернуть один контейнер SQL Server (экземпляр) для каждого модуля pod в Kubernetes. Таким образом, в каждом поде кластера Kubernetes развернут один экземпляр SQL Server.
Аналогично, рекомендованный скрипт развертывания заключается в развертывании одного экземпляра SQL Server, установив значение 1
для replicas
. Если ввести число больше, чем 1
в качестве значения replicas
, вы получите такое количество экземпляров SQL Server с коррелирующими именами. Например, в приведенном ниже сценарии, если вы назначили номер 2
в качестве значения для replicas
, необходимо развернуть два пода 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
При развертывании нескольких подов в одном кластере Kubernetes необходимо правильно распределять ресурсы, чтобы обеспечить эффективную работу кластера Kubernetes. Вы можете сконфигурировать поды так, чтобы им было назначено определенное качество обслуживания (QoS).
Kubernetes использует классы качества обслуживания для принятия решений о планировании и вытеснении pod. Дополнительные сведения о различных классах качества обслуживания см. в разделе "Настройка качества обслуживания для модулей Pod".
С точки зрения SQL Server, рекомендуется развертывать pod’ы SQL Server, используя QoS Guaranteed
для рабочих нагрузок в продакшене. Учитывая, что модуль pod SQL Server имеет только один экземпляр контейнера SQL Server, работающий для обеспечения гарантированного качества обслуживания для этого модуля, необходимо указать запросы ЦП и памяти для контейнера, который должен быть равен ограничениям памяти и ЦП. Это гарантирует, что узлы обеспечивают и резервируют необходимые ресурсы, указанные во время развертывания, и имеют прогнозируемую производительность для pods SQL Server.
Ниже приведен пример YAML для развертывания, который разворачивает один контейнер SQL Server в пространстве имен по умолчанию. Запросы на ресурсы не были указаны, но лимиты заданы в соответствии с рекомендациями в примере гарантированного качества обслуживания. В результате, pod, созданный в следующем примере, имеет QoS, установленное как Guaranteed
. Если запросы ресурсов не указаны, 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
...
Пример QoS с методикой Best Effort
Чтобы определить BestEffort
пример на YAML, удалите запросы ресурсов и лимиты ресурсов . В конечном итоге вы получите класс обслуживания по принципу BestEffort, как описано в Создании pod с назначенным классом QoS BestEffort. Как и раньше, следующий код отображает только разницу от Guaranteed
примера, чтобы определить оптимальную рабочую нагрузку. Это наименее рекомендуемые варианты для подов 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
...