Permalink
Browse files

Add support for starting MySQL Cluster 7.5.4

1 parent 826b9da commit 8993bb3d1af6cbf52738cf127085abf178cfb5e9 @MarkLeith committed Oct 25, 2016
View
@@ -11,6 +11,205 @@ All MySQL instances are configured to listen on port 3306 (the default), with th
* repl / repl (a replication user)
* mem / mem (a MySQL Enterprise Monitor user)
+### mysql-cluster
+
+Sets up a MySQL Cluster using the latest Oracle Linux and MySQL Cluster 7.5.4.
+
+A wrapper script is included that allows you to build and start the cluster:
+
+```
+$ cluster.py -h
+usage: cluster.py [-h] [--debug] {build,start,stop,clean} ...
+
+Create a test MySQL Cluster deployment in docker
+
+positional arguments:
+ {build,start,stop,clean}
+ build Build the cluster containers
+ start Start up the cluster containers
+ stop Stop the cluster containers
+ clean Stop and remove the cluster containers
+
+optional arguments:
+ -h, --help show this help message and exit
+ --debug Whether to print debug info
+
+$ cluster.py build -h
+usage: cluster.py build [-h] [-m MANAGEMENT_NODES] [-d DATA_NODES]
+ [-s SQL_NODES]
+
+optional arguments:
+ -h, --help show this help message and exit
+ -m MANAGEMENT_NODES, --management-nodes MANAGEMENT_NODES
+ Number of Management nodes to run (default: 2; max: 2)
+ -d DATA_NODES, --data-nodes DATA_NODES
+ Number of NDB nodes to run (default: 4; max: 48)
+ -s SQL_NODES, --sql-nodes SQL_NODES
+ Number of SQL nodes to run (default: 2)
+
+$ cluster.py start -h
+usage: cluster.py start [-h] [-n NETWORK] [-m MANAGEMENT_NODES]
+ [-d DATA_NODES] [-s SQL_NODES]
+
+optional arguments:
+ -h, --help show this help message and exit
+ -n NETWORK, --network NETWORK
+ Name of the docker network to use
+ -m MANAGEMENT_NODES, --management-nodes MANAGEMENT_NODES
+ Number of Management nodes to run (default: 2; max: 2)
+ -d DATA_NODES, --data-nodes DATA_NODES
+ Number of NDB nodes to run (default: 4; max: 48)
+ -s SQL_NODES, --sql-nodes SQL_NODES
+ Number of SQL nodes to run (default: 2)
+ ```
+```
+
+You must invoke this with both the build and start arguments being the same, as the build command builds the initial cluster.ini file, which is then used when started using the start command - the initial number of ndb nodes must be as expected when started.
+
+#### Build:
+
+```
+$ cluster.py --debug build
+2016-10-25T16:04:33.229000: Arguments: Namespace(data_nodes=4, debug=True, func=<function build at 0x0000000002E63BA8>, management_nodes=2, sql_nodes=2)
+2016-10-25T16:04:33.235000: Running: docker build -t markleith/mysqlcluster75:ndb_mgmd -f management-node/Dockerfile management-node
+2016-10-25T16:04:33.511000: Running: docker build -t markleith/mysqlcluster75:ndbmtd -f data-node/Dockerfile data-node
+2016-10-25T16:04:33.809000: Running: docker build -t markleith/mysqlcluster75:sql -f sql-node/Dockerfile sql-node
+```
+
+#### Run:
+
+```
+$ cluster.py --debug start
+2016-10-25T16:04:37.007000: Arguments: Namespace(data_nodes=4, debug=True, func=<function start at 0x0000000002F73C18>, management_nodes=2, network='myclusternet', sql_nodes=2)
+2016-10-25T16:04:37.012000: Running: docker network ls
+2016-10-25T16:04:37.076000: myclusternet network found, using existing
+2016-10-25T16:04:37.078000: Running: docker run -d -P --net myclusternet --name mymgmd49 --ip 172.18.0.249 -e NODE_ID=49 -e NOWAIT=50 -e CONNECTSTRING= markleith/mysqlcluster75:ndb_mgmd
+2016-10-25T16:04:38.799000: Running: docker port mymgmd49 1186/tcp
+2016-10-25T16:04:38.885000: Added: Node(mymgmd49 : 32800 : mgmd)
+2016-10-25T16:04:38.887000: Running: docker run -d -P --net myclusternet --name mymgmd50 --ip 172.18.0.250 -e NODE_ID=50 -e NOWAIT=49 -e CONNECTSTRING=mymgmd49:1186 markleith/mysqlcluster75:ndb_mgmd
+2016-10-25T16:04:40.338000: Running: docker port mymgmd50 1186/tcp
+2016-10-25T16:04:40.394000: Added: Node(mymgmd50 : 32801 : mgmd)
+2016-10-25T16:04:40.396000: Running: docker run -d -P --net myclusternet --name myndbmtd1 --ip 172.18.0.11 -e NODE_ID=1 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:ndbmtd
+2016-10-25T16:04:41.925000: Running: docker port myndbmtd1 11860/tcp
+2016-10-25T16:04:41.987000: Added: Node(myndbmtd1 : 32802 : ndbmtd)
+2016-10-25T16:04:41.989000: Running: docker run -d -P --net myclusternet --name myndbmtd2 --ip 172.18.0.12 -e NODE_ID=2 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:ndbmtd
+2016-10-25T16:04:43.280000: Running: docker port myndbmtd2 11860/tcp
+2016-10-25T16:04:43.336000: Added: Node(myndbmtd2 : 32803 : ndbmtd)
+2016-10-25T16:04:43.338000: Running: docker run -d -P --net myclusternet --name myndbmtd3 --ip 172.18.0.13 -e NODE_ID=3 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:ndbmtd
+2016-10-25T16:04:44.855000: Running: docker port myndbmtd3 11860/tcp
+2016-10-25T16:04:44.936000: Added: Node(myndbmtd3 : 32804 : ndbmtd)
+2016-10-25T16:04:44.937000: Running: docker run -d -P --net myclusternet --name myndbmtd4 --ip 172.18.0.14 -e NODE_ID=4 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:ndbmtd
+2016-10-25T16:04:49.039000: Running: docker port myndbmtd4 11860/tcp
+2016-10-25T16:04:49.117000: Added: Node(myndbmtd4 : 32805 : ndbmtd)
+2016-10-25T16:04:49.119000: Running: docker run -d -P --net myclusternet --name mysqlndb51 --ip 172.18.0.151 -e NODE_ID=51 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:sql
+2016-10-25T16:05:06.190000: Running: docker port mysqlndb51 3306/tcp
+2016-10-25T16:05:06.264000: Added: Node(mysqlndb51 : 32806 : sql)
+2016-10-25T16:05:06.266000: Running: docker run -d -P --net myclusternet --name mysqlndb52 --ip 172.18.0.152 -e NODE_ID=52 -e CONNECTSTRING=mymgmd49:1186,mymgmd50:1186 markleith/mysqlcluster75:sql
+2016-10-25T16:05:12.735000: Running: docker port mysqlndb52 3306/tcp
+2016-10-25T16:05:13.104000: Added: Node(mysqlndb52 : 32807 : sql)
+2016-10-25T16:05:13.105000: Started: [Node(mymgmd49 : 32800 : mgmd), Node(mymgmd50 : 32801 : mgmd), Node(myndbmtd1 : 32802 : ndbmtd), Node(myndbmtd2 : 32803 : ndbmtd), Node(myndbmtd3 : 32804 : ndbmtd), Node(myndbmtd4 : 32805 : ndbmtd), Node(mysqlndb51 : 32806 : sql), Node(mysqlndb52 : 32807 : sql)]
+```
+
+#### Connecting
+
+You can use the exposed ports to connect directly to a SQL node from the docker host OS, such as taking the exposed port for mysqlndb52 above (32807):
+
+```
+$ mysql -u root -pmysql -h 127.0.0.1 -P 32807
+mysql: [Warning] Using a password on the command line interface can be insecure.
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 4
+Server version: 5.7.16-ndb-7.5.4-cluster-gpl MySQL Cluster Community Server (GPL)
+
+Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+
+Oracle is a registered trademark of Oracle Corporation and/or its
+affiliates. Other names may be trademarks of their respective
+owners.
+
+Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+mysql> show tables from ndbinfo;
++---------------------------------+
+| Tables_in_ndbinfo |
++---------------------------------+
+| arbitrator_validity_detail |
+| arbitrator_validity_summary |
+| blocks |
+| cluster_locks |
+| cluster_operations |
+| cluster_transactions |
+| config_params |
+| config_values |
+| counters |
+| cpustat |
+| cpustat_1sec |
+| cpustat_20sec |
+| cpustat_50ms |
+| dict_obj_info |
+| dict_obj_types |
+| disk_write_speed_aggregate |
+| disk_write_speed_aggregate_node |
+| disk_write_speed_base |
+| diskpagebuffer |
+| locks_per_fragment |
+| logbuffers |
+| logspaces |
+| membership |
+| memory_per_fragment |
+| memoryusage |
+| nodes |
+| operations_per_fragment |
+| resources |
+| restart_info |
+| server_locks |
+| server_operations |
+| server_transactions |
+| table_distribution_status |
+| table_fragments |
+| table_info |
+| table_replicas |
+| tc_time_track_stats |
+| threadblocks |
+| threads |
+| threadstat |
+| transporters |
++---------------------------------+
+41 rows in set (0.00 sec)
+
+mysql> desc ndbinfo.memoryusage;
++-------------+------------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++-------------+------------------+------+-----+---------+-------+
+| node_id | int(10) unsigned | YES | | NULL | |
+| memory_type | varchar(512) | YES | | NULL | |
+| used | decimal(62,0) | YES | | NULL | |
+| used_pages | decimal(42,0) | YES | | NULL | |
+| total | decimal(62,0) | YES | | NULL | |
+| total_pages | decimal(42,0) | YES | | NULL | |
++-------------+------------------+------+-----+---------+-------+
+6 rows in set (0.10 sec)
+
+mysql> select node_id, memory_type, sys.format_bytes(used) used, sys.format_bytes(total) total from ndbinfo.memoryusage;
++---------+---------------------+------------+-----------+
+| node_id | memory_type | used | total |
++---------+---------------------+------------+-----------+
+| 1 | Data memory | 704.00 KiB | 80.00 MiB |
+| 1 | Index memory | 104.00 KiB | 18.25 MiB |
+| 1 | Long message buffer | 384.00 KiB | 32.00 MiB |
+| 2 | Data memory | 704.00 KiB | 80.00 MiB |
+| 2 | Index memory | 104.00 KiB | 18.25 MiB |
+| 2 | Long message buffer | 256.00 KiB | 32.00 MiB |
+| 3 | Data memory | 704.00 KiB | 80.00 MiB |
+| 3 | Index memory | 104.00 KiB | 18.25 MiB |
+| 3 | Long message buffer | 256.00 KiB | 32.00 MiB |
+| 4 | Data memory | 704.00 KiB | 80.00 MiB |
+| 4 | Index memory | 104.00 KiB | 18.25 MiB |
+| 4 | Long message buffer | 256.00 KiB | 32.00 MiB |
++---------+---------------------+------------+-----------+
+12 rows in set (0.42 sec)
+```
+
### mysql-repo-server-5.6-centos-6.8
Sets up CentOS 6.8 with SSH and MySQL started.
@@ -0,0 +1,193 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import argparse
+import datetime
+import os
+import shutil
+import subprocess
+
+NDBD_BASE_ID = 1
+NDBD_BASE_IP = "172.18.0.1"
+MGMD_BASE_ID = 49
+MGMD_BASE_IP = "172.18.0.2"
+API_BASE_ID = 51
+API_BASE_IP = "172.18.0.1"
+SUBNET_BASE = "172.18.0.0/16"
+
+nodes=[]
+
+class Node:
+ def __init__(self, name, port, node_type):
+ self.name = name
+ self.port = port
+ self.node_type = node_type
+
+ def __str__(self):
+ return("Node("+str(self.name)+" : "+str(self.port)+" : "+str(self.node_type)+")")
+
+ def __repr__(self):
+ return str(self)
+
+def add_node(nodeName, node_type):
+ if node_type == "mgmd":
+ port = cmd("docker port {0} 1186/tcp".format(nodeName))
+ elif node_type == "ndbmtd":
+ port = cmd("docker port {0} 11860/tcp".format(nodeName))
+ elif node_type == "sql":
+ port = cmd("docker port {0} 3306/tcp".format(nodeName))
+ node = Node(nodeName, port.strip().split(":",1)[1], node_type)
+ nodes.append(node)
+ debug("Added: {0}".format(node))
+
+def ts():
+ return datetime.datetime.utcnow().isoformat()+": "
+
+def debug(msg):
+ if args.debug: print ts()+msg
+
+def cmd(cmd):
+ debug("Running: " + cmd)
+ return subprocess.check_output(cmd, shell=True)
+
+def write_ini_section(file, header, nodeid, nodeip):
+ file.write("\n["+header+"]\n")
+ file.write("NodeId={0}\n".format(nodeid))
+ file.write("HostName={0}\n".format(nodeip))
+
+def build_config_ini():
+ config_ini = os.getcwd()+"/management-node/config.ini"
+ try:
+ cfgtmpl = os.getcwd()+"/management-node/config.ini.in"
+ shutil.copy(cfgtmpl, config_ini)
+ except shutil.Error as e:
+ print('Error: %s' % e)
+ except IOError as e:
+ print('Error: %s' % e.strerror)
+ with open(config_ini, "ab") as f:
+ nodeid = MGMD_BASE_ID
+ for i in range(args.management_nodes):
+ write_ini_section(f, "NDB_MGMD", nodeid, "{0}{1}".format(MGMD_BASE_IP, nodeid))
+ nodeid += 1
+ nodeid = NDBD_BASE_ID
+ for i in range(args.data_nodes):
+ write_ini_section(f, "NDBD", nodeid, "{0}{1}".format(NDBD_BASE_IP, nodeid))
+ nodeid += 1
+ nodeid = API_BASE_ID
+ for i in range(args.sql_nodes):
+ write_ini_section(f, "MYSQLD", nodeid, "{0}{1}".format(API_BASE_IP, nodeid))
+ nodeid += 1
+
+def connect_string():
+ mgmd_nodes = filter(lambda x: x.node_type == "mgmd", nodes)
+ return ",".join(x.name+":1186" for x in mgmd_nodes)
+
+def management_nodes_option(x):
+ x = int(x)
+ if x > 2:
+ raise argparse.ArgumentTypeError("Maximum Managment nodes is 2")
+ return x
+
+def create_mgmd_nodes():
+ nodeid = MGMD_BASE_ID
+ mgmdSibling = nodeid + 1
+ ndbConnectString = ""
+ for i in range(args.management_nodes):
+ if i: nodeid, mgmdSibling = mgmdSibling, nodeid
+ nodeName = "mymgmd{0}".format(nodeid)
+ ip = "{0}{1}".format(MGMD_BASE_IP, nodeid)
+ runCmd = 'docker run -d -P --net {0} --name {1} --ip {2} -e NODE_ID={3} -e NOWAIT={4} -e CONNECTSTRING={5} markleith/mysqlcluster75:ndb_mgmd'
+ cmd(runCmd.format(args.network, nodeName, ip, nodeid, mgmdSibling, connect_string()))
+ add_node(nodeName, "mgmd")
+
+def data_nodes_option(x):
+ x = int(x)
+ if x > 48:
+ raise argparse.ArgumentTypeError("Maximum Data nodes is 48")
+ return x
+
+def create_data_nodes():
+ nodeid = NDBD_BASE_ID
+ for i in range(args.data_nodes):
+ nodeName = "myndbmtd{0}".format(nodeid)
+ ip = "{0}{1}".format(NDBD_BASE_IP, nodeid)
+ runCmd = 'docker run -d -P --net {0} --name {1} --ip {2} -e NODE_ID={3} -e CONNECTSTRING={4} markleith/mysqlcluster75:ndbmtd'
+ cmd(runCmd.format(args.network, nodeName, ip, nodeid, connect_string()))
+ add_node(nodeName, "ndbmtd")
+ nodeid += 1
+
+def create_sql_nodes():
+ nodeid = API_BASE_ID
+ for i in range(args.sql_nodes):
+ nodeName = "mysqlndb{0}".format(nodeid)
+ ip = "{0}{1}".format(API_BASE_IP, nodeid)
+ runCmd = 'docker run -d -P --net {0} --name {1} --ip {2} -e NODE_ID={3} -e CONNECTSTRING={4} markleith/mysqlcluster75:sql'
+ cmd(runCmd.format(args.network, nodeName, ip, nodeid, connect_string()))
+ add_node(nodeName, "sql")
+ nodeid += 1
+
+def build(args):
+ build_config_ini()
+ cmd('docker build -t markleith/mysqlcluster75:ndb_mgmd -f management-node/Dockerfile management-node')
+ cmd('docker build -t markleith/mysqlcluster75:ndbmtd -f data-node/Dockerfile data-node')
+ cmd('docker build -t markleith/mysqlcluster75:sql -f sql-node/Dockerfile sql-node')
+
+def start(args):
+ networks = cmd("docker network ls")
+ if networks.find(args.network) != -1:
+ debug(args.network + " network found, using existing")
+ else:
+ debug(args.network + " network not found, creating")
+ cmd("docker network create --subnet="+SUBNET_BASE+" "+args.network)
+ create_mgmd_nodes()
+ create_data_nodes()
+ create_sql_nodes()
+ print "{0}Started: {1}".format(ts(), nodes)
+
+def stop(args):
+ debug("OH DEAR, MUST IMPLEMENT STOP")
+
+def clean(args):
+ debug("OH DEAR, MUST IMPLEMENT CLEAN")
+
+if __name__ == '__main__':
+
+ parser = argparse.ArgumentParser(description="Create a test MySQL Cluster deployment in docker")
+ network = argparse.ArgumentParser(add_help=False)
+ network.add_argument('-n', '--network', default="myclusternet", help='Name of the docker network to use')
+ mgmd_nodes = argparse.ArgumentParser(add_help=False)
+ mgmd_nodes.add_argument('-m', '--management-nodes', default=2, type=management_nodes_option, help='Number of Management nodes to run (default: 2; max: 2)')
+ data_nodes = argparse.ArgumentParser(add_help=False)
+ data_nodes.add_argument('-d', '--data-nodes', default=4, type=data_nodes_option, help='Number of NDB nodes to run (default: 4; max: 48)')
+ sql_nodes = argparse.ArgumentParser(add_help=False)
+ sql_nodes.add_argument('-s', '--sql-nodes', default=2, type=int, help='Number of SQL nodes to run (default: 2)')
+ sp = parser.add_subparsers()
+ sp_build = sp.add_parser('build', parents=[mgmd_nodes, data_nodes, sql_nodes], help='Build the cluster containers')
+ sp_build.set_defaults(func=build)
+ sp_start = sp.add_parser('start', parents=[network, mgmd_nodes, data_nodes, sql_nodes], help='Start up the cluster containers')
+ sp_start.set_defaults(func=start)
+ sp_stop = sp.add_parser('stop', parents=[network], help='Stop the cluster containers')
+ sp_stop.set_defaults(func=stop)
+ sp_clean = sp.add_parser('clean', parents=[network], help='Stop and remove the cluster containers')
+ sp_clean.set_defaults(func=clean)
+ parser.add_argument('--debug', default=False, action="store_true", help='Whether to print debug info')
+ args = parser.parse_args()
+
+ debug("Arguments: {0}".format(args))
+
+ args.func(args)
Oops, something went wrong.

0 comments on commit 8993bb3

Please sign in to comment.