Docker 容器部署 SQL Server AlwaysOn AG

本文详细介绍了如何在Linux Ubuntu虚拟机上利用Docker镜像构建并配置SQL Server 2019的AlwaysOn Availability Group(AG),包括安装Docker、创建镜像、启动容器、配置实例、证书管理及AG设置等步骤。

SQL Server 2016 开始支持 Linux。随着2017 和2019 版本的推出,它开始支持Linux和Container平台上的HA/DR、Kubernetes和大数据集群解决方案。

今天我们就直接测试,使用容器构建 SQL Server AlwaysOn AG,这对于学习 AlwaysOn AG 的同学来说,是不错的选择。容器可以使用更少的资源,就可配置完成。文章比较详细,一步步跟踪操作即可实现!

现在,我们创建了一台Ubuntu虚拟机,接下来,我们继续安装 docker ,并通过模板(docker镜像)创建3个 SQL Server 实例容器,然后在这3个实例中配置 AlwaysOn AG。不管在 Linux 或是容器环境,没有配置系统集群的情况下,也是可以配置 SQL Server AlwaysOn AG 的,只是 AlwaysOn AG 并没有实现自动故障转移,不过我们可以进行手动故障转移。

首先安装 Docker & Docker-Compose 

#如果有之前版本的docker安装,建议删除
apt-get remove docker docker-engine docker.io containerd runc
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common

#添加Docker的官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

#添加 Docker 存储库
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

#安装Docker引擎
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
apt-get install -y docker-compose

配置SQLServer实例镜像

# vi dockerfile
FROM ubuntu:20.04

RUN DEBIAN_FRONTEND="noninteractive"
RUN apt-get update && apt-get install -y tzdata
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt-get update
RUN apt install -y sudo wget curl gnupg gnupg1 gnupg
RUN apt install -y software-properties-common systemd vim
RUN apt install -y telnetd iputils-ping

RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
RUN add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/18.04/mssql-server-2019.list)"

RUN apt-get update
RUN apt-get install -y libldap2-dev checkinstall
RUN apt-get install -y mssql-server

RUN /opt/mssql/bin/mssql-conf set hadr.hadrenabled  1
RUN /opt/mssql/bin/mssql-conf set sqlagent.enabled true
RUN /opt/mssql/bin/mssql-conf set memory.memorylimitmb 2048

EXPOSE 1433
EXPOSE 5022

ENTRYPOINT /opt/mssql/bin/sqlservr

构建SQLServer实例镜像

配名称为 dockerfile,build 默认现在当前路径文件,当然你也可以指定。

# 先拉取系统镜像
docker pull ubuntu:20.04

#构建SQLServer镜像
docker build -t mssql2019:hadr .

#查看
docker images
------------------------------------------------------------------------------------
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
------------------------------------------------------------------------------------
mssql2019           hadr                a9134337ba77        2 hours ago         1.8GB
ubuntu              20.04               ba6acccedd29        6 weeks ago         72.8MB
------------------------------------------------------------------------------------

docker compose 启动3个 SQL Server 容器

# vi docker-compose.yml
version: '3'

services:
  db1:
    container_name: sqlNode1
    image: mssql2019:hadr
    hostname: sqlNode1
    domainname: lab.local
    environment:
      SA_PASSWORD: "Str0ngPa@w0rd"
      ACCEPT_EULA: "Y"
    ports:
    - "1501:1433"
    extra_hosts:
      sqlNode2.lab.local: "10.10.10.102"
      sqlNode3.lab.local: "10.10.10.103"
    networks:
      internal:
        ipv4_address: 10.10.10.101

  db2:
    container_name: sqlNode2
    image: mssql2019:hadr
    hostname: sqlNode2
    domainname: lab.local
    environment:
      SA_PASSWORD: "Str0ngPa@w0rd"
      ACCEPT_EULA: "Y"
    ports:
    - "1502:1433"
    extra_hosts:
      sqlNode1.lab.local: "10.10.10.101"
      sqlNode3.lab.local: "10.10.10.103"
    networks:
      internal:
        ipv4_address: 10.10.10.102

  db3:
    container_name: sqlNode3
    image: mssql2019:hadr
    hostname: sqlNode3
    domainname: lab.local
    environment:
      SA_PASSWORD: "Str0ngPa@w0rd"
      ACCEPT_EULA: "Y"
    ports:
    - "1503:1433"
    extra_hosts:
      sqlNode1.lab.local: "10.10.10.101"
      sqlNode2.lab.local: "10.10.10.102"
    networks:
      internal:
        ipv4_address: 10.10.10.103

networks:
    internal:
      driver: bridge
      ipam:
        driver: default
        config:
          - subnet: 10.10.10.0/24

启动时,Docker 将创建一个新的 bridge 网络,可通过 ifconfig 或 docker network ls 查看。当然,你也可以使用一个已存在的虚拟网络。接下来,才是启动!

#Docker Compose 启动堆栈,-d 后台运行
docker-compose up -d

docker ps
docker-compose ps
------------------------------------------------------------------------------------
  Name                Command               State                Ports
------------------------------------------------------------------------------------
sqlNode1   /bin/sh -c /opt/mssql/bin/ ...   Up      0.0.0.0:1501->1433/tcp, 5022/tcp
sqlNode2   /bin/sh -c /opt/mssql/bin/ ...   Up      0.0.0.0:1502->1433/tcp, 5022/tcp
sqlNode3   /bin/sh -c /opt/mssql/bin/ ...   Up      0.0.0.0:1503->1433/tcp, 5022/tcp
------------------------------------------------------------------------------------

安装客户端工具 sqlcmd

实例已经创建好SQLServer实例了,怎么去连接呢?我们需要一个客户端工具——sqlcmd。

curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/21.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list
apt-get update
apt-get install -y mssql-tools unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

此时我们可以通过该工具进行连接操作实例了!

sqlcmd -S "127.0.0.1,1501" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "print @@servername"

当然,你也可以通过Windows客户端工具 SSMS 进行连接操作。IP为虚拟机Ubuntu的IP地址,端口为容器对外映射的端口。

SQL Server AlwaysOn AG 配置

3个实例创建登录名、主密钥和证书

#创建登录名、主密钥和证书
for port in {1501..1503}
do
sqlcmd -S "127.0.0.1,$port" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE LOGIN dbm_login WITH PASSWORD = 'MyStr0ngPa@w0rd';
GO
CREATE USER dbm_user FOR LOGIN dbm_login;
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd';
GO
CREATE CERTIFICATE dbm_certificate_$port WITH SUBJECT = 'dbm';
GO
CREATE ENDPOINT [Hadr_endpoint]
    AS TCP (LISTENER_IP = (0.0.0.0), LISTENER_PORT = 5022)
    FOR DATA_MIRRORING (
        ROLE = ALL,
        AUTHENTICATION = CERTIFICATE dbm_certificate_$port,
        ENCRYPTION = REQUIRED ALGORITHM AES
    );
GO
ALTER ENDPOINT [Hadr_endpoint] STATE = STARTED;
GO
GRANT CONNECT ON ENDPOINT::[Hadr_endpoint] TO [dbm_login];
GO
BACKUP CERTIFICATE dbm_certificate_$port
TO FILE = '/tmp/dbm_certificate_$port.cer'
WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_$port.pvk',
        ENCRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO"
done

将带有 cer 和 pvk 扩展名的文件从容器复制到其他容器节点

docker cp sqlNode1:/tmp/dbm_certificate_1501.cer .
docker cp sqlNode1:/tmp/dbm_certificate_1501.pvk .
docker cp sqlNode2:/tmp/dbm_certificate_1502.cer .
docker cp sqlNode2:/tmp/dbm_certificate_1502.pvk .
docker cp sqlNode3:/tmp/dbm_certificate_1503.cer .
docker cp sqlNode3:/tmp/dbm_certificate_1503.pvk .

docker cp dbm_certificate_1501.cer sqlNode2:/tmp/
docker cp dbm_certificate_1501.pvk sqlNode2:/tmp/
docker cp dbm_certificate_1501.cer sqlNode3:/tmp/
docker cp dbm_certificate_1501.pvk sqlNode3:/tmp/
docker cp dbm_certificate_1502.cer sqlNode1:/tmp/
docker cp dbm_certificate_1502.pvk sqlNode1:/tmp/
docker cp dbm_certificate_1502.cer sqlNode3:/tmp/
docker cp dbm_certificate_1502.pvk sqlNode3:/tmp/
docker cp dbm_certificate_1503.cer sqlNode1:/tmp/
docker cp dbm_certificate_1503.pvk sqlNode1:/tmp/
docker cp dbm_certificate_1503.cer sqlNode2:/tmp/
docker cp dbm_certificate_1503.pvk sqlNode2:/tmp/

各节点相互还原证书

sqlcmd -S "127.0.0.1,1501" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE CERTIFICATE dbm_certificate_1502  
    AUTHORIZATION dbm_user
    FROM FILE = '/tmp/dbm_certificate_1502.cer'
    WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_1502.pvk',
        DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO
CREATE CERTIFICATE dbm_certificate_1503  
AUTHORIZATION dbm_user
FROM FILE = '/tmp/dbm_certificate_1503.cer'
WITH PRIVATE KEY (
    FILE = '/tmp/dbm_certificate_1503.pvk',
    DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO"

sqlcmd -S "127.0.0.1,1502" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE CERTIFICATE dbm_certificate_1501  
    AUTHORIZATION dbm_user
    FROM FILE = '/tmp/dbm_certificate_1501.cer'
    WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_1501.pvk',
        DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO
CREATE CERTIFICATE dbm_certificate_1503  
    AUTHORIZATION dbm_user
    FROM FILE = '/tmp/dbm_certificate_1503.cer'
    WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_1503.pvk',
        DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO"

sqlcmd -S "127.0.0.1,1503" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE CERTIFICATE dbm_certificate_1501  
    AUTHORIZATION dbm_user
    FROM FILE = '/tmp/dbm_certificate_1501.cer'
    WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_1501.pvk',
        DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO
CREATE CERTIFICATE dbm_certificate_1502 
    AUTHORIZATION dbm_user
    FROM FILE = '/tmp/dbm_certificate_1502.cer'
    WITH PRIVATE KEY (
        FILE = '/tmp/dbm_certificate_1502.pvk',
        DECRYPTION BY PASSWORD = 'MyStr0ngPa@w0rd'
    );
GO"

现在,开始创建 AlwaysOn Availability Group,因为非集群,所以设置 CLUSTER_TYPE = EXTERNAL

sqlcmd -S "127.0.0.1,1501" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE AVAILABILITY GROUP [MyAG]
    WITH (CLUSTER_TYPE = NONE)
    FOR REPLICA ON
    N'sqlNode1'
        WITH (
        ENDPOINT_URL = N'tcp://sqlNode1:5022',
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
            SEEDING_MODE = AUTOMATIC,
            FAILOVER_MODE = MANUAL,
            SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL)
        ),
    N'sqlNode2'
        WITH (
        ENDPOINT_URL = N'tcp://sqlNode2:5022',
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
            SEEDING_MODE = AUTOMATIC,
            FAILOVER_MODE = MANUAL,
            SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL)
        ),
    N'sqlNode3'
        WITH (
        ENDPOINT_URL = N'tcp://sqlNode3:5022',
        AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
            SEEDING_MODE = AUTOMATIC,
            FAILOVER_MODE = MANUAL,
            SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL)
        );
GO"

两个辅助节点加入 AG

sqlcmd -S "127.0.0.1,1502" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
ALTER AVAILABILITY GROUP [MyAG] JOIN WITH (CLUSTER_TYPE = NONE);
GO
ALTER AVAILABILITY GROUP [MyAG] GRANT CREATE ANY DATABASE;
GO"

sqlcmd -S "127.0.0.1,1503" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
ALTER AVAILABILITY GROUP [MyAG] JOIN WITH (CLUSTER_TYPE = NONE);
GO
ALTER AVAILABILITY GROUP [MyAG] GRANT CREATE ANY DATABASE;
GO"

现在,我们可以在Primary节点创建数据库进行测试。我们配置 AG时已经设置自动播种模式(SEEDING_MODE = AUTOMATIC),所以数据库就不需要通过备份还原初始化了。

sqlcmd -S "127.0.0.1,1501" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "
CREATE DATABASE test;
GO
ALTER DATABASE test SET RECOVERY FULL;
GO
BACKUP DATABASE test TO DISK = 'NUL:';
GO
BACKUP LOG test TO  DISK = 'NUL:';
GO
ALTER AVAILABILITY GROUP [MyAG] ADD DATABASE [test];
GO"

如何切换角色呢?比如我们将primary切换到端口为 1502 的节点。

sqlcmd -S "127.0.0.1,1502" -d "master" -U SA -P "Str0ngPa@w0rd" -Q "ALTER AVAILABILITY GROUP [MyAG] FORCE_FAILOVER_ALLOW_DATA_LOSS"

 如果你想用到开发或测试环境,你也可以把数据设置存储到容器之外的磁盘位置,但资源要提前规划好(生产环境没必要容器化数据库)。当然,容器化的一个好处就是,你可以创建更多的独立容器实例来模拟各种测试,相比以前我们开很多虚拟机方便多了!

更多资源,请关注公众号

参考:

Quickstart: Run SQL Server container images with Docker

SQL Server 2019 AlwaysOn Availability Group on Docker Containers

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值