SQL Server Availability Groups for Kubernetes StatefulSets on Azure
Introduction
This guide describes how to create and deploy a DxEnterprise + SQL Server container image to an Azure Kubernetes Service (AKS) cluster for Availability Groups. Using this guide, the user will create a DxEnterprise + SQL Server container image and push the image to a repository, deploy and configure an AKS cluster and a StatefulSet, and use DxEnterprise to create and configure the availability group.
This guide covers the deployment of three AG replicas. When deploying availability groups, please be aware of Quorum Considerations for SQL Server Availability Groups.
Prerequisites
-
A machine with the Azure and Kubernetes CLIs installed and logged into an Azure account. For information about installing the Azure CLI and logging in, view Microsoft documentation. To install the Kubernetes CLI, run the command
az aks install-cli
. Alternatively, the Azure Cloud Shell may be used. -
Docker installed on a Linux VM and logged in to a Docker account with push and pull privileges. This can be the same VM that has the Azure and Kubernetes CLIs installed. For more information about installing Docker, view Docker documentation. Use
docker login
to log into a Docker account. -
A valid repository for the image on a registry service such as Docker Hub. For more information about creating repositories on Docker Hub, view Docker documentation. This guide relies on Docker instructions, but it is perfectly acceptable to use another registry service such as Azure Container Registry.
-
A valid DxEnterprise license with availability group management features and tunnels enabled. A fully featured Developer Edition is available for free for non-production use. To purchase DxEnterprise software for production workloads, visit the DH2i Store.
Prepare the Kubernetes Cluster
This section describes how to create the container image, create the Kubernetes image, and deploy the StatefulSet in Azure.
Create the SQL Server and DxEnterprise Combined Container Image
-
Download the dxemssql Dockerfile from DH2i’s GitHub to the current working directory.
curl https://raw.githubusercontent.com/dh2i/dxemssql/main/dxemssql.dockerfile -o dxemssql.dockerfile
-
Build the image using the Dockerfile. The DxEnterprise + SQL Server container image layers DxEnterprise software on top of the base SQL Server image. The Dockerfile contains commands to install .NET Core 3.1, add the DxEnterprise tarball from DH2i’s website, and add some additional permissions. Ensure that the image is tagged with a
<Docker_ID>
and<repository>
(e.g.,dh2i/dxemssql
):docker build -t <Docker_ID>/<repository> -f dxemssql.dockerfile ./
-
Push the image to Docker Hub, or any other registry service.
docker push <Docker_ID>/<repository>
Create the Kubernetes Cluster
-
Create a resource group in Azure for the Kubernetes cluster.
az group create -n <resource_group> -l <region>
-
Create a two-node Azure Kubernetes Service (AKS) Cluster in the resource group. For more information about CLI parameters, view Microsoft documentation.
az aks create -g <resource_group> -n <cluster_name> -c 2 --disable-rbac --generate-ssh-keys
-
Obtain the access credentials for the AKS cluster.
az aks get-credentials -g <resource_group> -n <cluster_name>
Create the StatefulSet
-
Download the example YAML deployment from DH2i’s GitHub.
curl https://raw.githubusercontent.com/dh2i/dxemssql/main/dxemssql.yaml -o dxemssql.yaml
-
Use sed to insert the Docker ID and repository into the YAML configuration. Replace the
<Docker_ID>
and<repository>
with those used in steps 2 and 3 of the previous section.cautionNote that the backslash after the
<Docker_ID>
is required as part of the command.sed -i 's/image:.*/image: <Docker_ID>\/<repository>/' dxemssql.yaml
-
Create a credential for the SQL instance.
kubectl create secret generic mssql --from-literal=SA_PASSWORD="<password>"
-
List the nodes, then apply the primary label to one of the Kubernetes nodes (VM).
kubectl get nodes
kubectl label node <node_name> role=ags-primary -
Apply the secondary label to the remaining node.
kubectl label node <node_name> role=ags-secondary
-
Apply the StatefulSet configuration.
kubectl apply -f dxemssql.yaml
-
Check the status of the pods using one or both of the commands below. Proceed to the next section after the primary pod’s status updates to “running”.
kubectl get pods
kubectl describe pods
Create the Availability Group
This section describes how to start the availability group on the primary, then join the two secondary Kubernetes pods to the DxEnterprise cluster and the availability group.
Configure the Primary Pod and Add the Availability Group
All DxCLI commands can be run from outside the container using the command format kubectl exec <pod_name> -- dxcli <command>
. This format will be used for all of the subsequent DxCLI
command examples.
-
Activate the DxEnterprise license using the command
dxcli activate-sever
.Example
kubectl exec dxemssql-primary-0 -- dxcli activate-server AAAA-BBBB-CCCC-DDDD
-
Add a Vhost to the cluster using the command
dxcli cluster-add-vhost
.Example
kubectl exec dxemssql-primary-0 -- dxcli cluster-add-vhost vhost *127.0.0.1 dxemssql-primary-0
-
Encrypt the SQL Server sysadmin password for DxEnterprise using the command
dxcli encrypt-text
. The encrypted password will be used to create the availability group in the next step.Example
kubectl exec dxemssql-primary-0 -- dxcli encrypt-text pa$$word
-
Add an availability group to the Vhost using the command
dxcli add-ags
. The SQL Server sysadmin password must be encrypted using the commanddxcli encrypt-text
from the previous step.Example
kubectl exec dxemssql-primary-0 -- dxcli add-ags vhost1 ags1 "dxemssql-primary-0|mssqlserver|sa|6pnFaDrRS+W/F+dkRuPKAA==|5022|synchronous_commit|50221"
-
Set a One-Time PassKey (OTPK) using the command
dxcli set-otpk
. The output from this command will be used to join the other nodes to the DxEnterprise cluster.Example
kubectl exec dxemssql-primary-0 -- dxcli set-otpk
Join the Second Pod to the DxEnterprise Cluster
-
Activate the DxEnterprise license for the second node using the command
dxcli activate-server
.Example
kubectl exec dxemssql-secondary-0 -- dxcli activate-server AAAA-BBBB-CCCC-DDDD
-
Join the second node to the DxEnterprise cluster using the command
dxcli join-cluster-ex
. Use the default NAT proxy of match.dh2i.com.Example
kubectl exec dxemssql-secondary-0 -- dxcli join-cluster-ex match.dh2i.com 331bc8bf-7096-99bc-05e5-0dd097393600 true
-
Add the second node to the existing availability group using the command
dxcli add-ags-node
. The SQL Server sysadmin password must be encrypted using the commanddxcli encrypt-text
.infoThe commands
dxcli add-ags
anddxcli add-ags-node
take identical parameter sets. The only parameters which must be unique to each command are thenode_name
and thetunnel_port
.The functionality difference between the commands is that
add-ags
creates the availability group under a Vhost, whileadd-ags-node
adds a node to an existing Vhost and availability group.Example
kubectl exec dxemssql-secondary-0 -- dxcli add-ags-node vhost1 ags1 "dxemssql-secondary-0|mssqlserver|sa|6pnFaDrRS+W/F+dkRuPKAA==|5022|synchronous_commit|50222"
Join the Third Pod to the DxEnterprise Cluster
-
Activate the DxEnterprise license for the third node using the command
dxcli activate-server
.Example
kubectl exec dxemssql-secondary-1 -- dxcli activate-server AAAA-BBBB-CCCC-DDDD
-
Join the third node to the DxEnterprise cluster using the command
dxcli join-cluster-ex
.Example
kubectl exec dxemssql-secondary-1 -- dxcli join-cluster-exmatch.dh2i.com 331bc8bf- 7096 - 99bc-05e5-0dd097393600 true
-
Add the third node to the existing availability group using the command
dxcli add-ags-node
.- Synchronous Replica
- Asynchronous Replica
- Configuration Only
kubectl exec dxemssql-secondary-1 -- dxcli add-ags-node vhost1 ags1 "dxemssql-secondary-1|mssqlserver|sa|6pnFaDrRS+W/F+dkRuPKAA==|5022|synchronous_commit|50223"
kubectl exec dxemssql-secondary-1 -- dxcli add-ags-node vhost1 ags1 "dxemssql-secondary-1|mssqlserver|sa|6pnFaDrRS+W/F+dkRuPKAA==|5022|asynchronous_commit|50223"
kubectl exec dxemssql-secondary-1 -- dxcli add-ags-node vhost1 ags1 "dxemssql-secondary-1|mssqlserver|sa|6pnFaDrRS+W/F+dkRuPKAA==|5022|configuration_only|50223"
Add the Availability Group Database(s)
-
If a database is not already available, create it using
sqlcmd
on the primary.kubectl exec dxemssql-primary-0 -- /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P p@ssw0rd -Q "create database db1"
-
Add databases to the availability group from the primary using the command
dxcli add-ags-databases
.Example
kubectl exec dxemssql-primary-0 -- dxcli add-ags-databases vhost1 ags1 db1
-
Verify the details of the availability group using the command
dxcli get-ags-detail
.Example
kubectl exec dxemssql-primary-0 -- dxcli get-ags-detail vhost1 ags1
Optional: Configure External Access to the Cluster
These steps describe how to configure external access to cluster resources using an Azure load balancer.
Create the AG Listener and a Load Balancer for the StatefulSet
Load balancers can be used by Kubernetes to provide access to cluster resources via a public IP address. The steps below describe how to apply a load balancer that will allow access to the DxEnterprise management port, the SQL Server management port, and the AGS listener port.
-
Set a cluster passkey using the command
dxcli cluster-set-secret-ex
. A cluster passkey is required for connecting to the cluster using the DxAdmin UI.Example
kubectl exec dxemssql-primary-0 -- dxcli cluster-set-secret-ex p@ssw0rd
-
Set an AG listener port using the command
dxcli add-ags-listener
.Example
kubectl exec dxemssql-primary- 0 -- dxcli add-ags-listener vhost1 ags1 14033
-
Download the example load balancer configuration from DH2i’s GitHub.
curl https://raw.githubusercontent.com/dh2i/dxemssql/main/lb.yaml -o lb.yaml
-
Apply the load balancer.
kubectl apply -f lb.yaml
-
List the service and note the external IP address.
kubectl get service
-
Connect to the instance (port 1433) or AG listener (port 14033) via SSMS and the external IP address.
-
DxEnterprise’s administration port of 7979 is used for DxCLI and DxAdmin, DxEnterprise’s client UI. Use the external IP address from step 5 and passkey from step 1 to connect to the cluster from a remote machine. For more information about installing DxAdmin, view the DxAdmin Client UI Quick Start Guide.
Optional: Replace the Azure-allocated IP address with a Static IP
When creating a Kubernetes load balancer service in Azure, the load balancer is assigned a public IP address that lasts for the lifespan of the resource. This IP address will change if the service is deleted and recreated. Reference Microsoft documentation for further information about static IPs in Kubernetes. To assign a static IP that persists between service re-deployments, do the following:
-
Delete any running load balancer resource for the DxEnterprise + SQL Server cluster.
kubectl delete -f lb.yaml
-
Create a Public IP address resource with a static allocation method and standard SKU using the Azure CLI. The public IP address should be assigned to the additional resource group Azure created during the initial Kubernetes cluster deployment. The name of this auto-generated resource group follows the pattern
MC_<resource-group>_<cluster-name>_<region>
. To list the name, run the commandaz group list | grep “MC_”
. For example:az network public-ip create -g MC_examplegroup_examplecluster_westus2 -n exampleStaticIPName --sku Standard --allocation-method static
-
Copy the
ipAddress
value from the JSON output. -
Use
sed
to add the static IP to the service YAML file. Replace the<Public_IP>
value with the IP address copied in step 2. Note in the command that there are two spaces after the backslash.sed -i '/.*type:.*/a \ loadBalancerIP: <Public_IP>' lb.yaml
-
Reapply the load balancer.
kubectl apply -f lb.yaml
-
Verify the load balancer is using the new static IP.
kubectl get service