Partilhar via


Como usar transações distribuídas com contêineres do SQL Server Linux

Aplica-se a:SQL Server em Linux

Este artigo explica como configurar contêineres do SQL Server Linux para transações distribuídas, incluindo requisitos e cenários especiais.

As imagens de contêiner do SQL Server podem usar o Microsoft Distributed Transaction Coordinator (MSDTC), que é necessário para transações distribuídas. Para entender os requisitos de comunicação para MSDTC, consulte Como configurar o Microsoft Distributed Transaction Coordinator (MSDTC) no Linux.

Observação

O SQL Server 2017 (14.x) é executado em contêineres raiz por padrão, enquanto o SQL Server 2019 (15.x) e contêineres posteriores são executados como um usuário não raiz.

Configuração

Para habilitar a transação MSDTC em contêineres do SQL Server, você deve definir duas novas variáveis de ambiente:

  • MSSQL_RPC_PORT: a porta TCP à qual o serviço de mapeador de pontos de extremidade RPC se liga e escuta.
  • MSSQL_DTC_TCP_PORT: a porta na qual o serviço MSDTC está configurado para escutar.

Puxe e corra

O exemplo a seguir mostra como usar essas variáveis de ambiente para extrair e executar um único contêiner do SQL Server 2017 configurado para MSDTC. Isso permite que ele se comunique com qualquer aplicativo em qualquer host.

Importante

A variável de ambiente SA_PASSWORD foi preterida. Use MSSQL_SA_PASSWORD em vez disso.

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

O exemplo a seguir mostra como usar essas variáveis de ambiente para extrair e executar um único contêiner do SQL Server 2019 (15.x) configurado para MSDTC. Isso permite que ele se comunique com qualquer aplicativo em qualquer host.

Importante

A variável de ambiente SA_PASSWORD foi preterida. Use MSSQL_SA_PASSWORD em vez disso.

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

Atenção

Sua senha deve seguir a política de senha de padrão do SQL Server. Por padrão, a senha deve ter pelo menos oito caracteres e conter caracteres de três dos quatro conjuntos a seguir: letras maiúsculas, letras minúsculas, dígitos de base 10 e símbolos. As palavras-passe podem ter até 128 caracteres. Use senhas tão longas e complexas quanto possível.

Neste comando, o serviço Mapeador de Pontos de Extremidade RPC está vinculado à porta 135 e o serviço MSDTC está vinculado à porta 51000 dentro da rede virtual do contentor. A comunicação TDS do SQL Server ocorre na porta 1433, também dentro da rede virtual do contêiner. Essas portas são expostas externamente ao host como porta TDS 51433, porta 135 do mapeador de ponto de extremidade RPC e porta MSDTC 51000.

O Mapeador de Pontos de Extremidade RPC e a porta MSDTC não têm de ser iguais no host e no contentor. Portanto, embora a porta do Mapeador de Pontos de Extremidade RPC tenha sido configurada para ser 135 no contêiner, ela poderia ser potencialmente mapeada para a porta 13501 ou qualquer outra porta disponível no servidor host.

Configurar o firewall

Para se comunicar com e através do host, você também deve configurar o firewall no servidor host para os contêineres. Abra o firewall para todas as portas que o contêiner do SQL Server expõe para comunicação externa. No exemplo anterior, seriam as portas 135, 51433 e 51000. Estas são as portas que estão no próprio host e não as portas para as quais são mapeadas no contentor. Portanto, se a porta 51000 do mapeador de ponto de extremidade RPC do contêiner foi mapeada para a porta 51001 do host, a porta 51001 (não 51000) deve ser aberta no firewall para comunicação com o host.

O exemplo a seguir mostra como criar essas regras no 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

O exemplo a seguir mostra como isso pode ser feito no 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

Configurar o roteamento de porta no host

No exemplo anterior, como um único contêiner do SQL Server mapeia a porta RPC 135 para a porta 135 no host, as transações distribuídas com o host agora devem funcionar sem nenhuma configuração adicional. É possível usar a porta 135 diretamente em contêineres executados como raiz, porque o SQL Server é executado com privilégios elevados nesses contêineres. Para o SQL Server fora de um contêiner ou para contêineres não raiz, você deve usar uma porta efêmera diferente (por exemplo, 13500) no contêiner, e o tráfego destinado à porta 135 deve ser roteado para essa porta. Você também precisaria configurar regras de roteamento de porta dentro do contêiner da porta de contêiner 135 para a porta efêmera.

Além disso, se você decidir mapear a porta 135 do contêiner para uma porta diferente no host, como 13500, será necessário configurar o roteamento de porta no host. Isso permite que o contêiner do SQL Server participe de transações distribuídas com o host e com outros servidores externos.

Para obter mais informações sobre portas de roteamento, consulte Configurar o roteamento de porta.

Contêineres do SQL Server com MSDTC no Kubernetes

Se você estiver implantando contêineres do SQL Server em uma plataforma Kubernetes, consulte o exemplo de manifesto de implantação do YAML a seguir. Neste exemplo, a plataforma Kubernetes é o Serviço Kubernetes do Azure (AKS).

Cenário 1: Cliente MSDTC conectando-se ao SQL Server em um contêiner do Kubernetes

O diagrama a seguir mostra o processo quando um cliente MSDTC se conecta ao MSDTC no SQL Server em execução dentro de um contêiner Linux no Kubernetes.

Diagrama mostrando o processo quando um cliente MSDTC se conecta ao MSDTC no SQL Server em execução dentro de um contêiner Linux.

  1. O cliente MSDTC faz uma conexão com a porta 135 no host Kubernetes.
  2. A conexão é encaminhada para a porta 135 no contêiner.
  3. O contêiner encaminha a conexão para o mapeador de ponto de extremidade RPC, que está na porta 13500 neste exemplo.
  4. O mapeador de endpoint informa ao cliente MSDTC em qual porta o MSDTC está a ser executado dentro do contêiner (porta 51000 neste exemplo).
  5. O cliente MSDTC faz uma conexão diretamente com o MSDTC conectando-se ao host na porta 51000, que é encaminhado para o SQL Server dentro do contêiner.

Cenário 2: SQL Server conectando-se ao SQL Server em um contêiner do Kubernetes

O diagrama a seguir mostra o processo quando um contêiner do SQL Server Linux se conecta ao MSDTC em um segundo contêiner do SQL Server Linux, no Kubernetes.

Diagrama mostrando o processo quando um contêiner do SQL Server Linux se conecta ao MSDTC em um segundo contêiner do SQL Server Linux.

  1. A primeira instância do SQL Server estabelece uma ligação com a porta 135 no computador anfitrião Kubernetes da segunda instância do SQL Server.
  2. A conexão é encaminhada para a porta 135 no contêiner da segunda instância.
  3. O contêiner encaminha a conexão para o mapeador de ponto de extremidade RPC, que está na porta 13500 neste exemplo.
  4. O mapeador de ponto de extremidade informa à primeira instância do SQL Server qual porta MSDTC está sendo executada dentro do segundo contêiner (porta 51000 neste exemplo).
  5. A primeira instância do SQL Server faz uma conexão diretamente com o MSDTC na segunda instância, conectando-se ao segundo host na porta 51000, que é encaminhado para o SQL Server dentro do contêiner.

Implantar contêineres do SQL Server com MSDTC configurado em uma plataforma Kubernetes

Antes de executar o script YAML de implantação de exemplo, crie o segredo necessário para armazenar a senha sa, usando o seguinte comando de exemplo:

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

Atenção

Sua senha deve seguir a política de senha de padrão do SQL Server. Por padrão, a senha deve ter pelo menos oito caracteres e conter caracteres de três dos quatro conjuntos a seguir: letras maiúsculas, letras minúsculas, dígitos de base 10 e símbolos. As palavras-passe podem ter até 128 caracteres. Use senhas tão longas e complexas quanto possível.

Observe os seguintes pontos no arquivo de manifesto:

  1. No cluster, criamos os seguintes objetos: StorageClass, dois pods do SQL Server implantados como implantações statefulset e dois serviços de balanceador de carga para se conectar às respetivas instâncias do SQL Server.

  2. Você também observa que os serviços de balanceador de carga são implantados com endereços IP estáticos, que podem ser configurados no Serviço Kubernetes do Azure. Veja Usar um endereço IP público estático e um rótulo DNS com o balanceador de carga do Serviço de Kubernetes do Azure (AKS). A criação dos serviços do balanceador de carga com endereços IP estáticos garante que o endereço IP externo não seja alterado se o serviço do balanceador de carga for excluído e recriado.

  3. No script a seguir, você pode ver que a porta 13500 é usada para a variável de ambiente MSSQL_RPC_PORT e a porta 51000 para a variável de ambiente MSSQL_DTC_TCP_PORT, ambas necessárias para MSDTC.

  4. O roteamento de porta (ou seja, a porta de roteamento 135 a 13500) é configurado no script do balanceador de carga configurando adequadamente o port e o targetPort conforme mostrado no exemplo a seguir:

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

Supondo que você criou o recurso no namespace padrão, quando você executa o comando kubectl get all após a implantação anterior para ver todos os recursos criados, você deve ver a saída mostrada no exemplo a seguir.

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

Você pode usar ferramentas como o SQL Server Management Studio (SSMS) para se conectar a qualquer uma das duas instâncias anteriores do SQL Server e executar uma transação DTC de exemplo. Neste exemplo, você se conecta ao mssql-1 (10.72.137.129) e cria o servidor vinculado ao mssql-0 (10.88.213.209) para executar a transação distribuída, conforme mostrado no exemplo a seguir.

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

Atenção

Sua senha deve seguir a política de senha de padrão do SQL Server. Por padrão, a senha deve ter pelo menos oito caracteres e conter caracteres de três dos quatro conjuntos a seguir: letras maiúsculas, letras minúsculas, dígitos de base 10 e símbolos. As palavras-passe podem ter até 128 caracteres. Use senhas tão longas e complexas quanto possível.

Agora podes iniciar a transação distribuída; este exemplo de código mostra o sys.sysprocesses a partir da instância mssql-0:

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION;

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

COMMIT TRANSACTION;
GO