Compartilhar via


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

Aplica-se a:SQL Server no Linux

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

As imagens de contêiner do SQL Server podem usar o Coordenador de Transações Distribuídas da Microsoft (MSDTC), que é necessário para transações distribuídas. Para entender os requisitos de comunicação do MSDTC, confira Como configurar o MSDTC (Coordenador de Transações Distribuídas da Microsoft) em Linux.

Observação

O SQL Server 2017 (14.x) é executado em contêineres raiz por padrão, enquanto contêineres do SQL Server 2019 (15.x) e versões 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ê deverá definir duas novas variáveis de ambiente:

  • MSSQL_RPC_PORT: a porta TCP à qual o serviço mapeador de ponto de extremidade RPC se associa e na qual escuta.
  • MSSQL_DTC_TCP_PORT: a porta configurada para o serviço MSDTC escutar.

Efetuar pull e executar

O exemplo a seguir mostra como usar essas variáveis de ambiente para efetuar pull e executar um único contêiner do SQL Server 2017 configurado para o 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 efetuar pull e executar um único contêiner do SQL Server 2019 (15.x) configurado para o 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

Cuidado

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

Neste comando, o serviço Mapeador de Ponto de Extremidade RPC foi associado à porta 135 e o serviço MSDTC foi associado à porta 51000 na rede virtual do contêiner. A comutador do TDS do SQL Server ocorre na porta 1433 na rede virtual do contêiner. Essas portas foram expostas externamente ao host como a porta 51433 do TDS, a porta 135 do mapeador de ponto de extremidade RPC e porta 51000 do MSDTC.

A porta do Mapeador de Ponto de Extremidade RPC e do MSDTC não precisam ser iguais no host e no contêiner. Assim, enquanto a porta do Mapeador de Ponto de Extremidade RPC tiver sido configurada para ser a 135 no contêiner, ela poderá ser mapeada para a porta 13501 ou qualquer outra porta disponível no servidor host.

Configurar o firewall

Para comunicar-se com e por meio 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. Essas são as portas no próprio host, e não as portas para as quais eles mapeiam no contêiner. Portanto, se a porta 51000 do mapeador de ponto de extremidade RPC do contêiner tiver sido mapeada para a porta de host 51001, a porta 51001 (não 51000) deverá 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 RHEL (Red Hat Enterprise Linux):

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 135 RPC 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 diretamente a porta 135 em contêineres que são 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 para a porta 135 deve ser roteado para essa porta. Você também precisaria configurar as 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 a 13500, precisará 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 o roteamento de portas, confira Configurar roteamento de porta.

Contêineres do SQL Server com MSDTC no Kubernetes

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

Cenário 1: cliente MSDTC se conectando 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.

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.

  1. O cliente MSDTC faz uma conexão com a porta 135 no host do 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 pontos de extremidade RPC, que está na porta 13500 neste exemplo.
  4. O mapeador de pontos de extremidade informa ao cliente MSDTC qual porta o MSDTC está executando 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 é encaminhada para o SQL Server dentro do contêiner.

Cenário 2: SQL Server se conectar a SQL Server em um contêiner do Kubernetes

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

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

  1. A primeira instância do SQL Server faz uma conexão com a porta 135 no host 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 pontos de extremidade RPC, que está na porta 13500 neste exemplo.
  4. O mapeador do ponto de extremidade informa à primeira instância do SQL Server em qual porta o MSDTC está em execução dentro do segundo contêiner (porta 51000, neste exemplo).
  5. A primeira instância do SQL Server faz uma conexão direta 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 o 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 comando de exemplo a seguir:

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

Cuidado

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

Você observará 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 respectivas instâncias do SQL Server.

  2. Você também observará que os serviços do balanceador de carga são implantados com endereços IP estáticos, que podem ser configurados no Serviço de Kubernetes do Azure. Confira Usar um endereço IP público estático e um rótulo de DNS com o balanceador de carga do AKS (Serviço de Kubernetes do Azure). A criação dos serviços do balanceador de carga com endereços IP estáticos garantirá 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 abaixo, 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 o MSDTC.

  4. O roteamento de porta (ou seja, o roteamento da porta 135 para 13500) é configurado no script do balanceador de carga configurando adequadamente port e 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ê tenha criado o recurso no namespace padrão, ao executar o comando kubectl get all após a implantação acima para ver todos os recursos criados, você deverá 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 SQL Server Management Studio (SSMS) para se conectar a qualquer uma das duas instâncias do SQL Server acima e executar uma transação DTC de amostra. Neste exemplo, você se conectará a mssql-1 (10.72.137.129) e criará 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

Cuidado

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

Agora você pode iniciar a transação distribuída, e este exemplo de código mostrará o sys.sysprocesses da instância mssql-0:

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION;

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

COMMIT TRANSACTION;
GO