This guide walks you through setting up a 3-node MySQL InnoDB Cluster using Docker Compose, complete with high availability and load balancing options using either MySQL Router or ProxySQL.
- 3 MySQL Nodes: Primary cluster nodes for high availability
- Network: All nodes communicate via
mysql-network - Proxy Options: Choose between MySQL Router or ProxySQL for load balancing
- Admin User:
clusteradminwith full privileges for cluster management
- Docker and Docker Compose installed
- Basic understanding of MySQL and clustering concepts
- Network connectivity between all nodes
Your docker-compose.yml should include 3 MySQL nodes, all connected to the mysql-network.
Each MySQL node runs the following initialization script:
CREATE USER 'clusteradmin'@'%' IDENTIFIED BY 'cladmin';
GRANT ALL privileges ON *.* TO 'clusteradmin'@'%' WITH GRANT OPTION;
RESET MASTER;This script:
- Creates the cluster administrator user
- Grants full privileges needed for cluster operations
- Resets the binary log to ensure clean cluster initialization
docker-compose up -dWait for all 3 MySQL containers to be fully initialized and running.
Connect to the first node using MySQL Shell:
docker exec -it <mysql-node-1> mysqlshFor each of the 3 nodes, perform the following steps:
dba.checkInstanceConfiguration('clusteradmin@<node-hostname>:3306')This command verifies that the MySQL instance is properly configured for InnoDB Cluster.
dba.configureInstance('clusteradmin@<node-hostname>:3306')This automatically configures the instance with the required settings for clustering. You may need to restart the MySQL instance if prompted.
Repeat for all 3 nodes:
clusteradmin@mysql-node-1:3306clusteradmin@mysql-node-2:3306clusteradmin@mysql-node-3:3306
On the first node, create the cluster:
var cluster = dba.createCluster('myCluster')Add the remaining nodes to the cluster:
cluster.addInstance('clusteradmin@mysql-node-2:3306')
cluster.addInstance('clusteradmin@mysql-node-3:3306')cluster.status()This should show all 3 nodes as part of the cluster with one PRIMARY and two SECONDARY nodes.
By default, InnoDB Cluster operates in single-primary mode. You can optionally configure it for multi-primary mode where all nodes accept writes:
cluster.switchToMultiPrimaryMode()Alternatively, create the cluster directly in multi-primary mode:
var cluster = dba.createCluster('myCluster', {multiPrimary: true})cluster.switchToSinglePrimaryMode()cluster.status()The output will show "topologyMode": "Multi-Primary" or "topologyMode": "Single-Primary"
Important Considerations for Multi-Primary Mode:
- All nodes can accept read and write operations
- Requires careful application design to avoid conflicts
- May have different performance characteristics
- Ensure your application can handle potential write conflicts
If all nodes go down and the cluster becomes unavailable:
dba.rebootClusterFromCompleteOutage('myCluster')This command:
- Analyzes the cluster state
- Determines which node has the most recent data
- Restarts the cluster from that node
- Rejoins other nodes automatically
If a single node fails and needs to rejoin:
cluster.rejoinInstance('clusteradmin@<failed-node>:3306')Choose between MySQL Router or ProxySQL for load balancing and high availability.
- Navigate to the
mysql-routerfolder - Build and start the router container using the provided Dockerfile:
cd mysql-router
docker build -t mysql-router .
docker run -d --name mysql-router --network <network-name> mysql-router- Navigate to the
proxysqlfolder - Build and start the ProxySQL container using the provided Dockerfile:
cd proxysql
docker build -t proxysql .
docker run -d --name proxysql --network <network-name> proxysqlvar cluster = dba.getCluster()
cluster.status()If you lose quorum (majority of nodes):
cluster.forceQuorumUsingPartitionOf('clusteradmin@<surviving-node>:3306')cluster.removeInstance('clusteradmin@<failed-node>:3306', {force: true})To completely remove the cluster configuration:
cluster.dissolve({force: true})- Node 1:
mysql-node-1:3306 - Node 2:
mysql-node-2:3306 - Node 3:
mysql-node-3:3306
- MySQL Router: Usually exposes ports 6446 (RW) and 6447 (RO)
- ProxySQL: Usually exposes port 6033
- Username:
clusteradmin - Password:
cladmin
- Monitoring: Regularly check cluster status
- Backups: Implement regular backup strategies
- Network: Ensure stable network connectivity between nodes
- Resources: Monitor CPU, memory, and disk usage
- Logs: Check MySQL error logs for any issues
- Testing: Regularly test failover scenarios
- Network connectivity: Ensure all nodes can communicate
- Version compatibility: Use the same MySQL version across all nodes
- Resource constraints: Ensure adequate memory and disk space
- Configuration drift: Verify all nodes have consistent configuration
// Check instance readiness
dba.checkInstanceConfiguration('clusteradmin@<node>:3306')
// Get cluster object
var cluster = dba.getCluster()
// Detailed cluster status
cluster.status({extended: true})
// Check routing options
cluster.listRouters()This setup provides a robust, highly available MySQL cluster suitable for production workloads with automatic failover and load balancing capabilities.