Condividi tramite


Come usare le transazioni distribuite con contenitori SQL Server in Linux

Si applica a:SQL Server - Linux

Questo articolo illustra come configurare contenitori SQL Server in Linux per le transazioni distribuite, inclusi gli scenari e i requisiti speciali.

Le immagini del contenitore di SQL Server possono usare Microsoft Distributed Transaction Coordinator (MSDTC), necessario per le transazioni distribuite. Per informazioni sui requisiti di comunicazione per MSDTC, vedere Come configurare Microsoft Distributed Transaction Coordinator (MSDTC) in Linux.

Nota

SQL Server 2017 (14.x) viene eseguito in contenitori root per impostazione predefinita, mentre i contenitori di SQL Server 2019 (15.x) e successivi vengono eseguiti come utenti non root.

Impostazione

Per abilitare le transazioni MSDTC nei contenitori SQL Server, è necessario impostare due nuove variabili di ambiente:

  • MSSQL_RPC_PORT: la porta TCP a cui il servizio mapper di endpoint RPC si associa e ascolta.
  • MSSQL_DTC_TCP_PORT: la porta su cui è configurato il servizio MSDTC per l'ascolto.

Scarica ed esegui

L'esempio seguente illustra come usare queste variabili di ambiente per il pull e l'esecuzione di un singolo contenitore di SQL Server 2017 configurato per MSDTC. Ciò consente le comunicazioni con qualsiasi applicazione su qualsiasi host.

Importante

La variabile di ambiente SA_PASSWORD è deprecata. Utilizzare invece 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

L'esempio seguente illustra come usare queste variabili di ambiente per il pull e l'esecuzione di un singolo contenitore di SQL Server 2019 (15x.) configurato per MSDTC. Ciò consente le comunicazioni con qualsiasi applicazione su qualsiasi host.

Importante

La variabile di ambiente SA_PASSWORD è deprecata. Utilizzare invece 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

Attenzione

La password deve seguire i criteri password predefiniti di SQL Server. Per impostazione predefinita, la password deve essere composta da almeno otto caratteri e contenere caratteri di tre delle quattro categorie seguenti: lettere maiuscole, lettere minuscole, cifre in base 10 e simboli. Le password possono contenere fino a 128 caratteri. Usare password il più possibile lunghe e complesse.

In questo comando il servizio mapper di endpoint RPC è associato alla porta 135 e il servizio MSDTC è associato alla porta 51000 nella rete virtuale del contenitore. Le comunicazioni TDS di SQL Server avvengono sulla porta 1433 all'interno della rete virtuale del contenitore. Queste porte sono esposte esternamente all'host come porta TDS 51433, porta del mapper di endpoint RPC 135 e porta MSDTC 51000.

Le porte del mapper di endpoint RPC e dell'MSDTC non devono necessariamente coincidere tra l'host e il contenitore. Sebbene la porta del mapper di endpoint RPC sia stata configurata come 135 nel contenitore, potrebbe essere potenzialmente mappata sulla porta 13501 o su qualsiasi altra porta disponibile sul server host.

Configurare il firewall

Per comunicare con e tramite l'host, è anche necessario configurare il firewall nel server host per i contenitori. Aprire il firewall per tutte le porte esposte dal contenitore SQL Server per le comunicazioni esterne. Nell'esempio precedente si tratta delle porte 135, 51433 e 51000. Queste sono le porte nell'host stesso e non le porte a cui sono mappate nel contenitore. Di conseguenza, se è stato eseguito il mapping della porta del mapper di endpoint RPC 51000 del contenitore alla porta 51001 dell'host, per le comunicazioni con l'host deve essere aperta la porta 51001 (non 51000) nel firewall.

L'esempio seguente mostra come creare queste regole in Ubuntu.

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

L'esempio seguente mostra come eseguire questa operazione in Red Hat Enterprise Linux (RHEL):

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

Configurare il routing delle porte nell'host

Nell'esempio precedente, dato che un singolo contenitore SQL Server esegue il mapping della porta RPC 135 alla porta 135 nell'host, le transazioni distribuite con l'host dovrebbero ora funzionare senza ulteriori configurazioni. È possibile usare direttamente la porta 135 in contenitori in esecuzione come radice, perché in tali contenitori SQL Server viene eseguito con privilegi elevati. Per SQL Server all'esterno di un contenitore o in contenitori non radice, è necessario usare una porta temporanea diversa, ad esempio la porta 13500, nel contenitore e il traffico destinato alla porta 135 deve quindi essere indirizzato alla porta temporanea. È anche necessario configurare regole di routing delle porte all'interno del contenitore dalla porta 135 alla porta temporanea.

Se si decide di eseguire il mapping della porta 135 del contenitore a una porta diversa nell'host, ad esempio alla porta 13500, è anche necessario configurare il routing delle porte nell'host. Ciò consente al contenitore SQL Server di partecipare alle transazioni distribuite con l'host e con altri server esterni.

Per altre informazioni sulle porte di routing, vedere Configurare il routing delle porte.

Contenitori SQL Server con MSDTC in Kubernetes

Se si distribuiscono contenitori SQL Server in una piattaforma Kubernetes, vedere il manifesto della distribuzione YAML di esempio seguente. In questo esempio la piattaforma Kubernetes è il servizio Azure Kubernetes.

Scenario 1: client MSDTC che si connette a SQL Server in un contenitore Kubernetes

Il diagramma seguente illustra il processo in cui un client MSDTC si connette a MSDTC in SQL Server in esecuzione all'interno di un contenitore Linux in Kubernetes.

Il diagramma seguente illustra il processo in cui un client MSDTC si connette a MSDTC in SQL Server in esecuzione all'interno di un contenitore Linux.

  1. Il client MSDTC effettua una connessione alla porta 135 nell'host Kubernetes.
  2. La connessione viene inoltrata alla porta 135 nel contenitore.
  3. Il contenitore inoltra la connessione al mapper dell'endpoint RPC, che si trova sulla porta 13500 in questo esempio.
  4. Il mapper dell'endpoint indica al client MSDTC quale porta sia utilizzata da MSDTC all'interno del contenitore (porta 51000 in questo esempio).
  5. Il client MSDTC effettua una connessione direttamente a MSDTC connettendosi all'host sulla porta 51000, che viene inoltrata a SQL Server all'interno del contenitore.

Scenario 2: La connessione di SQL Server a SQL Server in un contenitore Kubernetes

Il diagramma seguente illustra il processo in cui un contenitore SQL Server Linux si connette a MSDTC in un secondo contenitore SQL Server Linux in Kubernetes.

Diagramma che mostra il processo in cui un contenitore Linux di SQL Server si connette a MSDTC in un secondo contenitore Linux di SQL Server.

  1. La prima istanza di SQL Server stabilisce una connessione alla porta 135 nell'host Kubernetes della seconda istanza di SQL Server.
  2. La connessione viene inoltrata alla porta 135 nel contenitore della seconda istanza.
  3. Il contenitore inoltra la connessione al mapper dell'endpoint RPC, che si trova sulla porta 13500 in questo esempio.
  4. Il mapper di endpoint indica alla prima istanza di SQL Server su quale porta è in esecuzione MSDTC all'interno del secondo contenitore (porta 51000 in questo esempio).
  5. La prima istanza di SQL Server effettua una connessione direttamente a MSDTC nella seconda istanza connettendosi al secondo host sulla porta 51000, che viene inoltrata a SQL Server all'interno del contenitore.

Distribuire contenitori SQL Server con MSDTC configurato in una piattaforma Kubernetes

Prima di eseguire lo script YAML di distribuzione di esempio, creare il segreto necessario per archiviare la password sa, usando il comando di esempio seguente:

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

Attenzione

La password deve seguire i criteri password predefiniti di SQL Server. Per impostazione predefinita, la password deve essere composta da almeno otto caratteri e contenere caratteri di tre delle quattro categorie seguenti: lettere maiuscole, lettere minuscole, cifre in base 10 e simboli. Le password possono contenere fino a 128 caratteri. Usare password il più possibile lunghe e complesse.

Si possono notare i punti seguenti nel file manifesto:

  1. Nel cluster vengono creati gli oggetti seguenti: StorageClass, due pod SQL Server distribuiti come distribuzioni statefulset e due servizi di bilanciamento del carico per connettersi alle rispettive istanze di SQL Server.

  2. È possibile notare anche che i servizi di bilanciamento del carico vengono distribuiti con indirizzi IP statici, che possono essere configurati nel servizio Azure Kubernetes. Consulta l'uso di un indirizzo IP pubblico statico e di un'etichetta DNS con il load balancer di Azure Kubernetes Service (AKS). La creazione dei servizi di bilanciamento del carico con indirizzi IP statici garantisce che l'indirizzo IP esterno non cambi se il servizio di bilanciamento del carico viene eliminato e ricreato.

  3. Nello script seguente è possibile notare che la porta 13500 viene usata per la variabile di ambiente MSSQL_RPC_PORT e la porta 51000 per la variabile di ambiente MSSQL_DTC_TCP_PORT, entrambe necessarie per MSDTC.

  4. Il routing delle porte, ovvero il routing della porta da 135 a 13500, viene configurato nello script del servizio di bilanciamento del carico configurando in modo appropriato port e targetPort come illustrato nell'esempio seguente:

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

Supponendo di aver creato la risorsa nello spazio dei nomi predefinito, quando si esegue il comando kubectl get all dopo la distribuzione precedente per visualizzare tutte le risorse create, verrà visualizzato l'output illustrato nell'esempio seguente.

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

È possibile usare strumenti come SQL Server Management Studio (SSMS) per connettersi a una delle due istanze di SQL Server precedenti ed eseguire una transazione DTC di esempio. In questo esempio ci si connette a mssql-1 (10.72.137.129) e si crea il server collegato a mssql-0 (10.88.213.209) per eseguire la transazione distribuita, come illustrato nell'esempio seguente.

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

Attenzione

La password deve seguire i criteri password predefiniti di SQL Server. Per impostazione predefinita, la password deve essere composta da almeno otto caratteri e contenere caratteri di tre delle quattro categorie seguenti: lettere maiuscole, lettere minuscole, cifre in base 10 e simboli. Le password possono contenere fino a 128 caratteri. Usare password il più possibile lunghe e complesse.

A questo punto è possibile avviare la transazione distribuita e questo esempio di codice mostra l'oggetto sys.sysprocesses dall'istanza mssql-0:

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION;

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

COMMIT TRANSACTION;
GO