Delen via


SQL Server Linux-containers implementeren in Kubernetes met StatefulSets

van toepassing op:SQL Server- - Linux

Dit artikel bevat aanbevolen procedures en richtlijnen voor het uitvoeren van SQL Server-containers in Kubernetes met StatefulSets. U wordt aangeraden één SQL Server-container (instantie) per pod in Kubernetes te implementeren. U hebt dus één SQL Server-exemplaar geïmplementeerd per pod in het Kubernetes-cluster.

Op dezelfde manier is de aanbeveling voor het implementatiescript om één SQL Server-exemplaar te implementeren door de replicas waarde in te stellen op 1. Wanneer u een getal invoert dat groter is dan 1 als de replicas waarde, krijgt u dat aantal SQL Server-exemplaren met vergelijkbare namen. Als u in het onderstaande script bijvoorbeeld het aantal 2 als waarde voor replicashebt toegewezen, implementeert u twee SQL Server-pods, met respectievelijk de namen mssql-0 en mssql-1.

Een andere reden waarom we één SQL Server per implementatiescript aanbevelen, is om wijzigingen in configuratiewaarden, edities, traceringsvlagmen en andere instellingen onafhankelijk toe te staan voor elk GEÏMPLEMENTEERD SQL Server-exemplaar.

In het volgende voorbeeld moet de naam van de StatefulSet-workload overeenkomen met de .spec.template.metadata.labels waarde, die in dit geval mssqlis. Zie StatefulSetsvoor meer informatie.

Belangrijk

De omgevingsvariabele SA_PASSWORD is afgeschaft. Gebruik in plaats daarvan 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

Als u er nog steeds voor kiest om meer dan één replica van het SQL Server-exemplaar te implementeren met dezelfde implementatie, wordt dat scenario behandeld in de volgende sectie. Dit zijn echter afzonderlijke onafhankelijke SQL Server-exemplaren en geen replica's (in tegenstelling tot replica's van beschikbaarheidsgroepen in SQL Server).

Het workloadtype kiezen

Het kiezen van het juiste workloadimplementatietype heeft geen invloed op de prestaties, maar statefulSet biedt wel vereisten voor identiteitsstickerigheid.

StatefulSet-workloads

SQL Server is een databasetoepassing en moet dus meestal worden geïmplementeerd als een StatefulSet workloadtype. Het implementeren van workloads als StatefulSet helpt functies te bieden, zoals unieke netwerk-id's, permanente en stabiele opslag en meer. Raadpleeg de Kubernetes-documentatievoor meer informatie over dit type werkbelasting.

Wanneer u meer dan één replica van SQL Server-containers implementeert met hetzelfde YAML-implementatiescript als een StatefulSet-workload, is een belangrijke parameter die u moet overwegen Beleid voor podbeheer, dat wil gezegd .spec.podManagementPolicy.

Er zijn twee waarden mogelijk voor deze instelling:

  • OrderedReady-: Dit is de standaardwaarde en het gedrag is zoals beschreven in de implementatie- en schaalgaranties.

  • Parallel: Dit is het alternatieve beleid waarmee de pods (in dit geval SQL Server-pods) parallel worden gecreëerd en gestart, zonder te wachten tot andere pods worden gecreëerd. Evenzo worden alle pods parallel verwijderd tijdens beëindiging. U kunt deze optie gebruiken wanneer u SQL Server-exemplaren implementeert die onafhankelijk van elkaar zijn en wanneer u niet van plan bent een volgorde te volgen om de SQL Server-exemplaren te starten of te verwijderen.

    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
    

Omdat de SQL Server-pods die zijn geïmplementeerd op Kubernetes onafhankelijk van elkaar zijn, is Parallel de waarde die normaal gesproken wordt gebruikt voor podManagementPolicy.

Het volgende voorbeeld is de voorbeelduitvoer voor kubectl get all, net nadat u de pods hebt gemaakt met behulp van een parallelle strategie:

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

Uitrolworkloads

U kunt het -implementatietype voor SQL Server gebruiken in scenario's waarin u SQL Server-containers wilt implementeren als staatloze databasetoepassingen, bijvoorbeeld wanneer gegevenspersistentie niet kritiek is. Sommige voorbeelden hiervan zijn voor test-/QA- of CI/CD-doeleinden.

Isolatie via naamruimten

Naamruimten bieden een mechanisme voor het isoleren van groepen resources binnen één Kubernetes-cluster. Zie Naamruimtenvoor meer informatie over naamruimten en wanneer u deze kunt gebruiken.

Vanuit het perspectief van SQL Server, als u van plan bent om SQL Server-pods uit te voeren op een Kubernetes-cluster dat ook andere resources host, moet u de SQL Server-pods hun eigen naamruimte geven om het beheer en de administratie te vergemakkelijken. Stel dat u meerdere afdelingen hebt die hetzelfde Kubernetes-cluster delen en u een SQL Server-exemplaar wilt implementeren voor het verkoopteam en een andere voor het marketingteam. U maakt twee naamruimten met de naam sales en marketing, zoals wordt weergegeven in het volgende voorbeeld:

kubectl create namespace sales
kubectl create namespace marketing

Als u wilt controleren of de naamruimten zijn gemaakt, voert u kubectl get namespacesuit en ziet u een lijst die vergelijkbaar is met de volgende uitvoer.

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

U kunt nu SQL Server-containers implementeren in elk van deze naamruimten met behulp van de voorbeeld-YAML die in het volgende voorbeeld wordt weergegeven. Let op de namespace metagegevens die zijn toegevoegd aan de YAML-implementatie, zodat alle containers en services van deze implementatie worden geïmplementeerd in de sales naamruimte.

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

Als u de resources wilt zien, kunt u de opdracht kubectl get all uitvoeren met de naamruimte die is opgegeven om deze resources weer te geven:

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

Naamruimten kunnen ook worden gebruikt om de resources en pods te beperken die in een naamruimte zijn gemaakt, met behulp van het limietbereik en/of resourcequotum beleid, om het aanmaken van de totale resources binnen een naamruimte te beheren.

Pod Quality of Service configureren

Wanneer u meerdere pods implementeert op één Kubernetes-cluster, moet u resources op de juiste manier delen om ervoor te zorgen dat het Kubernetes-cluster efficiënt wordt uitgevoerd. U kunt pods zo configureren dat ze een bepaalde QoS (Quality of Service) krijgen toegewezen.

Kubernetes gebruikt QoS--klassen om beslissingen te maken over het plannen en verwijderen van pods. Zie Quality of Service configureren voor Podsvoor meer informatie over de verschillende QoS-klassen.

Vanuit het oogpunt van SQL Server raden we u aan SQL Server-pods te implementeren met behulp van QoS als Guaranteed voor op productie gebaseerde workloads. Aangezien voor een SQL Server-pod slechts één SQL Server-containerinstantie wordt uitgevoerd om gegarandeerde QoS voor die pod te bereiken, moet u de CPU en het geheugen opgeven aanvragen voor de container die gelijk moet zijn aan het geheugen en de CPU-limieten. Dit zorgt ervoor dat de knooppunten de vereiste resources leveren en doorvoeren die tijdens de implementatie zijn opgegeven en voorspelbare prestaties hebben voor de SQL Server-pods.

Hier volgt een voorbeeld van een YAML-implementatie waarmee één SQL Server-container in de standaardnaamruimte wordt geïmplementeerd. Omdat de resourceaanvragen niet zijn opgegeven, maar de limieten zijn opgegeven volgens de richtlijnen in het voorbeeld Gegarandeerde kwaliteit van de service, zien we dat de pod die in het volgende voorbeeld wordt gemaakt, de QoS is ingesteld als Guaranteed. Wanneer u de resourceaanvragen niet opgeeft, beschouwt Kubernetes de resource limieten gelijk aan de resource aanvragen.

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

U kunt de opdracht kubectl describe pod mssql-0 uitvoeren om de QoS weer te geven als Guaranteed, met uitvoer die vergelijkbaar is met het volgende fragment.

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

Voor niet-productieworkloads, waarbij prestaties en beschikbaarheid geen hoge prioriteit hebben, kunt u overwegen de QoS in te stellen op Burstable of BestEffort.

Voorbeeld van Burstable QoS

Als u een YAML-voorbeeld van een Burstable wilt definiëren, geeft u de resource aanvragen op, niet de resource limieten; of u geeft de limietenop, die hoger is dan aanvragen. In de volgende code wordt alleen het verschil van het vorige voorbeeld weergegeven om een burstable workload te definiëren.

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'

U kunt de opdracht kubectl describe pod mssql-0 uitvoeren om de QoS weer te geven als Burstable, met uitvoer die vergelijkbaar is met het volgende fragment.

...
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-voorbeeld van best effort

Om een YAML-voorbeeld van een BestEffort te definiëren, verwijder de resource verzoeken en resource limieten. U krijgt uiteindelijk de best effort QoS, zoals gedefinieerd in Een pod maken waaraan een QoS-klasse van BestEffortwordt toegewezen. Net als voorheen geeft de volgende code alleen het verschil weer van het Guaranteed voorbeeld om een best effort workload te definiëren. Dit zijn de minst aanbevolen opties voor SQL Server-pods, omdat ze waarschijnlijk de eerste zijn die moeten worden beëindigd in het geval van conflicten tussen resources. Zelfs voor test- en QA-scenario's raden we u aan om de optie Burstable voor SQL Server te gebruiken.

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

U kunt de opdracht kubectl describe pod mssql-0 uitvoeren om de QoS weer te geven als BestEffort, met uitvoer die vergelijkbaar is met het volgende fragment.

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

Geheugenlimieten configureren met besturingsgroep (cgroup) v2

Vanaf SQL Server 2025 (17.x) Preview en SQL Server 2022 (16.x) CU 20 detecteert en honoreert SQL Server controlegroep (cgroup) v2-beperkingen, waardoor prestatiestabiliteit en resourceisolatie in Docker-, Kubernetes- en OpenShift-omgevingen worden verbeterd. Besturingsgroepen maken fijnmazige controle mogelijk in de Linux-kernel over systeemresources, zoals CPU en geheugen.

Met ondersteuning voor cgroup v2 beperkt SQL Server geheugenfouten (OOM) die eerder werden waargenomen in containerimplementaties, met name op Kubernetes-clusters (bijvoorbeeld AKS v1.25+), waarbij geheugenlimieten die zijn gedefinieerd in containerspecificaties niet werden afgedwongen.

CGroup-versie controleren

stat -fc %T /sys/fs/cgroup

De resultaten zijn als volgt:

Resultaat Description
cgroup2fs U gebruikt cgroup v2
cgroup U gebruikt cgroup v1

Overschakelen naar cgroup v2

Het eenvoudigste pad is het kiezen van een distributie die ondersteuning biedt voor cgroup v2.

Als u handmatig moet overschakelen, voegt u de volgende regel toe aan uw GRUB-configuratie:

systemd.unified_cgroup_hierarchy=1

Voer vervolgens de volgende opdracht uit om GRUB bij te werken:

sudo update-grub

Zie de volgende bronnen voor meer informatie: