Share via


Bereitstellen von SQL Server-Linux-Containern in Kubernetes mit StatefulSets

Gilt für:SQL Server – Linux

Dieser Artikel enthält bewährte Methoden und Leitfäden zum Ausführen von SQL Server-Containern in Kubernetes mit StatefulSets. Es wird empfohlen, pro Pod einen SQL Server-Container (Instanz) in Kubernetes bereitzustellen. So verfügen Sie über eine SQL Server-Instanz, die pro Pod im Kubernetes-Cluster bereitgestellt wird.

Entsprechend lautet die Empfehlung des Bereitstellungsskripts, eine SQL Server-Instanz bereitzustellen, indem Sie den Wert von replicas auf 1 festlegen. Wenn Sie eine größere Zahl als 1 als Wert von replicas eingeben, erhalten Sie entsprechend viele SQL Server-Instanzen mit ähnlichen Namen. Wenn Sie beispielsweise im folgenden Skript die Zahl 2 als Wert für replicas zugewiesen haben, stellen Sie zwei SQL Server-Pods mit den Namen mssql-0 bzw. mssql-1 bereit.

Ein weiterer Grund, warum eine SQL Server-Instanz pro Bereitstellungsskript empfohlen wird, besteht darin, dass es dadurch möglich ist, Änderungen an Konfigurationswerten, Editionen, Ablaufverfolgungsflags und anderen Einstellungen unabhängig für jede bereitgestellte SQL Server-Instanz vorzunehmen.

Im folgenden Beispiel sollte der Name der StatefulSet-Workload mit dem Wert von .spec.template.metadata.labels übereinstimmen, der in diesem Fall mssql lautet. Weitere Informationen finden Sie unter StatefulSets.

Wichtig

Die Umgebungsvariable SA_PASSWORD ist veraltet. Verwenden Sie stattdessen 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: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

Ein Szenario, in dem Sie mehrere Replikate der SQL Server-Instanz mithilfe derselben Bereitstellung bereitstellen, wird im nächsten Abschnitt behandelt. Dies sind jedoch separate unabhängige SQL Server-Instanzen und keine Replikate (im Gegensatz zu Verfügbarkeitsgruppenreplikaten in SQL Server).

Auswählen des Workloadtyps

Die Auswahl des richtigen Workloadbereitstellungstyps wirkt sich nicht auf die Leistung aus, aber das StatefulSet stellt Anforderungen an die Identitätsbindung.

StatefulSet-Workloads

SQL Server ist eine Datenbankanwendung und sollte daher typischerweise als StatefulSet-Workloadtyp bereitgestellt werden. Durch die Bereitstellung von Workloads als StatefulSet können Sie Features wie eindeutige Netzwerkkennungen, persistenten und stabilen Speicher und vieles mehr bereitstellen. Weitere Informationen zu diesem Workloadtyp finden Sie in der Kubernetes-Dokumentation.

Bei der Bereitstellung von mehreren Replikaten von SQL Server-Containern mit demselben YAML-Bereitstellungsskript wie für eine StatefulSet-Workload müssen Podverwaltungsrichtlinien berücksichtigt werden, d. h. .spec.podManagementPolicy.

Für diese Einstellung sind zwei Werte möglich:

  • OrderedReady: Dies ist der Standardwert, und das Verhalten entspricht dem in den Bereitstellungs- und Skalierungsgarantien beschriebenen Verhalten.

  • Parallel: Dies ist eine alternative Richtlinie, mit der die Pods (in diesem Fall SQL Server-Pods) parallel erstellt und gestartet werden, ohne darauf zu warten, dass andere Pods erstellt werden. Auf dieselbe Weise werden die Pods beim Beenden auch entfernt. Sie können diese Option verwenden, wenn Sie unabhängige SQL Server-Instanzen bereitstellen und wenn Sie nicht beabsichtigen, eine bestimmte Reihenfolge zum Starten oder Löschen der SQL Server-Instanzen zu befolgen.

    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
    

Da die in Kubernetes bereitgestellten SQL Server-Pods unabhängig voneinander sind, wird normalerweise der Wert Parallel für podManagementPolicy verwendet.

Das folgende Beispiel ist die Beispielausgabe für kubectl get all direkt nach dem Erstellen der Pods mithilfe einer parallelen Richtlinie:

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

Bereitstellungsworkloads

Sie können den Bereitstellungstyp für SQL Server in Szenarien verwenden, in denen Sie SQL Server-Container als zustandslose Datenbankanwendungen bereitstellen möchten, z. B. wenn die Datenpersistenz nicht wichtig ist. Einige Beispiele hierfür dienen zu Test-/QA- oder CI/CD-Zwecken.

Isolation über Namespaces

Namespaces bieten einen Mechanismus für das Isolieren von Ressourcengruppen in einem einzelnen Kubernetes-Cluster. Weitere Informationen zu Namespaces und deren Verwendung finden Sie unter Namespaces.

Wenn Sie planen, SQL Server-Pods in einem Kubernetes-Cluster auszuführen, der auch andere Ressourcen hostet, sollten Sie die SQL Server-Pods aus Sicht von SQL Server in einem eigenen Namespace ausführen, um die Verwaltung zu vereinfachen. Stellen Sie sich beispielsweise vor, dass mehrere Abteilungen denselben Kubernetes-Cluster nutzen und Sie eine SQL Server-Instanz für das Vertriebsteam und eine andere für das Marketingteam bereitstellen möchten. Sie erstellen in diesem Fall zwei Namespaces mit den Namen sales und marketing, wie im folgenden Beispiel gezeigt:

kubectl create namespace sales
kubectl create namespace marketing

Um zu überprüfen, ob die Namespaces erstellt wurden, führen Sie kubectl get namespaces aus. Damit zeigen Sie eine Liste ähnlich der folgenden Ausgabe an.

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

Nun können Sie SQL Server-Container in jedem dieser Namespaces mithilfe des YAML-Codes bereitstellen, der im folgenden Beispiel gezeigt wird. Beachten Sie die namespace-Metadaten, die der YAML-Bereitstellung hinzugefügt wurden und die bewirken, dass alle Container und Dienste dieser Bereitstellung im Namespace sales bereitgestellt werden.

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

Um die Ressourcen anzuzeigen, können Sie den Befehl kubectl get all unter Angabe des Namespace ausführen, um die folgenden Ressourcen anzuzeigen:

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

Namespaces können auch verwendet werden, um die Ressourcen und Pods einzugrenzen, die in einem Namespace erstellt werden. Dazu verwenden Sie den Grenzwertbereich und/oder Richtlinien für das Ressourcenkontingent, um die gesamte Ressourcenerstellung innerhalb eines Namespace zu verwalten.

Konfigurieren der Servicequalität für Pods

Wenn Sie mehrere Pods in einem einzelnen Kubernetes-Cluster bereitstellen, müssen Sie Ressourcen so freigeben, dass eine effiziente Ausführung des Kubernetes-Clusters sichergestellt ist. Sie können Pods so konfigurieren, dass ihnen eine bestimmte Servicequalität (Quality of Service, QoS) zugewiesen wird.

Kubernetes verwendet QoS-Klassen, um Entscheidungen zur Planung und Entfernung von Pods zu treffen. Weitere Informationen zu den verschiedenen QoS-Klassen finden Sie unter Konfigurieren der Servicequalität für Pods.

Aus SQL Server-Perspektive wird empfohlen, SQL Server-Pods mit der Servicequalität Guaranteed für produktionsbasierte Workloads bereitzustellen. Da ein SQL Server-Pod nur über eine SQL Server-Containerinstanz verfügt, die ausgeführt wird, um eine garantierte Servicequalität für diesen Pod zu erreichen, müssen Sie die CPU- und Arbeitsspeicheranforderungen für den Container angeben. Diese sollten den Grenzwerten für Arbeitsspeicher und CPU entsprechen. Dadurch wird sichergestellt, dass die Knoten die erforderlichen Ressourcen bereitstellen und committen, die während der Bereitstellung angegeben werden, und eine vorhersagbare Leistung für die SQL Server-Pods aufweisen.

Das folgende Beispiel für YAML-Bereitstellungscode stellt einen SQL Server-Container im Standardnamespace bereit. Da zwar keine Ressourcenanforderungen, aber Grenzwerte gemäß den Richtlinien im Beispiel für garantierte Dienstqualität angegeben wurden, können Sie sehen, dass für den Pod, der im folgenden Beispiel erstellt wurde, die Servicequalität auf Guaranteed festgelegt wurde. Wenn Sie die Ressourcenanforderungen nicht angeben, verwendet Kubernetes als Ressourcengrenzwerte die Ressourcenanforderungen.

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

Sie können den Befehl kubectl describe pod mssql-0 ausführen, um die Servicequalität Guaranteed anzuzeigen. Die Ausgabe ähnelt dem folgenden Codeschnipsel.

...
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
...

Für Nicht-Produktionsworkloads, bei denen Leistung und Verfügbarkeit keine hohe Priorität haben, können Sie erwägen, die Servicequalität auf Burstable oder BestEffort festzulegen.

Beispiel für burstfähiges Servicequalität

Um ein Burstable YAML-Beispiel zu definieren, geben Sie die Ressourcenanforderungen und nicht die Ressourcengrenzwerte an. Sie können auch Grenzwerte angeben, die höher als die Anforderungen sind. Im folgenden Code werden nur die Unterschiede zum vorherigen Beispiel angezeigt, die erforderlich sind, um eine burstfähige Workload zu definieren.

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'

Sie können den Befehl kubectl describe pod mssql-0 ausführen, um die Servicequalität Burstable anzuzeigen. Die Ausgabe ähnelt dem folgenden Codeschnipsel.

...
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
...

Beispiel für Servicequalität „BestEffort“

Um ein BestEffort-YAML-Beispiel zu definieren, entfernen Sie die Ressourcenanforderungen und Ressourcengrenzwerte. Damit erhalten Sie eine Servicequalität der BestEffort-Klasse wie unter Create a Pod that gets assigned a QoS class of BestEffort (Erstellen eines Pods mit der QoS-Klasse „BestEffort“) definiert. Auch im hier folgenden Code werden nur die Unterschiede zum Guaranteed-Beispiel angezeigt, die erforderlich sind, um eine BestEffort-Workload zu definieren. Diese Optionen werden für SQL Server-Pods nur eingeschränkt empfohlen, da sie wahrscheinlich die ersten wären, die im Fall eines Ressourcenkonflikts beendet werden. Auch für Test- und QA-Szenarien wird die Verwendung der burstfähigen Option für SQL Server empfohlen.

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

Sie können den Befehl kubectl describe pod mssql-0 ausführen, um die Servicequalität BestEffort anzuzeigen. Die Ausgabe ähnelt dem folgenden Codeschnipsel.

...
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
...