Deploy a single Neo4j cluster across AKS clusters

With the Neo4j Helm charts, you can deploy a Neo4j cluster on multiple AKS clusters using load balancers and Application Gateway.

The following diagram is a schematic representation of a Neo4j cluster setup on multiple 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 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

  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 the 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
    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

Configure the load balancer values.yaml file

You configure the load balancer Helm chart to be used in a multi-zone /region Neo4j cluster scenario.

In the load balancer values.yaml file, set the parameter multiCluster: true and add an annotation, e.g., service.beta.kubernetes.io/azure-load-balancer-internal: "true".

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.

An example of what to configure in the load balancer YAML file
  neo4j:
    name: "neo4j-cluster"
    edition: "enterprise"

  # Annotations for the external service
  annotations:
     service.beta.kubernetes.io/azure-load-balancer-internal: "true"

  #this flag allows you to open internal neo4j ports necessary in multi-zone /region neo4j cluster scenario
  multiCluster: true

Install a load balancer on each AKS cluster

You install a load balancer on each AKS cluster to be used by the Neo4j instance running there.

You must have owner’s permissions in the resource group not to face auth issues while deploying the load balancers.

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

    kubectl config use-context my-aks-cluster-a-admin
    Example output
    Switched to context "my-aks-cluster-a-admin".
  2. Install the load balancer using the YAML file you created.

    helm install lb1 neo4j/neo4j-cluster-loadbalancer -f /path/to/lb-values.yaml
    Example output
    NAME: lb1
    LAST DEPLOYED: Thu Sep  8 20:27:45 2022
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    Thank you for installing neo4j-cluster-loadbalancer.
    
    Your release "lb1" has been installed in namespace "default".
    
    To view the status of your Load Balancer service you can use
      $ kubectl get service lb-neo4j
    
    Once your Load Balancer has an External-IP assigned you can connect to your Neo4j cluster using "neo4j://:7687". Try:
    
      $ cypher-shell -a "neo4j://:7687"
    
    Graphs are everywhere!
  3. Repeat steps 1 and 2 to create lb2 for my-aks-cluster-b-admin and lb3 for my-aks-cluster-c-admin.

Create a values.yaml file for each cluster member

Create a custom YAML file for each Neo4j cluster member, for example, core-1.values.yaml, core-2.values.yaml, core-3.values.yaml. Add the address based on the load balancer EXTERNAL-IP you created for each member. For more information on how to create a custom YAML file, see Create Helm deployment values files.

  1. Get the IPs of the load balancers.

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

      kubectl config use-context my-aks-cluster-a-admin
    2. Get the EXTERNAL-IP. Please make a note of it.

      kubectl get svc
      Example output
      NAME         TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)                                        AGE
      kubernetes   ClusterIP      10.0.0.1                443/TCP                                        5h47m
      lb-neo4j     LoadBalancer   10.0.160.168   20.62.182.59   7474:30430/TCP,7473:30683/TCP,7687:32214/TCP   12m
    3. Switch to the context of the second AKS cluster my-aks-cluster-b-admin and get the EXTERNAL-IP of lb2.

    4. Switch to the context of the third AKS cluster my-aks-cluster-c-admin and get the EXTERNAL-IP of lb3.

  2. In the core-1.values.yaml, add the following settings to the Neo4j configuration:

    # Neo4j Configuration (yaml format)
    config:
      dbms.mode: "CORE"
      dbms.config.strict_validation: "false"
      causal_clustering.middleware.akka.allow_any_core_to_bootstrap: "true"
      causal_clustering.discovery_type: "LIST"
      causal_clustering.initial_discovery_members: "<lb1-EXTERNAL-IP>:5000,<lb2-EXTERNAL-IP>:5000,<lb3-EXTERNAL-IP>:5000"
      causal_clustering.discovery_advertised_address: "<lb1-EXTERNAL-IP>:5000"
      causal_clustering.raft_advertised_address: "<lb1-EXTERNAL-IP>:7000"
      causal_clustering.transaction_advertised_address: "<lb1-EXTERNAL-IP>:6000"
      dbms.connector.bolt.advertised_address: "<lb1-EXTERNAL-IP>:7687"
      dbms.routing.advertised_address: "<lb1-EXTERNAL-IP>:7688"
  3. In the core-2.values.yaml, add the following settings to the Neo4j configuration:

    # Neo4j Configuration (yaml format)
    config:
      dbms.mode: "CORE"
      dbms.config.strict_validation: "false"
      causal_clustering.middleware.akka.allow_any_core_to_bootstrap: "true"
      causal_clustering.discovery_type: "LIST"
      causal_clustering.initial_discovery_members: "<lb1-EXTERNAL-IP>:5000,<lb2-EXTERNAL-IP>:5000,<lb3-EXTERNAL-IP>:5000"
      causal_clustering.discovery_advertised_address: "<lb2-EXTERNAL-IP>:5000"
      causal_clustering.raft_advertised_address: "<lb2-EXTERNAL-IP>:7000"
      causal_clustering.transaction_advertised_address: "<lb2-EXTERNAL-IP>:6000"
      dbms.connector.bolt.advertised_address: "<lb2-EXTERNAL-IP>:7687"
      dbms.routing.advertised_address: "<lb2-EXTERNAL-IP>:7688"
  4. In the core-3.values.yaml, add the following settings to the Neo4j configuration:

    # Neo4j Configuration (yaml format)
    config:
      dbms.mode: "CORE"
      dbms.config.strict_validation: "false"
      causal_clustering.middleware.akka.allow_any_core_to_bootstrap: "true"
      causal_clustering.discovery_type: "LIST"
      causal_clustering.initial_discovery_members: "<lb1-EXTERNAL-IP>:5000,<lb2-EXTERNAL-IP>:5000,<lb3-EXTERNAL-IP>:5000"
      causal_clustering.discovery_advertised_address: "<lb3-EXTERNAL-IP>:5000"
      causal_clustering.raft_advertised_address: "<lb3-EXTERNAL-IP>:7000"
      causal_clustering.transaction_advertised_address: "<lb3-EXTERNAL-IP>:6000"
      dbms.connector.bolt.advertised_address: "<lb3-EXTERNAL-IP>:7687"
      dbms.routing.advertised_address: "<lb3-EXTERNAL-IP>:7688"

Deploy the Neo4j cluster

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

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

    helm install core-1 neo4j/neo4j-cluster-core -f /path/to/core-1.values.yaml
    Example output
    NAME: core-1
    LAST DEPLOYED: Thu Sep  8 21:29:30 2022
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    Thank you for installing neo4j-cluster-core.
    
    Your release "core-1" has been installed .
    
    The neo4j user's password has been set to "my-password".
    
    This release creates a single Neo4j Core instance. It  will not become ready until it is able to form a working Neo4j cluster by joining other Neo4j Core instances. To create a working cluster requires at least 3 Core instances.
    
    Once you have a working Neo4j cluster you must install at least one Neo4j Service before you can connect applications to Neo4j. Available Neo4j services are:
      neo4j-headless-service - for connecting applications running inside Kubernetes to Neo4j
      neo4j-loadbalancer - for connecting applications running outside Kubernetes to Neo4j
    
    Graphs are everywhere!
  3. Switch the context to my-aks-cluster-b-admin.

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

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

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

    helm install core-3 neo4j/neo4j-cluster-core -f /path/to/core-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
    core-1-0   1/1     Running   0          4m51s

Create an 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.