Freigeben über


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

Gilt für: SQL Server – Linux

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

SQL Server-Containerimages können den für verteilte Transaktionen erforderlichen Microsoft Distributed Transaction Coordinator (MS DTC) verwenden. Informationen zu den Kommunikationsanforderungen für MS DTC finden Sie unter Konfigurieren des Microsoft Distributed Transaction Coordinator (MS DTC) unter Linux.

Hinweis

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

Zum Aktivieren von MS DTC-Transaktionen in SQL Server-Containern müssen Sie zwei neue Umgebungsvariablen festlegen:

  • MSSQL_RPC_PORT: der TCP-Port, wo der RPC-Endpunktzuordnungs-Dienst gebunden wird und lauscht.
  • MSSQL_DTC_TCP_PORT: der Port, für den der MS DTC-Dienst konfiguriert ist, und wo 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, mit jeder beliebigen Anwendung auf allen Hosts zu kommunizieren.

Wichtig

Die Umgebungsvariable SA_PASSWORD ist veraltet. Verwenden Sie stattdessen MSSQL_SA_PASSWORD.

docker run \
   -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=<YourStrong!Passw0rd>' \
   -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=<YourStrong!Passw0rd>" `
   -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, mit jeder beliebigen Anwendung auf allen Hosts zu kommunizieren.

Wichtig

Die Umgebungsvariable SA_PASSWORD ist veraltet. Verwenden Sie stattdessen MSSQL_SA_PASSWORD.

docker run \
   -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=<YourStrong!Passw0rd>' \
   -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=<YourStrong!Passw0rd>" `
   -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

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 werden extern für den Host als TDS-Port 51433, RPC-Endpunktzuordnungs-Port 135 und MS DTC-Port 51000 verfügbar gemacht.

Der RPC-Endpunktzuordnungs- und MS DTC-Port müssen auf Host und Container nicht identisch sein. Während der RPC-Endpunktzuordnungs-Port für den Container mit 135 konfiguriert wurde, kann er auf dem Hostserver möglicherweise Port 13501 oder einem beliebigen anderen verfügbaren Port 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 RPC-Endpunktzuordnungs-Port 51000 des Containers dem Hostport 51001 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

Die nachstehende Abbildung veranschaulicht folgenden Prozess: Ein SQL Server Linux-Container stellt eine Verbindung mit MS DTC in einem zweiten SQL Server Linux-Container in Kubernetes her.

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-Beispielskripts für die Bereitstellung das erforderliche Geheimnis zum Speichern des sa-Kennworts unter Verwendung des folgenden Befehls:

kubectl create secret generic mssql --from-literal=MSSQL_SA_PASSWORD="MyC0m9l&xP@ssw0rd"

Sie werden die folgenden Punkte in der Manifestdatei bemerken:

  1. Im Cluster erstellen wir die folgenden Objekte: StorageClass, zwei SQL Server-Pods, die als statefulset-Bereitstellungen bereitgestellt werden, und zwei Lastenausgleichsdienste, um eine Verbindung mit den entsprechenden SQL Server-Instanzen herzustellen.

  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. Lesen Sie dazu Verwenden einer statischen öffentlichen IP-Adresse und einer DNS-Bezeichnung mit dem Lastenausgleich von Azure Kubernetes Service (AKS). 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: 40.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: 20.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, Sie haben die Ressource im Standardnamespace erstellt. Wenn Sie nach der Bereitstellung vorherigen den Befehl kubectl get all ausführen, um alle erstellten Ressourcen anzuzeigen, sollte die Ausgabe im folgenden Beispiel angezeigt werden.

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   40.88.213.209   1433:31875/TCP,51000:31219/TCP,135:30044/TCP   2d6h
service/mssql-1      LoadBalancer   10.0.16.180   20.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 (20.72.137.129) her und erstellen den Verbindungsserver mit mssql-0 (40.88.213.209), um die verteilte Transaktion auszuführen, wie im folgenden Beispiel dargestellt.

USE [master]
GO
EXEC master.dbo.sp_addlinkedserver @server = N'40.88.213.209', @srvproduct=N'SQL Server';
GO

EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname = N'40.88.213.209', @rmtuser = 'sa', @rmtpassword = 'xxxx', @useself = N'False';
GO

Jetzt können Sie die verteilte Transaktion starten, und in diesem Codebeispiel werden die sys.sysprocesses aus der mssql-0-Instanz angezeigt:

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION
SELECT * FROM [40.88.213.209].master.dbo.sysprocesses;
COMMIT
GO