Поделиться через


Использование распределенных транзакций с SQL Server в контейнерах Linux

Применимо к:SQL Server в Linux

В этой статье показано, как настроить контейнеры SQL Server в Linux для распределенных транзакций, включая специальные требования и сценарии.

Образы контейнеров SQL Server могут использовать координатор распределенных транзакций Майкрософт (MSDTC), необходимый для распределенных транзакций. Сведения о требованиях к связи для MSDTC см. в статье Настройка координатора распределенных транзакций Майкрософт (MSDTC) в Linux.

Примечание.

SQL Server 2017 (14.x) выполняется в корневых контейнерах по умолчанию, в то время как SQL Server 2019 (15.x) и более поздние контейнеры выполняются как не корневой пользователь.

Настройка

Чтобы включить транзакцию MSDTC в контейнерах SQL Server, необходимо задать две новые переменные среды:

  • MSSQL_RPC_PORT: TCP-порт, к которому привязывается служба сопоставления конечных точек RPC и прослушивает его.
  • MSSQL_DTC_TCP_PORT: порт, на который настроена служба MSDTC для прослушивания.

Извлечение и запуск

В приведенном ниже примере показано, как использовать эти переменные среды для извлечения и запуска одиночного контейнера SQL Server 2017, настроенного для MSDTC. Это позволяет ему взаимодействовать с любым приложением на любых узлах.

Внимание

Переменная среды SA_PASSWORD является устаревшей. Вместо этого используйте 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

В следующем примере показано, как использовать эти переменные среды для извлечения и запуска одного контейнера SQL Server 2019 (15.x), настроенного для MSDTC. Это позволяет ему взаимодействовать с любым приложением на любых узлах.

Внимание

Переменная среды SA_PASSWORD является устаревшей. Вместо этого используйте 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

Внимание

Пароль должен соответствовать политике паролей по умолчанию SQL Server. По умолчанию пароль должен быть не короче восьми символов и содержать три вида символов из следующих: прописные буквы, строчные буквы, десятичные цифры, специальные символы. Пароли могут иметь длину до 128 символов. Рекомендуется использовать максимально длинные и сложные пароли.

В этой команде служба сопоставления конечных точек RPC привязана к порту 135, а служба MSDTC привязана к порту 51000 в виртуальной сети контейнера. Коммуникации TDS в SQL Server проходят через порт 1433 также в виртуальной сети контейнера. Эти порты открыты для хоста как порт TDS 51433, порт сопоставителя конечных точек RPC 135 и порт MSDTC 51000.

Сопоставитель конечных точек RPC и порт MSDTC могут не совпадать на узле и в контейнере. Хотя порт сопоставителя конечных точек RPC был настроен на порте 135 в контейнере, он может быть сопоставлен с портом 13501 или с любым другим доступным портом на сервере узла.

Настройка брандмауэра

Чтобы взаимодействовать с узлом и через него, необходимо также настроить брандмауэр на сервере узла для контейнеров. Откройте брандмауэр для всех портов, которые контейнер SQL Server открывает для внешнего обмена данными. В предыдущем примере это порты 135, 51433 и 51000. Это порты на самом хосте, а не порты, с которыми они сопоставлены в контейнере. Таким образом, если порт сопоставления конечных точек RPC 51000 контейнера сопоставлен с портом узла 51001, то порт 51001 (не 51000) должен быть открыт в брандмауэре для связи с узлом.

В следующем примере показано, как создать эти правила в 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

В следующем примере показано, как это можно сделать в 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

Настройка маршрутизации портов на узле

В предыдущем примере, так как контейнер SQL Server сопоставляет RPC-порт 135 с портом 135 на узле, распределенные транзакции с этим узлом теперь должны выполняться без дальнейшей настройки. Можно использовать порт 135 напрямую в контейнерах, работающих от имени пользователя root, потому что SQL Server в таких контейнерах работает с повышенными привилегиями. Для SQL Server за пределами контейнера или для некорневых контейнеров необходимо использовать другой эфемерный порт (например, 13500) в контейнере, а трафик, предназначенный для порта 135, должен затем направляться на этот порт. Кроме того, необходимо настроить правила маршрутизации портов в контейнере с порта контейнера 135 на временный порт.

Однако если вы решили связать порт 135 контейнера с другим портом на узле, например 13500, необходимо настроить маршрутизацию портов на узле. Это позволяет контейнеру SQL Server участвовать в распределенных транзакциях с узлом и другими внешними серверами.

Дополнительные сведения о маршрутизации портов см. в разделе Настройка маршрутизации портов.

Контейнеры SQL Server с MSDTC в Kubernetes

Если вы развертываете контейнеры SQL Server на платформе Kubernetes, ознакомьтесь со следующим примером манифеста развертывания YAML. В этом примере платформа Kubernetes — это служба Azure Kubernetes (AKS).

Сценарий 1. Подключение клиента MSDTC к SQL Server в контейнере Kubernetes

На следующей схеме показан процесс, когда клиент MSDTC подключается к MSDTC на SQL Server, работающем внутри контейнера Linux в Kubernetes.

Схема, показывающая процесс при подключении клиента MSDTC к MSDTC на SQL Server, работающем внутри контейнера Linux.

  1. Клиент MSDTC выполняет подключение к порту 135 на узле Kubernetes.
  2. Подключение перенаправлено на порт 135 в контейнере.
  3. Контейнер перенаправляет подключение к маршрутизатору конечных точек RPC, который в этом примере находится на порту 13500.
  4. Средство сопоставления конечных точек сообщает клиенту MSDTC, какой порт MSDTC выполняется внутри контейнера (порт 51000 в этом примере).
  5. Клиент MSDTC подключается непосредственно к MSDTC путем подключения к узлу через порт 51000, который пересылается в SQL Server внутри контейнера.

Сценарий 2. Подключение SQL Server к SQL Server в контейнере Kubernetes

На следующей схеме показано, как один контейнер SQL Server Linux подключается к MSDTC во втором контейнере Linux SQL Server в Kubernetes.

Схема, показывающая процесс при подключении одного контейнера SQL Server Linux к MSDTC во втором контейнере SQL Server Linux.

  1. Первый экземпляр SQL Server делает подключение к порту 135 на узле Kubernetes второго экземпляра SQL Server.
  2. Подключение перенаправлено в порт 135 в контейнере второго экземпляра.
  3. Контейнер перенаправляет подключение к маршрутизатору конечных точек RPC, который в этом примере находится на порту 13500.
  4. Сопоставитель конечных точек сообщает первому экземпляру SQL Server, на каком порту (порт 51000) запущен MSDTC во втором контейнере.
  5. Первый экземпляр SQL Server подключается непосредственно к MSDTC во втором экземпляре, подключаясь ко второму узлу через порт 51000, который пересылается в SQL Server внутри контейнера.

Развертывание контейнеров SQL Server с настроенным MSDTC на платформе Kubernetes

Перед запуском примера скрипта YAML развертывания создайте необходимый секрет для хранения sa пароля, выполнив следующую команду:

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

Внимание

Пароль должен соответствовать политике паролей по умолчанию SQL Server. По умолчанию пароль должен быть не короче восьми символов и содержать три вида символов из следующих: прописные буквы, строчные буквы, десятичные цифры, специальные символы. Пароли могут иметь длину до 128 символов. Рекомендуется использовать максимально длинные и сложные пароли.

Обратите внимание на следующие моменты в файле манифеста:

  1. В кластере мы создадим следующие объекты: StorageClassдва модуля pod SQL Server, развернутые в качестве statefulset развертываний, и две службы подсистемы балансировки нагрузки для подключения к соответствующим экземплярам SQL Server.

  2. Вы также замечаете, что службы балансировщика нагрузки развертываются со статическими IP-адресами, которые можно настроить в Azure Kubernetes Service. Дополнительные сведения см. в статье Использование статического общедоступного IP-адреса и DNS-метки с подсистемой балансировки нагрузки Службы Azure Kubernetes (AKS). Создание служб балансировки нагрузки со статическими IP-адресами гарантирует, что внешний IP-адрес не изменится при удалении и повторном создании службы балансировки нагрузки.

  3. В следующем сценарии можно увидеть, что порт 13500 используется для переменной MSSQL_RPC_PORT среды и порт 51000 для MSSQL_DTC_TCP_PORT переменной среды, оба из которых необходимы для MSDTC.

  4. Маршрутизация портов (то есть маршрутизация порта 135 на 13500) настраивается в скрипте балансировщика нагрузки посредством правильной настройки port и targetPort, как показано в следующем примере:

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

Если вы создали ресурс в пространстве имен по умолчанию, при выполнении kubectl get all команды после предыдущего развертывания, чтобы просмотреть все созданные ресурсы, вы увидите выходные данные, показанные в следующем примере.

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

С помощью таких средств, как SQL Server Management Studio (SSMS), можно подключиться к обоим предыдущим экземплярам SQL Server и запустить пример транзакции DTC. В этом примере подключитесь к mssql-1 (10.72.137.129) и создадите связанный сервер mssql-0 (10.88.213.209), чтобы запустить распределенную транзакцию, как показано в следующем примере.

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

Внимание

Пароль должен соответствовать политике паролей по умолчанию SQL Server. По умолчанию пароль должен быть не короче восьми символов и содержать три вида символов из следующих: прописные буквы, строчные буквы, десятичные цифры, специальные символы. Пароли могут иметь длину до 128 символов. Рекомендуется использовать максимально длинные и сложные пароли.

Теперь вы можете запустить распределенную транзакцию, и в этом примере кода показано, как sys.sysprocesses это сделать из экземпляра mssql-0 :

SET XACT_ABORT ON;

BEGIN DISTRIBUTED TRANSACTION;

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

COMMIT TRANSACTION;
GO