Vorgehensweise: Verwenden verteilter Transaktionen mit SQL Server-Linux-Containern

Gilt für:SQL Server unter Linux

In diesem Artikel wird erläutert, wie Sie SQL Server-Linux-Container für verteilte Transaktionen einrichten, einschließlich Sonderanforderungen und spezifischer Szenarien.

Containerimages für SQL Server können den Microsoft Distributed Transaction Coordinator (MSDTC) nutzen, der für verteilte Transaktionen erforderlich ist. Informationen zu den Kommunikationsanforderungen für MS DTC finden Sie unter Konfigurieren des Microsoft Distributed Transaction Coordinator (MS DTC) unter Linux.

Note

SQL Server 2017 (14.x)-Instanzen werden standardmäßig in Rootcontainern ausgeführt, während Container mit SQL Server 2019 (15.x) oder höher als Benutzer ohne Rootberechtigung ausgeführt werden.

Konfiguration

Um MSDTC-Transaktionen in SQL Server-Containern zu ermöglichen, müssen Sie zwei Umweltvariablen festlegen:

  • MSSQL_RPC_PORT: der TCP-Port, an den der RPC Endpoint Mapper-Dienst bindet und auf dem er abhört.
  • MSSQL_DTC_TCP_PORT: der Port, auf dem der MSDTC-Dienst so konfiguriert ist, dass er lauscht.

Pullen und Ausführen

Im folgenden Beispiel wird gezeigt, wie diese Umgebungsvariablen verwendet werden, um einen einzelnen für MS DTC konfigurierten SQL Server 2017-Container zu pullen und auszuführen. Dies ermöglicht es, mit jeder Anwendung auf jedem Host zu kommunizieren.

Important

Die Umgebungsvariable SA_PASSWORD ist veraltet. Verwenden Sie stattdessen MSSQL_SA_PASSWORD.

docker run \
   -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=<password>' \
   -e 'MSSQL_RPC_PORT=135' -e 'MSSQL_DTC_TCP_PORT=51000' \
   -p 51433:1433 -p 135:135 -p 51000:51000  \
   -d mcr.microsoft.com/mssql/server:2017-latest
docker run `
   -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=<password>" `
   -e "MSSQL_RPC_PORT=135" -e "MSSQL_DTC_TCP_PORT=51000" `
   -p 51433:1433 -p 135:135 -p 51000:51000  `
   -d mcr.microsoft.com/mssql/server:2017-latest

Im folgenden Beispiel wird gezeigt, wie diese Umgebungsvariablen verwendet werden, um einen einzelnen für MS DTC konfigurierten SQL Server 2019 (15.x)-Container zu pullen und auszuführen. Dies ermöglicht es, mit jeder Anwendung auf jedem Host zu kommunizieren.

Important

Die Umgebungsvariable SA_PASSWORD ist veraltet. Verwenden Sie stattdessen MSSQL_SA_PASSWORD.

docker run \
   -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=<password>' \
   -e 'MSSQL_RPC_PORT=135' -e 'MSSQL_DTC_TCP_PORT=51000' \
   -p 51433:1433 -p 135:135 -p 51000:51000  \
   -d mcr.microsoft.com/mssql/server:2019-GA-ubuntu-20.04
docker run `
   -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=<password>" `
   -e "MSSQL_RPC_PORT=135" -e "MSSQL_DTC_TCP_PORT=51000" `
   -p 51433:1433 -p 135:135 -p 51000:51000  `
   -d mcr.microsoft.com/mssql/server:2019-GA-ubuntu-20.04

Caution

Ihr Kennwort sollte der standardmäßigen Kennwortrichtlinie von SQL Server folgen. Standardmäßig muss das Kennwort mindestens acht Zeichen lang sein und Zeichen aus drei der folgenden vier Sätze enthalten: Großbuchstaben, Kleinbuchstaben, Basis-10 Ziffern und Symbole. Kennwörter können bis zu 128 Zeichen lang sein. Verwenden Sie möglichst lange und komplexe Kennwörter.

In diesem Befehl ist der RPC-Endpunktzuordnungs-Dienst an Port 135 gebunden, und der MS DTC-Dienst wurde an Port 51000 innerhalb des virtuellen Netzwerks des Containers gebunden. SQL Server-TDS-Kommunikation erfolgt an Port 1433, ebenfalls innerhalb des virtuellen Netzwerks des Containers. Diese Ports sind extern dem Host zugänglich als TDS-Port 51433, RPC-Endpunktmapper-Port 135 und MSDTC-Port 51000.

Die RPC Endpoint Mapper- und MSDTC-Ports müssen nicht auf dem Host und im Container gleich sein. Während der RPC Endpoint Mapper-Port im Container auf 135 konfiguriert war, könnte er potenziell auf Port 13501 oder einen anderen verfügbaren Port auf dem Hostserver zugeordnet werden.

Konfigurieren der Firewall

Um mit und über den Host zu kommunizieren, müssen Sie auch die Firewall auf dem Hostserver für die Container konfigurieren. Öffnen Sie die Firewall für alle Ports, die der SQL Server-Container für die externe Kommunikation verfügbar macht. Im vorherigen Beispiel waren dies die Ports 135, 51433 und 51000. Dabei handelt es sich um die Ports auf dem Host selbst und nicht um die Ports, die im Container zugeordnet sind. Wenn also der MSDTC-Port 51000 des Containers auf den Port 51001 des Hosts zugeordnet wurde, sollte Port 51001 (nicht 51000) in der Firewall für die Kommunikation mit dem Host geöffnet werden.

Im folgenden Beispiel wird das Erstellen dieser Regeln unter Ubuntu gezeigt.

sudo ufw allow from any to any port 51433 proto tcp
sudo ufw allow from any to any port 51000 proto tcp
sudo ufw allow from any to any port 135 proto tcp

Im folgenden Beispiel wird gezeigt, wie dies unter Red Hat Enterprise Linux (RHEL) durchgeführt werden kann:

sudo firewall-cmd --zone=public --add-port=51433/tcp --permanent
sudo firewall-cmd --zone=public --add-port=51000/tcp --permanent
sudo firewall-cmd --zone=public --add-port=135/tcp --permanent
sudo firewall-cmd --reload

Konfigurieren des Portroutings auf dem Host

Da im vorherigen Beispiel ein einzelner SQL Server-Container den RPC-Port 135 dem Port 135 auf dem Host zuordnet, sollten verteilte Transaktionen mit dem Host jetzt ohne weitere Konfiguration funktionieren. Es ist möglich, Port 135 direkt in Rootcontainern zu verwenden, da SQL Server in diesen Containern mit erhöhten Rechten ausgeführt wird. Bei Ausführung von SQL Server außerhalb eines Containers oder in Containern ohne Rootberechtigung muss ein anderer kurzlebiger Port (beispielsweise 13500) im Container verwendet werden, und der für Port 135 bestimmte Datenverkehr muss dann an diesen Port weitergeleitet werden. Sie müssen zudem Portroutingregeln im Container festlegen, die für Übertragungen vom Containerport 135 zum kurzlebigen Port gelten.

Wenn Sie den Port 135 des Containers einem anderen Port auf dem Host zugeordnet haben (z. B. 13500), müssen Sie das Portrouting auf dem Host konfigurieren. So kann der SQL Server-Container an verteilten Transaktionen mit dem Host und anderen externen Servern teilnehmen.

Weitere Informationen zu Routingports finden Sie unter Konfigurieren des Portroutings.

SQL Server-Container mit MS DTC in Kubernetes

Wenn Sie SQL Server-Container auf einer Kubernetes-Plattform bereitstellen, sehen Sie sich das folgende Beispiel für ein YAML-Bereitstellungsmanifest an. In diesem Beispiel ist AKS (Azure Kubernetes Service) die Kubernetes-Plattform.

Szenario 1: MS DTC-Client stellt eine Verbindung mit SQL Server in einem Kubernetes-Container her

Die nachstehende Abbildung veranschaulicht folgenden Prozess: Ein MS DTC-Client stellt eine Verbindung mit MS DTC auf einer SQL Server-Instanz her, die in einem Linux-Container in Kubernetes ausgeführt wird.

Abbildung: Ein MS DTC-Client stellt eine Verbindung mit MS DTC auf einer SQL Server-Instanz her, die in einem Linux-Container ausgeführt wird.

  1. Der MS DTC-Client stellt eine Verbindung mit Port 135 auf dem Kubernetes-Host her.
  2. Die Verbindung wird an Port 135 im Container weitergeleitet.
  3. Der Container leitet die Verbindung an die RPC-Endpunktzuordnung weiter, die sich in diesem Beispiel an Port 13500 befindet.
  4. Die Endpunktzuordnung teilt dem MS DTC-Client mit, an welchem Port MS DTC im Container ausgeführt wird (in diesem Beispiel Port 51000).
  5. Der MS DTC-Client stellt eine direkte Verbindung mit MS DTC her, indem er eine Verbindung mit dem Host an Port 51000 herstellt, der an die SQL Server-Instanz innerhalb des Containers weitergeleitet wird.

Szenario 2: SQL Server stellt eine Verbindung mit SQL Server in einem Kubernetes-Container her

Das folgende Diagramm zeigt den Prozess, wenn ein SQL Server Linux-Container mit MSDTC auf einem zweiten SQL Server Linux-Container auf Kubernetes verbunden ist.

Abbildung: Ein SQL Server Linux-Container stellt eine Verbindung mit MS DTC in einem zweiten SQL Server Linux-Container her.

  1. Die erste SQL Server-Instanz stellt eine Verbindung mit Port 135 auf dem Kubernetes-Host der zweiten SQL Server Instanz her.
  2. Die Verbindung wird an Port 135 des Containers der zweiten Instanz weitergeleitet.
  3. Der Container leitet die Verbindung an die RPC-Endpunktzuordnung weiter, die sich in diesem Beispiel an Port 13500 befindet.
  4. Die Endpunktzuordnung teilt der ersten SQL Server-Instanz mit, an welchem Port MS DTC im zweiten Container ausgeführt wird (in diesem Beispiel Port 51000).
  5. Die erste SQL Server-Instanz stellt eine direkte Verbindung mit MS DTC auf der zweiten Instanz her. Dazu wird eine Verbindung mit dem zweiten Host an Port 51000 hergestellt, die an SQL Server innerhalb des Containers weitergeleitet wird.

Bereitstellen von SQL Server-Containern mit MS DTC auf einer Kubernetes-Plattform

Erstellen Sie vor dem Ausführen des YAML-Beispielbereitstellungsskripts das erforderliche Geheimnis zum Speichern des sa-Kennworts. Verwenden Sie dazu den folgenden Beispielbefehl:

kubectl create secret generic mssql --from-literal=MSSQL_SA_PASSWORD="<password>"

Caution

Ihr Kennwort sollte der standardmäßigen Kennwortrichtlinie von SQL Server folgen. Standardmäßig muss das Kennwort mindestens acht Zeichen lang sein und Zeichen aus drei der folgenden vier Sätze enthalten: Großbuchstaben, Kleinbuchstaben, Basis-10 Ziffern und Symbole. Kennwörter können bis zu 128 Zeichen lang sein. Verwenden Sie möglichst lange und komplexe Kennwörter.

Sie werden die folgenden Punkte in der Manifestdatei bemerken:

  1. Das Manifest erstellt folgende Objekte: ein StorageClass, zwei SQL Server-Pods, die von einem bereitgestellt werdenStatefulSet, und zwei Load Balancer-Services, um sich mit den jeweiligen SQL Server-Instanzen zu verbinden.

  2. Sie werden außerdem bemerken, dass die Lastenausgleichsdienste mit statischen IP-Adressen bereitgestellt werden, die für Azure Kubernetes Service konfiguriert werden können. Siehe Verwenden einer statischen öffentlichen IP-Adresse und eines DNS-Namens mit dem Azure Kubernetes Service (AKS)-Load Balancer. Durch das Erstellen der Lastenausgleichsdienste mit statischen IP-Adressen wird sichergestellt, dass sich die externe IP-Adresse nicht ändert, wenn der Lastenausgleichsdienst gelöscht und neu erstellt wird.

  3. Im folgenden Skript sehen Sie, dass Port 13500 für die MSSQL_RPC_PORT-Umgebungsvariable und Port 51000 für die MSSQL_DTC_TCP_PORT-Umgebungsvariable verwendet wird, die beide für MS DTC erforderlich sind.

  4. Das Portrouting (d. h. die Weiterleitung von Port 135 zu 13500) wird im Lastenausgleichsskript konfiguriert, indem port und targetPort entsprechend konfiguriert werden, wie im folgenden Beispiel gezeigt:

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: 2
 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
     - containerPort: 13500
       name: dtcport
     - containerPort: 51000
       name: dtctcpport
     env:
     - name: ACCEPT_EULA
       value: "Y"
     - name: MSSQL_ENABLE_HADR
       value: "1"
     - name: MSSQL_AGENT_ENABLED
       value: "1"
     - name: MSSQL_RPC_PORT
       value: "13500"
     - name: MSSQL_DTC_TCP_PORT
       value: "51000"
     - 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-0
spec:
  type: LoadBalancer
  loadBalancerIP: 10.88.213.209
  selector:
    statefulset.kubernetes.io/pod-name: mssql-0
  ports:
  - protocol: TCP
    port: 1433
    targetPort: 1433
    name: tcpsql
  - protocol: TCP
    port: 51000
    targetPort: 51000
    name: dtctcpport
  - protocol: TCP
    port: 135
    targetPort: 13500
    name: nonrootport
---
apiVersion: v1
kind: Service
metadata:
  name: mssql-1
spec:
  type: LoadBalancer
  loadBalancerIP: 10.72.137.129
  selector:
    statefulset.kubernetes.io/pod-name: mssql-1
  ports:
  - protocol: TCP
    port: 1433
    targetPort: 1433
    name: tcpsql
  - protocol: TCP
    port: 51000
    targetPort: 51000
    name: dtctcpport
  - protocol: TCP
    port: 135
    targetPort: 13500
    name: nonrootport

Angenommen, du hast die Ressourcen im Standard-Namensraum erstellt, solltest du, wenn du den kubectl get all Befehl nach der vorherigen Bereitstellung ausführst, um alle erstellten Ressourcen zu sehen, die Ausgabe im folgenden Beispiel sehen.

NAME          READY   STATUS    RESTARTS   AGE
pod/mssql-0   1/1     Running   0          4d22h
pod/mssql-1   1/1     Running   0          4d22h

NAME                 TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                                        AGE
service/kubernetes   ClusterIP      10.0.0.1      <none>          443/TCP                                        6d6h
service/mssql-0      LoadBalancer   10.0.18.186   10.88.213.209   1433:31875/TCP,51000:31219/TCP,135:30044/TCP   2d6h
service/mssql-1      LoadBalancer   10.0.16.180   10.72.137.129   1433:30353/TCP,51000:32734/TCP,135:31239/TCP   2d6h

NAME                     READY   AGE
statefulset.apps/mssql   2/2     5d1h

Sie können Tools wie SQL Server Management Studio (SSMS) verwenden, um eine Verbindung mit einem der beiden zuvor genannten SQL-Server-Instanzen herzustellen und eine DTC-Beispieltransaktion auszuführen. In diesem Beispiel stellen Sie eine Verbindung mit mssql-1 (10.72.137.129) her und erstellen den verbundenen Server mit mssql-0 (10.88.213.209), um die verteilte Transaktion auszuführen, wie im folgenden Beispiel dargestellt.

USE [master];
GO

EXECUTE master.dbo.sp_addlinkedserver
    @server = N'10.88.213.209',
    @srvproduct = N'SQL Server';
GO

EXECUTE master.dbo.sp_addlinkedsrvlogin
    @rmtsrvname = N'10.88.213.209',
    @rmtuser = 'sa',
    @rmtpassword = '<password>',
    @useself = N'False';
GO

Caution

Ihr Kennwort sollte der standardmäßigen Kennwortrichtlinie von SQL Server folgen. Standardmäßig muss das Kennwort mindestens acht Zeichen lang sein und Zeichen aus drei der folgenden vier Sätze enthalten: Großbuchstaben, Kleinbuchstaben, Basis-10 Ziffern und Symbole. Kennwörter können bis zu 128 Zeichen lang sein. Verwenden Sie möglichst lange und komplexe Kennwörter.

Jetzt kannst du die verteilte Transaktion starten. Das folgende Codebeispiel fragt die Kompatibilitätsansicht sys.sysprocesses auf der mssql-0 Instanz ab:

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION;

SELECT *
FROM [10.88.213.209].master.dbo.sysprocesses;

COMMIT TRANSACTION;
GO