Deploy a single Neo4j cluster across multiple AKS clusters

With the Neo4j Helm chart, you can deploy a Neo4j cluster on multiple AKS clusters using load balancers and an Azure application gateway.

The following diagram is a schematic representation of a Neo4j cluster with three primary servers running on three different AKS clusters.

multi dc cc aks

The diagram shows three Neo4j instances, each running on a different AKS cluster in a different availability zone as part of a single Neo4j cluster. Each AKS cluster also includes an internal load balancer for each Neo4j instance and a LIST discovery method. They allow the Neo4j instances to communicate with each other. The Neo4j cluster can be accessed from outside Kubernetes using an Azure application gateway.

The following steps are an example of how to deploy a Neo4j cluster on a multi-AKS cluster.

Create three AKS clusters in three availability zones

You must have the Microsoft.Authorization/roleAssignments/write permission to perform these tasks.

  1. Install the az command-line interface (CLI) (https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).

  2. Create a resource group to host your virtual network. This example creates a resource group named my-RG in the eastus location:

    az group create \
        --name my-RG \
        --location eastus
    Example output
    {
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG",
      "location": "eastus",
      "managedBy": null,
      "name": "my-RG",
      "properties": {
        "provisioningState": "Succeeded"
      },
      "tags": null,
      "type": "Microsoft.Resources/resourceGroups"
    }
  3. In this resource group, create an Azure Virtual Network (VNet). This example creates a virtual network named my-VNet with the virtual network’s address range 10.30.0.0/16:

    az network vnet create \
      --name my-VNet \
      --resource-group my-RG \
      --address-prefixes 10.30.0.0/16
    Example output
    {
      "newVNet": {
        "addressSpace": {
          "addressPrefixes": [
            "10.30.0.0/16"
          ]
        },
        "bgpCommunities": null,
        "ddosProtectionPlan": null,
        "dhcpOptions": {
          "dnsServers": []
        },
        "enableDdosProtection": false,
        "enableVmProtection": null,
        "encryption": null,
        "etag": "W/\"97953f32-55fe-4821-aedd-ec7a800127e3\"",
        "extendedLocation": null,
        "flowTimeoutInMinutes": null,
        "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet",
        "ipAllocations": null,
        "location": "eastus",
        "name": "my-VNet",
        "provisioningState": "Succeeded",
        "resourceGroup": "my-RG",
        "resourceGuid": "4ed2a9f4-580e-4424-800b-1065ed9ad0a2",
        "subnets": [],
        "tags": {
          "Owner Department": "Engineering - Neo4j"
        },
        "type": "Microsoft.Network/virtualNetworks",
        "virtualNetworkPeerings": []
      }
    }
  4. Add four subnets to the virtual network you have created (my-VNet). They will be used by the Azure resources you will deploy on each AKS cluster. The subnet address range must be unique within the address space for the virtual network.

    az network vnet subnet create -g my-RG --vnet-name my-VNet -n subnet1 \
        --address-prefixes 10.30.1.0/24
    
    az network vnet subnet create -g my-RG --vnet-name my-VNet -n subnet2 \
        --address-prefixes 10.30.2.0/24
    
    az network vnet subnet create -g my-RG --vnet-name my-VNet -n subnet3 \
        --address-prefixes 10.30.3.0/24
    
    az network vnet subnet create -g my-RG --vnet-name my-VNet -n subnet4 \
        --address-prefixes 10.30.4.0/24
    Example output
    {
      "addressPrefix": "10.30.1.0/24",
      "addressPrefixes": null,
      "applicationGatewayIpConfigurations": null,
      "delegations": [],
      "etag": "W/\"32bb3a61-c446-4c20-b596-d92b6b9e2e9f\"",
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet1",
      "ipAllocations": null,
      "ipConfigurationProfiles": null,
      "ipConfigurations": null,
      "name": "subnet1",
      "natGateway": null,
      "networkSecurityGroup": null,
      "privateEndpointNetworkPolicies": "Disabled",
      "privateEndpoints": null,
      "privateLinkServiceNetworkPolicies": "Enabled",
      "provisioningState": "Succeeded",
      "purpose": null,
      "resourceGroup": "my-RG",
      "resourceNavigationLinks": null,
      "routeTable": null,
      "serviceAssociationLinks": null,
      "serviceEndpointPolicies": null,
      "serviceEndpoints": null,
      "type": "Microsoft.Network/virtualNetworks/subnets"
    }
    {
      "addressPrefix": "10.30.2.0/24",
      "addressPrefixes": null,
      "applicationGatewayIpConfigurations": null,
      "delegations": [],
      "etag": "W/\"8ec29708-e749-4a89-813e-0290c3c9a6f7\"",
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet2",
      "ipAllocations": null,
      "ipConfigurationProfiles": null,
      "ipConfigurations": null,
      "name": "subnet2",
      "natGateway": null,
      "networkSecurityGroup": null,
      "privateEndpointNetworkPolicies": "Disabled",
      "privateEndpoints": null,
      "privateLinkServiceNetworkPolicies": "Enabled",
      "provisioningState": "Succeeded",
      "purpose": null,
      "resourceGroup": "my-RG",
      "resourceNavigationLinks": null,
      "routeTable": null,
      "serviceAssociationLinks": null,
      "serviceEndpointPolicies": null,
      "serviceEndpoints": null,
      "type": "Microsoft.Network/virtualNetworks/subnets"
    }
    {
      "addressPrefix": "10.30.3.0/24",
      "addressPrefixes": null,
      "applicationGatewayIpConfigurations": null,
      "delegations": [],
      "etag": "W/\"4b9ba2be-e385-48e7-be24-c52c79769c3a\"",
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet3",
      "ipAllocations": null,
      "ipConfigurationProfiles": null,
      "ipConfigurations": null,
      "name": "subnet3",
      "natGateway": null,
      "networkSecurityGroup": null,
      "privateEndpointNetworkPolicies": "Disabled",
      "privateEndpoints": null,
      "privateLinkServiceNetworkPolicies": "Enabled",
      "provisioningState": "Succeeded",
      "purpose": null,
      "resourceGroup": "my-RG",
      "resourceNavigationLinks": null,
      "routeTable": null,
      "serviceAssociationLinks": null,
      "serviceEndpointPolicies": null,
      "serviceEndpoints": null,
      "type": "Microsoft.Network/virtualNetworks/subnets"
    }
    {
      "addressPrefix": "10.30.4.0/24",
      "addressPrefixes": null,
      "applicationGatewayIpConfigurations": null,
      "delegations": [],
      "etag": "W/\"ff08c2d1-2166-4c64-9892-3cac9bc20fd1\"",
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet4",
      "ipAllocations": null,
      "ipConfigurationProfiles": null,
      "ipConfigurations": null,
      "name": "subnet4",
      "natGateway": null,
      "networkSecurityGroup": null,
      "privateEndpointNetworkPolicies": "Disabled",
      "privateEndpoints": null,
      "privateLinkServiceNetworkPolicies": "Enabled",
      "provisioningState": "Succeeded",
      "purpose": null,
      "resourceGroup": "my-RG",
      "resourceNavigationLinks": null,
      "routeTable": null,
      "serviceAssociationLinks": null,
      "serviceEndpointPolicies": null,
      "serviceEndpoints": null,
      "type": "Microsoft.Network/virtualNetworks/subnets"
    }
  5. Now you are ready to create the AKS clusters. Get the subscription ID of subnet1 by either running the following command (it uses the jq command) or copying it from the subnet creation output.

    az network vnet subnet show -g my-RG --vnet-name my-VNet -n subnet1 --output json | jq .id
    Example output
    "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/
  6. Create the first AKS cluster named my-aks-cluster-a with 5 nodes in your resource group using the subscription ID.

    az aks create --name my-aks-cluster-a --node-count=5 --zones 1 --vnet-subnet-id "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet1" -g my-RG
    
    az aks create --name my-aks-cluster-b --node-count=5 --zones 1 --vnet-subnet-id "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet2" -g my-RG
    
    az aks create --name my-aks-cluster-c --node-count=5 --zones 1 --vnet-subnet-id "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet3" -g my-RG
    Example output
    Waiting for AAD role to propagate[################################    ]  90.0000%
    {
      "aadProfile": null,
      "addonProfiles": null,
      "agentPoolProfiles": [
        {
          "availabilityZones": [
            "1"
          ],
          "count": 5,
          "creationData": null,
          "currentOrchestratorVersion": "1.23.8",
          "enableAutoScaling": false,
          "enableEncryptionAtHost": false,
          "enableFips": false,
          "enableNodePublicIp": false,
          "enableUltraSsd": false,
          "gpuInstanceProfile": null,
          "hostGroupId": null,
          "kubeletConfig": null,
          "kubeletDiskType": "OS",
          "linuxOsConfig": null,
          "maxCount": null,
          "maxPods": 110,
          "minCount": null,
          "mode": "System",
          "name": "nodepool1",
          "nodeImageVersion": "AKSUbuntu-1804gen2containerd-2022.08.23",
          "nodeLabels": null,
          "nodePublicIpPrefixId": null,
          "nodeTaints": null,
          "orchestratorVersion": "1.23.8",
          "osDiskSizeGb": 128,
          "osDiskType": "Managed",
          "osSku": "Ubuntu",
          "osType": "Linux",
          "podSubnetId": null,
          "powerState": {
            "code": "Running"
          },
          "provisioningState": "Succeeded",
          "proximityPlacementGroupId": null,
          "scaleDownMode": null,
          "scaleSetEvictionPolicy": null,
          "scaleSetPriority": null,
          "spotMaxPrice": null,
          "tags": null,
          "type": "VirtualMachineScaleSets",
          "upgradeSettings": {
            "maxSurge": null
          },
          "vmSize": "Standard_DS2_v2",
          "vnetSubnetId": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/my-RG/providers/Microsoft.Network/virtualNetworks/my-VNet/subnets/subnet1",
          "workloadRuntime": null
        }
      ],
      "apiServerAccessProfile": null,
      "autoScalerProfile": null,
      "autoUpgradeProfile": null,
      "azurePortalFqdn": "my-aks-my-rg-5b9ae5-bd2a82e4.portal.hcp.eastus.azmk8s.io",
      "currentKubernetesVersion": "1.23.8",
      "disableLocalAccounts": false,
      "diskEncryptionSetId": null,
      "dnsPrefix": "my-aks-my-RG-5b9ae5",
      "enablePodSecurityPolicy": null,
      "enableRbac": true,
      "extendedLocation": null,
      "fqdn": "my-aks-my-rg-5b9ae5-bd2a82e4.hcp.eastus.azmk8s.io",
      "fqdnSubdomain": null,
      "httpProxyConfig": null,
      "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourcegroups/my-RG/providers/Microsoft.ContainerService/managedClusters/my-aks-cluster-a",
      "identity": {
        "principalId": "16334702-6bbd-44a0-8090-a7739b881974",
        "tenantId": "54e85725-ed2a-49a4-a19e-11c8d29f9a0f",
        "type": "SystemAssigned",
        "userAssignedIdentities": null
      },
      "identityProfile": {
        "kubeletidentity": {
          "clientId": "a445b12d-52d9-4564-b5cf-daa98bf17ab8",
          "objectId": "91cc2d37-0407-4916-a4cd-51849fbc6541",
          "resourceId": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourcegroups/MC_my-RG_my-aks-cluster-a_eastus/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-aks-cluster-a-agentpool"
        }
      },
      "kubernetesVersion": "1.23.8",
      "linuxProfile": {
        "adminUsername": "azureuser",
        "ssh": {
          "publicKeys": [
            {
              "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDzCbi+J6eJq9RTsCGFFhTk/PQrl8jNzbFYsPZeu4BKvyrRz7JfWRgzGLu6OTJynuUejKy6XlNaqYsEoZMsFdOMMYoK/bVCCUwOaOrpGAqNF9dCKbKkEnA6iv6WgEIfVHGoCtMc3pBRU0R9rfWYpf3h7WT/oShnaLzVhPUG+4Jblx3K2tRsZ5+2AEgQeniXUgtZRvPes8qXfr/OES7M7owI0VuOVgiuJo3//sCvDavGJwSAgUECzcPYOEwBfmTWNleYrluiEWc7Ye5Y+W8j86V4L/vh4LRs14WZ92Jt6K3QhshGSpY0tcLnxg7fskdZDtdcSWIPWpbQLdTxdIETKe66qDiijLXkpw2m3XRe8nTc5ysoXGaKvzASAWyR2FYpYvmaSSGe/65jeQMsDjSsEXnLRoDG2A3aHy5yV44QXSd4N9/+Znmea1WnB+tvOUuAlhIgjWvprRPXyhZHdybuQipXPErfYg4G83HWMwh35D5qBAV3DeZUIYYATFszYdGfp3ghdu1LBVXsgH/sHaMZXp9uy5PAP4jOxfGpho3k+UoQZHK3wwskxhK8/IiWpRPRPWUbfhUOilUdkQup8hyfVfGpW7htW3crFwXFbU1LG5gDNrars0i3OHqT1snFB3R38vxDaXdOZCEVPSQAevOj3Q/WYfO2m5o+gp2sEQtEp4mG+w== my.popova@gmail.com\n"
            }
          ]
        }
      },
      "location": "eastus",
      "maxAgentPools": 100,
      "name": "my-aks-cluster-a",
      "networkProfile": {
        "dnsServiceIp": "10.0.0.10",
        "dockerBridgeCidr": "172.17.0.1/16",
        "ipFamilies": [
          "IPv4"
        ],
        "loadBalancerProfile": {
          "allocatedOutboundPorts": null,
          "effectiveOutboundIPs": [
            {
              "id": "/subscriptions/5b9ae547-ce82-4834-b276-b72904ceaa84/resourceGroups/MC_my-RG_my-aks-cluster-a_eastus/providers/Microsoft.Network/publicIPAddresses/e7480132-3f34-4f2d-bbc3-4e27e23e574c",
              "resourceGroup": "MC_my-RG_my-aks-cluster-a_eastus"
            }
          ],
          "enableMultipleStandardLoadBalancers": null,
          "idleTimeoutInMinutes": null,
          "managedOutboundIPs": {
            "count": 1,
            "countIpv6": null
          },
          "outboundIPs": null,
          "outboundIpPrefixes": null
        },
        "loadBalancerSku": "Standard",
        "natGatewayProfile": null,
        "networkMode": null,
        "networkPlugin": "kubenet",
        "networkPolicy": null,
        "outboundType": "loadBalancer",
        "podCidr": "10.244.0.0/16",
        "podCidrs": [
          "10.244.0.0/16"
        ],
        "serviceCidr": "10.0.0.0/16",
        "serviceCidrs": [
          "10.0.0.0/16"
        ]
      },
      "nodeResourceGroup": "MC_my-RG_my-aks-cluster-a_eastus",
      "podIdentityProfile": null,
      "powerState": {
        "code": "Running"
      },
      "privateFqdn": null,
      "privateLinkResources": null,
      "provisioningState": "Succeeded",
      "publicNetworkAccess": null,
      "resourceGroup": "my-RG",
      "securityProfile": {
        "azureKeyVaultKms": null,
        "defender": null
      },
      "servicePrincipalProfile": {
        "clientId": "msi",
        "secret": null
      },
      "sku": {
        "name": "Basic",
        "tier": "Free"
      },
      "storageProfile": {
        "diskCsiDriver": {
          "enabled": true
        },
        "fileCsiDriver": {
          "enabled": true
        },
        "snapshotController": {
          "enabled": true
        }
      },
      "systemData": null,
      "tags": {
        "Owner Department": "Engineering - Neo4j"
      },
      "type": "Microsoft.ContainerService/ManagedClusters",
      "windowsProfile": null
    }
  7. Repeat the previous two steps to create two more AKS clusters, named my-aks-cluster-b and my-aks-cluster-c.

  8. Configure kubectl to use your AKS clusters using:

    az aks get-credentials --name my-aks-cluster-a --admin -g my-RG
    az aks get-credentials --name my-aks-cluster-b --admin -g my-RG
    az aks get-credentials --name my-aks-cluster-c --admin -g my-RG
    Example output
    Merged "my-aks-cluster-a-admin" as current context in /Users/myuser/.kube/config
    Merged "my-aks-cluster-b-admin" as current context in /Users/myuser/.kube/config
    Merged "my-aks-cluster-c-admin" as current context in /Users/myuser/.kube/config

In rare cases, where the usual K8S Kubernetes discovery methods do not work in your deployment/environment, you can use the multiCluster flag along with the LIST discovery method and perform all your network settings manually, as if you were using VMs for example. You need one load balancer per Neo4j Instance.

Install Neo4j on each AKS cluster

Install the neo4j/neo4j helm chart on each AKS cluster. The LoadBalancer service will be configured to use a private IP address from the subnet that was associated with the cluster. For example my-aks-cluster-a uses subnet1 with the range 10.30.1.0/24, so any address can be used from 10.30.1.1-10.30.1.255. In the example, the following are used for illustration:

  • server-1: 10.30.1.101

  • server-2: 10.30.2.101

  • server-3: 10.30.3.101

You must have owner’s permissions in the resource group or a custom permission with the Microsoft.Authorization/roleAssignments/write role not to face auth issues while deploying the load balancers.

Create a values.yaml file for each cluster member

Create a custom YAML file for each Neo4j cluster member, for example, server-1.values.yaml, server-2.values.yaml, server-3.values.yaml.

The property services.neo4j.spec.loadBalancerIP must be set to an IP address from the subnet1 example.

  1. Switch to the context of the first AKS cluster my-aks-cluster-a-admin using:

    kubectl config use-context my-aks-cluster-a-admin
  2. In the server-1.values.yaml, add the following settings to the Neo4j configuration:

    server-1.values.yaml
    # Neo4j Configuration (yaml format)
    neo4j:
      name: multicluster
      minimumClusterSize: 3
      acceptLicenseAgreement: "yes"
      edition: enterprise
    volumes:
      data:
        mode: defaultStorageClass
    services:
      neo4j:
        annotations:
          service.beta.kubernetes.io/azure-load-balancer-internal: "true"
        spec:
          loadBalancerIP: 10.30.1.101
        multiCluster: true
    config:
      dbms.cluster.discovery.type: LIST
      dbms.cluster.discovery.endpoints: "10.30.1.101:5000, 10.30.2.101:5000, 10.30.3.101:5000"
      server.discovery.advertised_address: "10.30.1.101:5000"
      server.cluster.advertised_address: "10.30.1.101:6000"
      server.cluster.raft.advertised_address: "10.30.1.101:7000"
      server.bolt.advertised_address: "10.30.1.101:7687"
      server.routing.advertised_address: "10.30.1.101:7688"
  3. In the server-2.values.yaml, add the following settings to the Neo4j configuration:

    server-2.values.yaml
    # Neo4j Configuration (yaml format)
    neo4j:
      name: multicluster
      minimumClusterSize: 3
      acceptLicenseAgreement: "yes"
      edition: enterprise
    volumes:
      data:
        mode: defaultStorageClass
    services:
      neo4j:
        spec:
          loadBalancerIP: 10.30.2.101
        multiCluster: true
    config:
      dbms.cluster.discovery.type: LIST
      dbms.cluster.discovery.endpoints: "10.30.1.101:5000, 10.30.2.101:5000, 10.30.3.101:5000"
      server.discovery.advertised_address: "10.30.2.101:5000"
      server.cluster.advertised_address: "10.30.2.101:6000"
      server.cluster.raft.advertised_address: "10.30.2.101:7000"
      server.bolt.advertised_address: "10.30.2.101:7687"
      server.routing.advertised_address: "10.30.2.101:7688"
  4. In the server-3.values.yaml, add the following settings to the Neo4j configuration:

    server-3.values.yaml
    # Neo4j Configuration (yaml format)
    neo4j:
      name: multicluster
      minimumClusterSize: 3
      acceptLicenseAgreement: "yes"
      edition: enterprise
    volumes:
      data:
        mode: defaultStorageClass
    services:
      neo4j:
        spec:
          loadBalancerIP: 10.30.3.101
        multiCluster: true
    config:
      dbms.cluster.discovery.type: LIST
      dbms.cluster.discovery.endpoints: "10.30.1.101:5000, 10.30.2.101:5000, 10.30.3.101:5000"
      server.discovery.advertised_address: "10.30.3.101:5000"
      server.cluster.advertised_address: "10.30.3.101:6000"
      server.cluster.raft.advertised_address: "10.30.3.101:7000"
      server.bolt.advertised_address: "10.30.3.101:7687"
      server.routing.advertised_address: "10.30.3.101:7688"

Deploy the Neo4j cluster

  1. Switch the context to my-aks-cluster-a-admin using:

    kubectl config use-context my-aks-cluster-a-admin
  2. Install server-1 using the server-1.values.yaml:

    helm install server-1 neo4j/neo4j -f /path/to/server-1.values.yaml
    Example output
    NAME: server-1
    LAST DEPLOYED: Tue Nov  1 14:53:54 2022
    NAMESPACE: neo4j
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    Thank you for installing neo4j.
    
    Your release "server-1" has been installed  in namespace "neo4j".
    
    The neo4j user's password has been set to "my-password".
    
    This release creates a single member of a Neo4j cluster. It will not become ready until it is able to form a working Neo4j cluster by joining other Neo4j servers. To create a working cluster at least 3 servers are required.
    
    Once you have a working Neo4j cluster, you can access the Neo4j browser using the IP address of the multicluster-lb-neo4j service
    eg. http://[SERVICE_IP]:7474
    
    Graphs are everywhere!
  3. Switch the context to my-aks-cluster-b-admin.

    kubectl config use-context my-aks-cluster-b-admin
  4. Install server-2 using the server-2.values.yaml:

    helm install server-2 neo4j/neo4j -f /path/to/server-2.values.yaml
  5. Switch the context to my-aks-cluster-c-admin.

    kubectl config use-context my-aks-cluster-c-admin
  6. Install server-3 using the server-3.values.yaml:

    helm install server-3 neo4j/neo4j -f /path/to/server-3.values.yaml
  7. Switch to each context and check that the pod there is READY and that they have formed a cluster.

    kubectl get pods
    NAME       READY   STATUS    RESTARTS   AGE
    server-1-0   1/1     Running   0          4m51s

Create an Azure application gateway

You create an application gateway to access the Neo4j cluster from outside the AKS clusters.

  1. Log in to the Azure portal.

  2. In the Search resources area, look for Application Gateway.
    The Load balancing | Application Gateway window opens.

  3. Click the Create button.

  4. On the Basics tab, configure the following settings:

    1. From the Resource group dropdown, select my-RG.

    2. Add a name for your application gateway in the Application gateway/name field.

    3. From the Region dropdown, select your region. In this example, it is East US.

    4. Disable the autoscaling.

    5. From the Virtual network dropdown, select my-VNet.

    6. From the Subnet dropdown, select subnet4 | 10.30.4.0/24.

    7. Click Next : Frontends >.

  5. On the Frontends tab, configure the Public IP address:

    1. From the Frontend IP address type, select Public.

    2. In Public IP address, click Add new.

      1. Add a name for it, for example, apg-public.

      2. Click OK.

    3. Click Next : Backends >.

  6. On the Backends tab, add the EXTERNAL-IPs of the load balancers:

    1. Click Add a backend pool.

      1. Add a name for the pool, for example, neo4j-cluster.

      2. In the Target type list, add the EXTERNAL-IPs of the load balancers under Target.

    2. Click Add.

    3. Click Next : Configuration >.

  7. On the Configuration tab, configure the routing rules:

    1. Click Add a routing rule and configure a routing rule for port 7474.

      1. In the Rule name field, add a name for your rule, for example, rule7474.

      2. For Priority, add 1.

      3. On the Listener tab, add a name for the Listener (e.g., listener7474), select Frontend IP to be Public, and add port 7474.

      4. On the Backend targets tab, configure the backend target and settings:

        1. From the Target type dropdown, select the Backend pool to be neo4j-cluster.

        2. For Backend targets, click Add new and config.

          1. In the Backend settings name, type settings7474.

          2. In the Backend port, type 7474.

      5. Click Add.

    2. Click Add a routing rule and configure a routing rule for port 7687.

      1. In the Rule name field, add a name for your rule, for example, rule7687.

      2. For Priority, add 2.

      3. On the Listener tab, add a name for the Listener (e.g., listener7687), select Frontend IP to be Public, and add port 7687.

      4. On the Backend targets tab, configure the backend target and settings:

        1. From the Target type dropdown, select the Backend pool to be neo4j-cluster.

        2. For Backend targets, click Add new and config.

          1. In the Backend settings name, type settings7687.

          2. In the Backend port, type 7687.

      5. Click Add.

    3. Click Next : Tags >.

    4. Click Next : Review + create >, review your configurations, and click Create.

Access the Neo4j cluster

After the application gateway is created and the deployment is complete, you can access the Neo4j cluster via the Neo4j Browser.

  1. Copy the Frontend public IP address and paste it into a browser.

  2. Add port :7474.
    Neo4j Browser opens.

  3. Log in with your credentials (e.g., neo4j/my-password).

  4. Verify that the cluster is up and running using the Cypher command SHOW DATABASES.