How to start a cluster with Docker Compose
Start a 3-node Apache Ignite 3 or GridGain 9 cluster for development using Docker Compose.
Prerequisites
- Docker 20.10 or later
- Docker Compose 2.23.1 or later (ships with Docker Desktop)
- curl and jq for verifying cluster health
- Ports 10300-10302 and 10800-10802 available on your machine
- 12 GB of available RAM for three cluster nodes (4 GB minimum; see the memory note in Step 1)
- GridGain 9 only: A license file from gridgain.com/tryfree (Community Edition or evaluation). Save the downloaded file as
gridgain-license.jsonin your project directory alongsidedocker-compose.yml.
Overview
This guide walks you through starting a 3-node development cluster on your local machine with Docker Compose. By the end, you will have a running cluster that accepts client connections on ports 10800-10802 and exposes a REST management API on ports 10300-10302.
Both Apache Ignite 3 and GridGain 9 share the same distributed architecture and management interfaces. The Docker images, configuration paths, and license requirements differ between the two products, but the cluster lifecycle is the same: start nodes, initialize them into a cluster, then connect.
You have two tools for managing the cluster once the containers are running:
- REST API (port 10300) accepts HTTP requests for cluster initialization, health checks, and configuration. It is available as soon as a node starts, even before the cluster is initialized. Use this when you want scriptable, automatable management.
- CLI tool is an interactive command-line shell that communicates with the cluster through the REST API. It is bundled inside the server image, so you access it via
docker execon any running node. Use it for interactive sessions, SQL queries, or one-off administration. For a deeper walkthrough, see How to Work with the Ignite CLI.
Select your product version in the tabs below. Each step shows both management approaches where they differ.
Create a Docker Compose File
Create a directory for your project and add a file named docker-compose.yml with the following content.
- Apache Ignite 3
- GridGain 9
name: ignite3
x-ignite-def: &ignite-def
image: apacheignite/ignite:3.1.0
environment:
JVM_MAX_MEM: "4g"
JVM_MIN_MEM: "4g"
configs:
- source: node_config
target: /opt/ignite/etc/ignite-config.conf
services:
node1:
<<: *ignite-def
container_name: ignite3-node1
command: --node-name node1
ports:
- "10300:10300"
- "10800:10800"
node2:
<<: *ignite-def
container_name: ignite3-node2
command: --node-name node2
ports:
- "10301:10300"
- "10801:10800"
depends_on:
- node1
node3:
<<: *ignite-def
container_name: ignite3-node3
command: --node-name node3
ports:
- "10302:10300"
- "10802:10800"
depends_on:
- node1
- node2
configs:
node_config:
content: |
ignite {
network {
port: 3344
nodeFinder.netClusterNodes = ["node1:3344", "node2:3344", "node3:3344"]
}
}
The YAML anchor (x-ignite-def) keeps the node definitions consistent. Each node exposes two ports: 10300 for the REST management API and 10800 for client connections (JDBC, ODBC, and thin client drivers). The Ignite CLI is bundled inside the server image, so you access it via docker exec on any running node.
Port 3344 handles internal cluster communication between nodes. Docker's internal network routes this traffic, so you don't need to expose it to the host.
Ensure your gridgain-license.json file (from the prerequisites) is in the same directory where you create docker-compose.yml.
name: gridgain9
x-gridgain-def: &gridgain-def
image: gridgain/gridgain9:9.1.8
environment:
JVM_MAX_MEM: "4g"
JVM_MIN_MEM: "4g"
configs:
- source: node_config
target: /opt/gridgain/etc/gridgain-config.conf
services:
node1:
<<: *gridgain-def
container_name: gridgain9-node1
command: --node-name node1
ports:
- "10300:10300"
- "10800:10800"
node2:
<<: *gridgain-def
container_name: gridgain9-node2
command: --node-name node2
ports:
- "10301:10300"
- "10801:10800"
depends_on:
- node1
node3:
<<: *gridgain-def
container_name: gridgain9-node3
command: --node-name node3
ports:
- "10302:10300"
- "10802:10800"
depends_on:
- node1
- node2
configs:
node_config:
content: |
ignite {
network {
port: 3344
nodeFinder.netClusterNodes = ["node1:3344", "node2:3344", "node3:3344"]
}
}
The structure mirrors the Apache Ignite 3 compose file with two key differences: the image names use gridgain/gridgain9, and the node configuration mounts to /opt/gridgain/etc/ instead of /opt/ignite/etc/. The GridGain CLI is bundled inside the server image at /opt/gridgain9cli/bin/gridgain9.
Port 3344 handles internal cluster communication between nodes. Docker's internal network routes this traffic, so you don't need to expose it to the host.
Reduce JVM_MAX_MEM and JVM_MIN_MEM to 1g if your machine has less than 16 GB of RAM. Each node will use approximately 1 GB instead of 4 GB. Performance will be adequate for development and tutorial workloads.
Start the Cluster
This command works for both Apache Ignite 3 and GridGain 9:
docker compose up -d
- Apache Ignite 3
- GridGain 9
Expected output:
[+] Running 4/4
✔ Network ignite3_default Created
✔ Container ignite3-node1 Started
✔ Container ignite3-node2 Started
✔ Container ignite3-node3 Started
Expected output:
[+] Running 4/4
✔ Network gridgain9_default Created
✔ Container gridgain9-node1 Started
✔ Container gridgain9-node2 Started
✔ Container gridgain9-node3 Started
The nodes need a few seconds to discover each other over port 3344 and form a physical topology. Verify all three containers are running:
docker compose ps --format "table {{.Name}}\t{{.Image}}\t{{.Status}}"
- Apache Ignite 3
- GridGain 9
Expected output:
NAME IMAGE STATUS
ignite3-node1 apacheignite/ignite:3.1.0 Up 30 seconds
ignite3-node2 apacheignite/ignite:3.1.0 Up 29 seconds
ignite3-node3 apacheignite/ignite:3.1.0 Up 28 seconds
Expected output:
NAME IMAGE STATUS
gridgain9-node1 gridgain/gridgain9:9.1.8 Up 30 seconds
gridgain9-node2 gridgain/gridgain9:9.1.8 Up 29 seconds
gridgain9-node3 gridgain/gridgain9:9.1.8 Up 28 seconds
Checkpoint: All three containers show Up status. If any container shows Restarting or Exited, see Troubleshooting.
Initialize the Cluster
At this point, the nodes are running and can see each other, but they are not yet a cluster. Initialization is a one-time step that elects a leader, designates which nodes store cluster metadata, and opens client connection ports (10800). Until you initialize, the REST API on port 10300 is the only way to interact with the nodes.
Choose your preferred management tool below. Both accomplish the same result.
- REST API
- CLI
Send the initialization request to any node's REST endpoint. The REST API is available on all three nodes (ports 10300, 10301, 10302), but you only need to send the init request once.
- Apache Ignite 3
- GridGain 9
curl -X POST http://localhost:10300/management/v1/cluster/init \
-H "Content-Type: application/json" \
-d '{
"metaStorageNodes": ["node1", "node2", "node3"],
"cmgNodes": ["node1", "node2", "node3"],
"clusterName": "my-cluster"
}'
A successful initialization returns HTTP 200 with an empty response body.
GridGain 9 requires the license content in the init request. Load the license file into a shell variable first. jq -Rs reads the file and encodes it as a JSON string with proper escaping:
LICENSE=$(jq -Rs . gridgain-license.json)
Initialize the cluster with the license:
curl -X POST http://localhost:10300/management/v1/cluster/init \
-H "Content-Type: application/json" \
-d '{"metaStorageNodes":["node1","node2","node3"],"cmgNodes":["node1","node2","node3"],"clusterName":"my-cluster","license":'"$LICENSE"'}'
A successful initialization returns HTTP 200 with an empty response body.
Open the CLI inside a running node with docker exec. The CLI is bundled in the server image.
- Apache Ignite 3
- GridGain 9
docker exec -it ignite3-node1 /opt/ignite3cli/bin/ignite3
At the CLI prompt, connect to the local node and initialize:
connect http://localhost:10300
cluster init --name=my-cluster --metastorage-group=node1,node2,node3
Expected output:
Connected to http://localhost:10300
Cluster was initialized successfully
Type exit; to leave the CLI.
First, copy the license file into the container:
docker cp gridgain-license.json gridgain9-node1:/opt/gridgain9cli/license.json
Then open the CLI:
docker exec -it gridgain9-node1 /opt/gridgain9cli/bin/gridgain9
At the CLI prompt, connect to the local node and initialize with the license file:
connect http://localhost:10300
cluster init --name=my-cluster --metastorage-group=node1,node2,node3 --license=/opt/gridgain9cli/license.json
Expected output:
Connected to http://localhost:10300
Cluster was initialized successfully
Type exit; to leave the CLI.
Allow a few seconds for the nodes to elect a leader and synchronize metadata before verifying.
Checkpoint: Initialization completes without errors. If the command hangs or returns a connection error, wait 30-60 seconds for the nodes to finish starting, then retry.
Verify Cluster Health
Once the cluster is initialized, confirm that all three nodes joined successfully. This verification works the same way for both Apache Ignite 3 and GridGain 9.
- REST API
- CLI
curl -s http://localhost:10300/management/v1/cluster/state | jq .
Expected output:
- Apache Ignite 3
- GridGain 9
{
"cmgNodes": ["node1", "node2", "node3"],
"msNodes": ["node1", "node2", "node3"],
"igniteVersion": "3.1.0",
"clusterTag": {
"clusterName": "my-cluster",
"clusterId": "..."
}
}
{
"cmgNodes": ["node1", "node2", "node3"],
"msNodes": ["node1", "node2", "node3"],
"igniteVersion": "9.1.8",
"clusterTag": {
"clusterName": "my-cluster",
"clusterId": "..."
}
}
Both cmgNodes (cluster management group) and msNodes (metastorage nodes) should list all three nodes. The igniteVersion field reflects the product version.
Checkpoint: Both cmgNodes and msNodes list all three nodes, confirming the cluster is healthy and accepting client connections on port 10800.
- Apache Ignite 3
- GridGain 9
docker exec -it ignite3-node1 /opt/ignite3cli/bin/ignite3
docker exec -it gridgain9-node1 /opt/gridgain9cli/bin/gridgain9
At the CLI prompt:
connect http://localhost:10300
cluster status
Expected output:
Connected to http://localhost:10300
[name: my-cluster, nodes: 3, status: active, cmgNodes: [node1, node2, node3], msNodes: [node1, node2, node3]]
For a detailed node list, use:
cluster topology physical
This lists all nodes with their names, addresses, and IDs.
Type exit; to leave the CLI.
Checkpoint: The cluster status command shows 3 nodes in active status. All nodes are in the CMG and MetaStorage groups.
Stopping and Restarting
All Docker Compose lifecycle commands work identically for both Apache Ignite 3 and GridGain 9.
Stop the cluster (preserves data):
docker compose stop
This stops the containers without removing them. Data, cluster state, and initialization all persist.
Restart a stopped cluster:
docker compose up -d
The nodes rejoin the existing cluster automatically. You do not need to re-initialize. Client connections on port 10800 become available once the nodes finish starting (typically 15-30 seconds). This same command also works after docker compose down to create a fresh cluster (which will require re-initialization).
Remove the cluster (destroys data):
docker compose down
This removes all containers and the default network, destroying all data. The next docker compose up -d starts a fresh cluster that requires re-initialization.
Remove the cluster and all volumes:
docker compose down -v
This also removes named volumes for a completely clean state.
Troubleshooting
These issues apply to both Apache Ignite 3 and GridGain 9 unless noted otherwise. Another process is using one of the required ports. Identify it: Stop the conflicting process, or change the host port mapping in Adjust all subsequent commands to use the new port number. The The nodes are not ready yet. Check that all containers are running: If a container shows Wait for the REST API to become available (30-60 seconds after startup): When this returns a JSON response, the node is ready for initialization. The cluster was initialized before all nodes discovered each other. In a development environment, the safest fix is to start over: Wait 30-60 seconds for all nodes to discover each other, then re-initialize. An application connecting to Client ports open only after cluster initialization. Verify the cluster is initialized: If this returns GridGain 9 only. The REST API returns HTTP 400 with a message about a missing or invalid license. Verify that Verify the file contains valid JSON: The GridGain 9 only. The CLI returns an error about a missing license when running Verify the license file was copied into the container: If the file is missing, copy it again: Use the GridGain 9 only. Cluster initialization or a join request fails with: This error means your license type does not match your GridGain 9 build type. GridGain 9 has two release types: Check which Docker image tag you are using in If you see a version newer than 9.1.8 (such as 9.1.20), you are running a private build that requires a private (paid) license. To fix this, either: The same mismatch applies to Maven dependencies. If your Port conflict on startup
docker compose up -d fails with Bind for 0.0.0.0:10300 failed: port is already allocated.docker-compose.yml. For example, map to port 10400 instead:Initialization timeout
curl command to /management/v1/cluster/init hangs or returns connection refused.Restarting or Exited, check its logs:Fewer than 3 nodes in cluster state
/management/v1/cluster/state shows fewer than 3 nodes in cmgNodes or msNodes.Client connection refused on port 10800
localhost:10800 gets Connection refused after the containers are running.null or an error, the cluster has not been initialized. Complete the Initialize the Cluster step above.GridGain 9: License error during REST API initialization
gridgain-license.json exists in the same directory as docker-compose.yml:license field in the curl command must be a JSON-encoded string of the file contents, not the filename. Use LICENSE=$(jq -Rs . gridgain-license.json) to load the license into a variable as shown in the initialization step.GridGain 9: License error during CLI initialization
cluster init.--license=/opt/gridgain9cli/license.json flag with the cluster init command.GridGain 9: "License for a private version is required"
docker-compose.yml:
gridgain/gridgain9:9.1.8 in your docker-compose.yml, then restart the cluster with a clean state:
pom.xml references a version newer than 9.1.8 (e.g., 9.1.20), Maven will fail to resolve it from the GridGain Nexus repository unless you have private repository access.
Your cluster is now accepting client connections on ports 10800-10802. You can connect with any Ignite thin client driver, JDBC (jdbc:ignite:thin://localhost:10800), or ODBC.
Related
-
How to Manage Cluster Lifecycle with the REST API - Monitor startup, initialize, and verify cluster health using REST endpoints.
-
Start Your Local Ignite 3 Development Cluster - Tutorial that walks through this setup with deeper context, loads the Music Store dataset, and introduces cluster concepts.
-
How to Work with the Ignite CLI - Interactive SQL, cluster inspection, output formatting, and profiles.