Skip to main content
Version: v2.0

Create a SQL Server Availability Group in Kubernetes

DxOperator is a software extension to Kubernetes that uses custom resource definitions to automate the deployment of DxEnterprise clusters. DxEnterprise then provides all of the instrumentation to create, configure, manage and provide automatic failover for Microsoft SQL Server availability group workloads in Kubernetes.

For a free developer license to test DxOperator - Request a free license.

Prerequisites

  • A Kubernetes cluster installed with at least 8GB of RAM.
  • A valid DxEnterprise license with availability group management features and tunnels enabled. A fully featured Developer Edition is available free for non-production use. To purchase DxEnterprise software for production workloads, please contact us.

Install DxOperator

  1. Download the DxOperator YAML.

    curl https://dxoperator.dh2i.com/dxsqlag/files/v2.yaml -o v2.yaml
  2. Apply the DxOperator YAML.

    kubectl apply -f v2.yaml
  3. Wait for the DxOperator pod to become ready.

    kubectl get pods -n dxoperator-v2-system -w

Create a SQL Server Availability Group

  1. Create secrets for the DxEnterprise passkey and license key, and the SQL Server SA account.

    kubectl create secret generic dxe --from-literal=DX_PASSKEY=<password> --from-literal=DX_LICENSE=<license_key>
    kubectl create secret generic mssql --from-literal=MSSQL_SA_PASSWORD=<password>
  2. (OPTIONAL) Apply a ConfigMap YAML for the mssql.conf file.

    info

    See the Microsoft documentation for all supported variables for MSSQL.

    configmap.yaml
    kind: ConfigMap 
    apiVersion: v1
    metadata:
    name: mssql-config
    data:
    mssql.conf: |

    [sqlagent]
    enabled = true
    kubectl apply -f configmap.yaml
  3. Copy the example DxSqlAg.yaml file below.

    info

    There are many configuration options for the DxSqlAg custom resource beyond those that are shown in this example. View the DxSqlAg API Reference for more information.

    apiVersion: dh2i.com/v1
    kind: DxSqlAg
    metadata:
    name: dxsqlag
    spec:
    sqlAgConfiguration:
    synchronousReplicas: 3
    asynchronousReplicas: 0
    # ConfigurationOnlyReplicas are only allowed with availabilityGroupClusterType set to EXTERNAL
    configurationOnlyReplicas: 0
    availabilityGroupName: AG1
    # Adds auto-generated load balancers to serviceTemplates for easy cluster access
    # For more customization, use the serviceTemplates section below
    #createLoadBalancers: true
    # Listener port for the availability group (uncomment to apply)
    #availabilityGroupListenerPort: 14033
    # For a contained availability group, add the option CONTAINED
    #availabilityGroupOptions: CONTAINED
    # Disables automatic availability mode switching when scaling down
    #disableModeSwitching: true
    # Service templates are used to create a service for each pod in the cluster
    serviceTemplates:
    - name: custom-service
    type: LoadBalancer
    ports:
    - name: dxe-admin
    port: 7979
    protocol: TCP
    # Per-service customizations are used to specify values specific to a service
    perServiceCustomizations:
    - name: custom-service-dxsqlag-0
    metadata:
    annotations:
    cloud-provider: "10.0.0.100"
    - name: custom-service-dxsqlag-1
    metadata:
    annotations:
    cloud-provider: "10.0.0.101"
    statefulSetSpec:
    podSpec:
    dxEnterpriseContainer:
    image: "docker.io/dh2i/dxe:latest"
    imagePullPolicy: Always
    acceptEula: true
    clusterSecret: dxe
    vhostName: VHOST1
    # Configuration options for the required persistent volume claim for DxEnterprise
    #volumeClaimConfiguration:
    # Set custom storage class for DxE PVC
    #storageClassName: example-class
    mssqlServerContainer:
    image: "mcr.microsoft.com/mssql/server:2025-latest"
    imagePullPolicy: Always
    mssqlSecret: mssql
    acceptEula: true
    mssqlPID: Developer
    # Set a non-default SQL Server port. DxOperator will auto-detect
    # the port from other sources too, such as mssqlConfigMap
    #mssqlTcpPort: 51433
    # The MSSQL configMap (mssql.conf file)
    #mssqlConfigMap: mssql-config
    # Configuration options for the required persistent volume claim for SQL Server
    #volumeClaimConfiguration:
    # resources:
    # requests:
    # storage: 2Gi
    # Additional pod containers, such as mssql-tools
    #containers:
    #- name: mssql-tools
    #image: "mcr.microsoft.com/mssql-tools"
    #command: [ "/bin/sh" ]
    #args: [ "-c", "tail -f /dev/null" ]
    SECURITY CAUTION: Avoid Default Listening Port for SQL Server

    For security best practices, do not use the default SQL Server port (1433) when configuring SQL Server instances in production environments. Using the default port can expose your instance to automated scanning and brute-force attacks. In production environments, it is strongly recommended to configure a non-standard port to reduce the attack surface and improve security posture. For more information on configuring SQL Server to use a non-default port, see: Configure SQL Server's Listening Port

    Also note: If you applied a ConfigMap in the previous optional step, you must explicitly set spec.mssqlServerContainer.mssqlConfigMap to ensure it is used:

    mssqlConfigMap: mssql-config
  4. Apply the DxSqlAg custom resource YAML.

    kubectl apply -f DxSqlAg.yaml
  5. Verify the StatefulSet has been created.

    kubectl get sts dxsqlag

That's it! DxOperator will begin spinning up a new SQL Server Availability Group in Kubernetes and should - depending on cluster resources - finish within a few minutes. You can check on the progress using kubectl exec -itc dxe dxsqlag-0 -- dxcli get-ags-detail <vhost_name> <ag_name>.

Creating an Availability Group Listener

  1. Assign the availabilityGroupListenerPort.

    Update the following value in the DxSqlAg.yaml file:

    DxSqlAg.yaml
    spec:
    sqlAgConfiguration:
    availabilityGroupListenerPort: 14033

    Apply the file:

    kubectl apply -f DxSqlAg.yaml
  2. In the DxSqlAg spec, uncomment the entry for the AG Listener.

  3. Apply the service YAML to add a load balancer for the listener.

    info

    Make sure to set the selector to dh2i.com/entity-name: <DxSqlAg_name>, using the name that was applied in the DxSqlAg.yaml above.

    Example Load Balancer Service
    apiVersion: v1
    kind: Service
    metadata:
    name: dxsqlag-cluster-lb
    spec:
    type: LoadBalancer
    selector:
    dh2i.com/entity-name: dxsqlag
    # This label points to whichever pod is the active Vhost member
    dh2i.com/active-vhost-vhost1: "true"
    ports:
    - name: sql
    protocol: TCP
    port: 1433
    targetPort: 1433
    - name: listener
    protocol: TCP
    port: 14033
    targetPort: 14033
    - name: dxe
    protocol: TCP
    port: 7979
    targetPort: 7979
  4. Verify the load balancer assignments.

    kubectl get services

What You Accomplished

Congratulations! You've successfully deployed a SQL Server Availability Group with automatic failover capabilities in Kubernetes using DxOperator. You now have:

  • Enterprise-grade high availability for your SQL Server workloads running in containers
  • Automatic failover that keeps your applications running even during node or instance failures
  • A foundation for production-ready database deployments that scale with your organization

Ready to take the next step? Contact DH2i to learn how DxOperator can power your mission-critical SQL Server workloads in Kubernetes.

Removing Custom Resources and DxOperator

The below steps will allow you to delete the custom resources and PVCs to redeploy with the same operator (steps 1 & 2). Or you can optionally also delete DxOperator completely (step 3).

  1. Delete the DxSqlAg custom resource YAML.

    kubectl delete -f DxSqlAg.yaml
  2. Delete the persistent volume claims (PVC).

    kubectl delete pvc --all
  3. Delete the DxOperator YAML.

    danger

    Running this command will delete the DxEnterpriseSqlAg CRD. If any DxEnterpriseSqlAg custom resources remain in the Kubernetes cluster, Kubernetes will destroy them as part of the deletion process. Only run this command if you intend on removing every DxEnterpiseSqlAg too!

    To list all DxSqlAgs, run 'kubectl get dxsqlag'.

    kubectl delete -f v2.yaml