Deploy a Neo4j cluster in a Docker container
Neo4j supports clustering in a containerized environment without an orchestration tool. This tutorial walks through setting this up locally for testing purposes. For production deployment across multiple servers, see Deploy a Neo4j cluster on multiple Docker hosts.
The examples on this page make use of both command expansion and DNS discovery method. For more information, see: |
Deploy a Neo4j cluster using Docker Compose
You can deploy a Neo4j cluster using Docker Compose.
Docker Compose is a management tool for Docker containers.
You use a YAML file to define the infrastructure of all your cluster servers in one file.
Then, by running the single command docker-compose up
, you create and start all the members without the need to invoke each of them individually.
For more information about Docker Compose, see the Docker Compose official documentation.
Prerequisites
-
Verify that you have installed Docker Compose. For more information, see the Install Docker Compose official documentation.
Procedure
-
Create a configuration file neo4j.conf which will be shared across cluster members and make it readable and writable for the user (eg.,
chmod 640 neo4j.conf
)# Setting that specifies how much memory Neo4j is allowed to use for the page cache. server.memory.pagecache.size=100M # Setting that specifies the initial JVM heap size. server.memory.heap.initial_size=100M # The behavior of the discovery service is determined by the parameters `dbms.cluster.discovery.resolver_type`, `dbms.cluster.discovery.v2.endpoints`, and `dbms.cluster.discovery.version`. # The DNS strategy fetches the IP addresses of the cluster members using the DNS A records. dbms.cluster.discovery.resolver_type=DNS # The value of `dbms.cluster.discovery.version` must be set to `V2_ONLY` if you want to use the discovery service v2. # The discovery service v2 utilizes the port `6000`. dbms.cluster.discovery.version=V2_ONLY # The value of `dbms.cluster.discovery.v2.endpoints` should be set to a single domain name and the port of the discovery service. # The domain name returns an A record for every server in the cluster when a DNS lookup is performed. # Each A record returned by DNS should contain the IP address of the server in the cluster. # The configured server uses all the IP addresses from the A records to join or form a cluster. # The discovery port must be the same on all servers when using this configuration. dbms.cluster.discovery.v2.endpoints=neo4j-network:6000 # Address (the public hostname/IP address of the machine) # and port setting that specifies where this instance advertises for discovery protocol messages from other members of the cluster. server.cluster.advertised_address=$(hostname -i) # Address (the public hostname/IP address of the machine) # and port setting that specifies where this instance advertises for Raft messages within the cluster. server.cluster.raft.advertised_address=$(hostname) # Enable server-side routing dbms.routing.enabled=true # Use server-side routing for neo4j:// protocol connections. dbms.routing.default_router=SERVER # The advertised address for the intra-cluster routing connector. server.routing.advertised_address=$(hostname) # Automatically enable servers, rather than needing to explicitly do so for Free servers initial.dbms.automatically_enable_free_servers=true
# Setting that specifies how much memory Neo4j is allowed to use for the page cache. server.memory.pagecache.size=100M # Setting that specifies the initial JVM heap size. server.memory.heap.initial_size=100M # The behavior of the initial discovery is determined by the parameters `dbms.cluster.discovery.resolver_type` and `dbms.cluster.discovery.endpoints`. # The DNS strategy fetches the IP addresses of the cluster members using the DNS A records. dbms.cluster.discovery.resolver_type=DNS # The value of `dbms.cluster.discovery.endpoints` should be set to a single domain name and the port of the discovery service. # The domain name returns an A record for every server in the cluster when a DNS lookup is performed. # Each A record returned by DNS should contain the IP address of the server in the cluster. # The configured server uses all the IP addresses from the A records to join or form a cluster. # The discovery port must be the same on all servers when using this configuration. dbms.cluster.discovery.endpoints=neo4j-network:5000 # Address (the public hostname/IP address of the machine) # and port setting that specifies where this instance advertises for discovery protocol messages from other members of the cluster. server.discovery.advertised_address=$(hostname -i) # Address (the public hostname/IP address of the machine) # and port setting that specifies where this instance advertises for Raft messages within the cluster. server.cluster.raft.advertised_address=$(hostname) # Address (the public hostname/IP address of the machine) # and port setting that specifies where this instance advertises for requests for transactions in the transaction-shipping catch-up protocol. server.cluster.advertised_address=$(hostname) # Enable server-side routing dbms.routing.enabled=true # Use server-side routing for neo4j:// protocol connections. dbms.routing.default_router=SERVER # The advertised address for the intra-cluster routing connector. server.routing.advertised_address=$(hostname)
-
Prepare your docker-compose.yml file using the following example. For more information, see the Docker Compose official Service configuration reference.
Example 1. Example docker-compose.yml fileversion: '3.8' # Custom top-level network networks: neo4j-internal: services: server1: # Docker image to be used image: ${NEO4J_DOCKER_IMAGE} # Hostname hostname: server1 # Service-level network, which specifies the networks, from the list of the top-level networks (in this case only neo4j-internal), that the server will connect to. # Adds a network alias (used in neo4j.conf when configuring the discovery members) networks: neo4j-internal: aliases: - neo4j-network # The ports that will be accessible from outside the container - HTTP (7474) and Bolt (7687). ports: - "7474:7474" - "7687:7687" # Uncomment the volumes to be mounted to make them accessible from outside the container. volumes: - ./neo4j.conf:/conf/neo4j.conf # This is the main configuration file. - ./data/server1:/data - ./logs/server1:/logs - ./conf/server1:/conf - ./import/server1:/import #- ./metrics/server1:/metrics #- ./licenses/server1:/licenses #- ./ssl/server1:/ssl # Passes the following environment variables to the container environment: - NEO4J_ACCEPT_LICENSE_AGREEMENT - NEO4J_AUTH - EXTENDED_CONF - NEO4J_EDITION - NEO4J_initial_server_mode__constraint=PRIMARY # Simple check testing whether the port 7474 is opened. # If so, the instance running inside the container is considered as "healthy". # This status can be checked using the "docker ps" command. healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"] # Set up the user user: ${USER_ID}:${GROUP_ID} server2: image: ${NEO4J_DOCKER_IMAGE} hostname: server2 networks: neo4j-internal: aliases: - neo4j-network ports: - "7475:7474" - "7688:7687" volumes: - ./neo4j.conf:/conf/neo4j.conf - ./data/server2:/data - ./logs/server2:/logs - ./conf/server2:/conf - ./import/server2:/import #- ./metrics/server2:/metrics #- ./licenses/server2:/licenses #- ./ssl/server2:/ssl environment: - NEO4J_ACCEPT_LICENSE_AGREEMENT - NEO4J_AUTH - EXTENDED_CONF - NEO4J_EDITION - NEO4J_initial_server_mode__constraint=PRIMARY healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"] user: ${USER_ID}:${GROUP_ID} server3: image: ${NEO4J_DOCKER_IMAGE} hostname: server3 networks: neo4j-internal: aliases: - neo4j-network ports: - "7476:7474" - "7689:7687" volumes: - ./neo4j.conf:/conf/neo4j.conf - ./data/server3:/data - ./logs/server3:/logs - ./conf/server3:/conf - ./import/server3:/import #- ./metrics/server3:/metrics #- ./licenses/server3:/licenses #- ./ssl/server3:/ssl environment: - NEO4J_ACCEPT_LICENSE_AGREEMENT - NEO4J_AUTH - EXTENDED_CONF - NEO4J_EDITION - NEO4J_initial_server_mode__constraint=PRIMARY healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"] user: ${USER_ID}:${GROUP_ID} server4: image: ${NEO4J_DOCKER_IMAGE} hostname: server4 networks: neo4j-internal: aliases: - neo4j-network ports: - "7477:7474" - "7690:7687" volumes: - ./neo4j.conf:/conf/neo4j.conf - ./data/server4:/data - ./logs/server4:/logs - ./conf/server4:/conf - ./import/server4:/import #- ./metrics/server4:/metrics #- ./licenses/server4:/licenses #- ./ssl/server4:/ssl environment: - NEO4J_ACCEPT_LICENSE_AGREEMENT - NEO4J_AUTH - EXTENDED_CONF - NEO4J_EDITION - NEO4J_initial_server_mode__constraint=SECONDARY healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"] user: ${USER_ID}:${GROUP_ID}
-
Set up the environment variables:
-
export USER_ID="$(id -u)"
-
export GROUP_ID="$(id -g)"
-
export NEO4J_DOCKER_IMAGE=neo4j:enterprise
-
export NEO4J_EDITION=docker_compose
-
export EXTENDED_CONF=yes
-
export NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
-
export NEO4J_AUTH=neo4j/your_password
-
-
Pre-build the folder structure by running the following command:
mkdir -p conf/{server1,server2,server3,server4} data/{server1,server2,server3,server4} import/{server1,server2,server3,server4} logs/{server1,server2,server3,server4}
-
Deploy your Neo4j cluster by running
docker-compose up
from your project folder. -
The instance will be available at the following addresses:
-
Neo4j instance server1 will be available at http://localhost:7474.
-
Neo4j instance server2 will be available at http://localhost:7475.
-
Neo4j instance server3 will be available at http://localhost:7476.
-
Neo4j instance server4 will be available at http://localhost:7477.
-
-
Authenticate with the default
neo4j/your_password
credentials. -
Check the status of the cluster by running the following in Neo4j Browser:
SHOW SERVERS
Example output:
Deploy a Neo4j Cluster using environment variables
You can set up containers in a cluster to talk to each other using environment variables.
Each container must have a network route to each of the others, the NEO4J_initial_dbms_default__primaries__count
, NEO4J_initial_dbms_default__secondaries__count
, and NEO4J_dbms_cluster_discovery_endpoints
environment variables must be set for all servers.
Cluster environment variables
The following environment variables are specific to the Neo4j cluster, and are available in the Neo4j Enterprise Edition:
-
NEO4J_initial_server_mode__constraint
: the database mode, defaults toNONE
, can be set toPRIMARY
orSECONDARY
. -
NEO4J_dbms_cluster_discovery_endpoints
: a comma-separated list of endpoints, which a server should contact to discover other cluster servers. Deprecated in 5.23 -
NEO4J_dbms_cluster_discovery_v2_endpoints
: a comma-separated list of endpoints, which a server should contact to discover other cluster servers. Introduced in 5.23 -
NEO4J_server_discovery_advertised_address
: hostname/IP address and port to advertise for member discovery management communication. Deprecated in 5.23 -
NEO4J_server.cluster.advertised_address
: hostname/IP address and port to advertise for transaction handling and v2 discovery. -
NEO4J_server.cluster.raft.advertised_address
: hostname/IP address and port to advertise for cluster communication. -
NEO4J_dbms_cluster_discovery_version
: the discovery service version to use, defaults toV1_ONLY
, can be set toV1_OVER_V2
,V2_OVER_V1
, orV2_ONLY
. Introduced in 5.23
See Settings reference for more details of Neo4j cluster settings.
Set up a Neo4j Cluster on a single Docker host
Within a single Docker host, you can use the default ports for HTTP, HTTPS, and Bolt. For each container, these ports are mapped to a different set of ports on the Docker host.
Example of a docker run
command for deploying a cluster with three servers:
docker network create --driver=bridge neo4j-cluster
docker run --name=server1 --detach --network=neo4j-cluster \
--publish=7474:7474 --publish=7473:7473 --publish=7687:7687 \
--hostname=server1 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_version=V2_ONLY \
--env NEO4J_dbms_cluster_discovery_v2_endpoints=server1:6000,server2:6000,server3:6000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:7687 \
--env NEO4J_server_http_advertised__address=localhost:7474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
docker run --name=server2 --detach --network=neo4j-cluster \
--publish=8474:7474 --publish=8473:7473 --publish=8687:7687 \
--hostname=server2 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_version=V2_ONLY \
--env NEO4J_dbms_cluster_discovery_v2_endpoints=server1:6000,server2:6000,server3:6000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:8687 \
--env NEO4J_server_http_advertised__address=localhost:8474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
docker run --name=server3 --detach --network=neo4j-cluster \
--publish=9474:7474 --publish=9473:7473 --publish=9687:7687 \
--hostname=server3 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_version=V2_ONLY \
--env NEO4J_dbms_cluster_discovery_v2_endpoints=server1:6000,server2:6000,server3:6000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:9687 \
--env NEO4J_server_http_advertised__address=localhost:9474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
docker network create --driver=bridge neo4j-cluster
docker run --name=server1 --detach --network=neo4j-cluster \
--publish=7474:7474 --publish=7473:7473 --publish=7687:7687 \
--hostname=server1 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_endpoints=server1:5000,server2:5000,server3:5000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:7687 \
--env NEO4J_server_http_advertised__address=localhost:7474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
docker run --name=server2 --detach --network=neo4j-cluster \
--publish=8474:7474 --publish=8473:7473 --publish=8687:7687 \
--hostname=server2 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_endpoints=server1:5000,server2:5000,server3:5000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:8687 \
--env NEO4J_server_http_advertised__address=localhost:8474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
docker run --name=server3 --detach --network=neo4j-cluster \
--publish=9474:7474 --publish=9473:7473 --publish=9687:7687 \
--hostname=server3 \
--env NEO4J_initial_server_mode__constraint=PRIMARY \
--env NEO4J_dbms_cluster_discovery_endpoints=server1:5000,server2:5000,server3:5000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:9687 \
--env NEO4J_server_http_advertised__address=localhost:9474 \
--env NEO4J_AUTH=neo4j/your_password \
neo4j:5.26.0-enterprise
Additional servers can be added to the cluster in an ad-hoc fashion.
Example of a docker run
command for adding a fourth server with a role SECONDARY
to the cluster:
docker run --name=read-server4 --detach --network=neo4j-cluster \
--publish=10474:7474 --publish=10473:7473 --publish=10687:7687 \
--hostname=read-server4 \
--env NEO4J_initial_server_mode__constraint=SECONDARY \
--env NEO4J_dbms_cluster_discovery_version=V2_ONLY \
--env NEO4J_dbms_cluster_discovery_v2_endpoints=server1:6000,server2:6000,server3:6000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:10687 \
--env NEO4J_server_http_advertised__address=localhost:10474 \
neo4j:5.26.0-enterprise
docker run --name=read-server4 --detach --network=neo4j-cluster \
--publish=10474:7474 --publish=10473:7473 --publish=10687:7687 \
--hostname=read-server4 \
--env NEO4J_initial_server_mode__constraint=SECONDARY \
--env NEO4J_dbms_cluster_discovery_endpoints=server1:5000,server2:5000,server3:5000 \
--env NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
--env NEO4J_server_bolt_advertised__address=localhost:10687 \
--env NEO4J_server_http_advertised__address=localhost:10474 \
neo4j:5.26.0-enterprise