Déployer des conteneurs Linux SQL Server sur Kubernetes avec StatefulSets
S’applique à : SQL Server - Linux
Cet article contient des bonnes pratiques et des conseils pour l’exécution de conteneurs SQL Server sur Kubernetes avec StatefulSets. Nous vous recommandons de déployer un conteneur (instance) SQL Server pour chaque pod dans Kubernetes. Ainsi, vous disposez d’une instance SQL Server déployée pour chaque pod dans le cluster Kubernetes.
De même, la recommandation du script de déploiement est de déployer une instance SQL Server en définissant la valeur de replicas
sur 1
. Si vous entrez un nombre supérieur à 1
pour la valeur replicas
, vous obtenez ce nombre d’instances SQL avec des noms corrélés. Par exemple, dans le script ci-dessous, si vous avez affecté le nombre 2
comme valeur pour replicas
, vous allez déployer deux pods SQL Server, respectivement avec les noms mssql-0
et mssql-1
.
Une autre raison pour laquelle nous recommandons un seul SQL Server par script de déploiement est de permettre que les modifications des valeurs de configuration, de l’édition, des indicateurs de trace et d’autres paramètres soient effectuées indépendamment pour chaque instance SQL Server déployée.
Dans l’exemple suivant, le nom de la charge de travail StatefulSet doit correspondre à la valeur de .spec.template.metadata.labels
, qui est dans ce cas mssql
. Pour plus d’informations, consultez StatefulSets.
Important
La variable d’environnement SA_PASSWORD
est dépréciée. Utilisez MSSQL_SA_PASSWORD
à la place.
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:2019-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
Si vous choisissez néanmoins de déployer plusieurs réplicas de l’instance SQL Server en utilisant le même déploiement, vous trouverez ce scénario décrit dans la section suivante. Cependant, il s’agit d’instances SQL Server indépendantes distinctes et non pas de réplicas (contrairement aux réplicas de groupe de disponibilité dans SQL Server).
Choisir le type de charge de travail
Le choix du type de déploiement de charge de travail approprié n’affecte pas les performances, mais StatefulSet répond aux exigences de persistance des identités.
Charges de travail StatefulSet
SQL Server est une application de base de données et elle doit donc principalement être déployée en tant que type de charge de travail StatefulSet. Le déploiement de charges de travail en tant que StatefulSet permet de fournir des fonctionnalités comme des identifiants réseau uniques, un stockage persistant et stable, etc. Pour plus d’informations sur ce type de charge de travail, consultez la documentation Kubernetes.
Lors du déploiement de plusieurs réplicas de conteneurs SQL Server en utilisant le même script YAML de déploiement qu’une charge de travail StatefulSet, un paramètre important à prendre en compte est Stratégies de gestion des pods, c’est-à-dire .spec.podManagementPolicy
.
Deux valeurs sont possibles pour ce paramètre :
OrderedReady : c’est la valeur par défaut, et le comportement est celui décrit dans les garanties de déploiement et de mise à l’échelle.
Parallel : c’est la stratégie alternative qui crée et lance les pods (dans le cas présent, les pods SQL Server) en parallèle, sans attendre que d’autres pods soient créés. De même, tous les pods sont supprimés en parallèle lors de l’arrêt. Vous pouvez utiliser cette option quand vous déployez des instances SQL Server indépendantes les unes des autres, et quand vous n’avez pas l’intention de suivre un ordre pour démarrer ou supprimer les instances 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:2019-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
Comme les pods SQL Server déployés sur Kubernetes sont indépendants les uns des autres, Parallel
est la valeur normalement utilisée pour podManagementPolicy
.
L’exemple suivant est l’exemple de sortie pour kubectl get all
, juste après la création des pods en utilisant une stratégie parallèle :
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
Charges de travail de déploiement
Vous pouvez utiliser le type déploiement pour SQL Server dans les scénarios où vous voulez déployer des conteneurs SQL Server en tant qu’applications de base de données sans état, par exemple quand la persistance des données n’est pas critique. Vous utilisez cela par exemple à des fins de test/assurance qualité ou pour la CI/CD.
Isolation via des espaces de noms
Les espaces de noms fournissent un mécanisme permettant d’isoler des groupes de ressources au sein d’un même cluster Kubernetes. Pour plus d’informations sur les espaces de noms et quand les utiliser, consultez Espaces de noms.
Du point de vue de SQL Server, si vous envisagez d’exécuter des pods SQL Server sur un cluster Kubernetes qui héberge également d’autres ressources, vous devez exécuter les pods SQL Server dans leur propre espace de noms afin de faciliter la gestion et l’administration. Par exemple, supposez que vous avez plusieurs départements partageant le même cluster Kubernetes, et que vous voulez déployer une instance SQL Server pour l’équipe Ventes et une autre pour l’équipe Marketing. Vous allez créer deux espaces de noms appelés sales
et marketing
, comme illustré dans l’exemple suivant :
kubectl create namespace sales
kubectl create namespace marketing
Pour vérifier que les espaces de noms sont créés, exécutez kubectl get namespaces
, et vous verrez une liste similaire à la sortie suivante.
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
Vous pouvez maintenant déployer des conteneurs SQL Server dans chacun de ces espaces de noms en utilisant l’exemple YAML illustré dans l’exemple suivant. Notez que les métadonnées namespace
ont été ajoutées au fichier YAML de déploiement, de sorte que tous les conteneurs et services de ce déploiement sont déployés dans l’espace de noms 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:2019-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
Pour voir les ressources, vous pouvez exécuter la commande kubectl get all
en spécifiant l’espace de noms :
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
Les espaces de noms peuvent également être utilisés pour limiter les ressources et les pods créés au sein d’un espace de noms, en utilisant la plage de limites et/ou des stratégies de quota de ressources, afin de gérer la création globale des ressources au sein d’un espace de noms.
Configurer la qualité de service des pods
Quand vous déployez plusieurs pods sur un même cluster Kubernetes, vous devez partager les ressources de façon appropriée pour garantir l’exécution efficace du cluster Kubernetes. Vous pouvez configurer les pods de façon à qu’ils bénéficient d’une qualité de service (QoS) particulière.
Kubernetes utilise des classes de qualité de service pour prendre des décisions concernant la planification et l’éviction des pods. Pour plus d’informations sur les différentes classes de qualité de service, consultez Configurer la qualité de service pour les pods.
Du point de vue SQL Server, nous vous recommandons de déployer les pods SQL Server en utilisant la qualité de service Guaranteed
pour les charges de travail en production. Étant donné qu’un pod SQL Server n’a qu’une seule instance de conteneur SQL Server en cours d’exécution pour satisfaire à la garantie de qualité de service pour ce pod, vous devez spécifier que les demandes de processeur et de mémoire pour le conteneur doivent être égales aux limites de mémoire et de processeur. Ceci garantit que les nœuds fournissent et valident les ressources requises spécifiées lors du déploiement et qu’ils offrent des performances prévisibles pour les pods SQL Server.
Voici un exemple de déploiement YAML qui déploie un conteneur SQL Server dans l’espace de noms par défaut. Étant donné que les demandes de ressources n’ont pas été spécifiées, mais que les limites ont été spécifiées conformément aux instructions de l’exemple de qualité de service garantie, nous constatons que la valeur QoS (Qualité de service) du pod créé dans l’exemple suivant est définie sur Guaranteed
. Quand vous ne spécifiez pas les demandes de ressources, Kubernetes considère que les limites de ressources sont égales aux demandes de ressources.
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:2019-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
Vous pouvez exécuter la commande kubectl describe pod mssql-0
pour voir que la qualité de service est définie sur Guaranteed
, avec une sortie similaire à l’extrait de code suivant.
...
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
...
Pour les charges de travail hors production, où les performances et la disponibilité ne sont pas une priorité, vous pouvez envisager de définir la qualité de service sur Burstable
ou BestEffort
.
Exemple de qualité de service burstable
Pour définir un exemple YAML Burstable
, vous spécifiez les demandes de ressources et non pas les limites de ressources, ou bien vous spécifiez les limites, qui sont supérieures aux demandes. Le code suivant montre seulement la différence par rapport à l’exemple précédent, afin de définir une charge de travail burstable .
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:2019-latest
resources:
requests:
memory: 2Gi
cpu: '2'
Vous pouvez exécuter la commande kubectl describe pod mssql-0
pour voir que la qualité de service est définie sur Burstable
, avec une sortie similaire à l’extrait de code suivant.
...
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
...
Exemple de qualité de service « meilleure possibilité » (best effort)
Pour définir un exemple YAML BestEffort
, supprimez les demandes de ressources et les limites de ressources. Vous obtenez alors la qualité de service « meilleure possibilité », comme défini dans Créer un pod qui reçoit une classe de qualité de service « BestEffort ». Comme précédemment, le code suivant montre seulement la différence par rapport à l’exemple Guaranteed
, afin de définir une charge de travail « meilleure possibilité » (best effort). Ce sont les options les moins recommandées pour les pods SQL Server, car ils seraient probablement les premiers à être arrêtés en cas de contention des ressources. Même pour les scénarios de test et d’assurance qualité, nous vous recommandons d’utiliser l’option Burstable pour 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:2019-latest
ports:
- containerPort: 1433
Vous pouvez exécuter la commande kubectl describe pod mssql-0
pour voir que la qualité de service est définie sur BestEffort
, avec une sortie similaire à l’extrait de code suivant.
...
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
...