MariaDB Master Slave Replication in Docker Containers
Introduction
One of the main features of MariaDB is the Master Slave Replication. As explained in documentation:
Replication is a feature allowing the contents of one or more servers (called masters) to be mirrored on one or more servers (called slaves).
We are going to create a basic two-node Master Slave Replication using Docker containers in a Google Cloud Platform virtual machine.
Previously we have installed and configured a MariaDB Master Slave Replication on VM Instances, this time we are going to build it with containers.
Prerequisites
A running Docker host in any OS. We are using a virtual machine instance in Google Cloud Platform with Container Optimized OS
as it already includes Docker 19.03
.
Create MariaDB Containers
Create Network
In order to ease the reference between the cluster nodes we are going to use our own docker network
type bridge
previously created so both containers can find the other by name:
pato@patocontainer ~ $ docker network ls
NETWORK ID NAME DRIVER SCOPE
...
522c4b821356 pato-net bridge local
Build Containers from Customized image
Let’s create our containers with docker run
using the customized image patomx/patomariadb
. For more information on this image visit My MariaDB Docker Image and Volume.
We will be using the network previously created --network pato-net
and we will assign a particular name for the datadir volume -v patovolgm:/var/lib/mysql
.
pato@patocontainer ~ $ docker run -d --name patomariadb --network pato-net -v patovoldb:/var/lib/mysql patomx/patomariadb
9480dd3937c18a034406875f9f2e8b3c39dafff65e677052f8bc39d763df2734
pato@patocontainer ~ $ docker run -d --name patomariarp --network pato-net -v patovolrp:/var/lib/mysql patomx/patomariadb
638f5ce36f85c6a64b3b684c59cd5ddf9b6fcd705389fbc4a7face0f674c0a90
pato@patocontainer ~ $ docker stop patomariadb patomariarp
patovoldb
patovolrp
Once created we replicate the data from our customized database to our new containers volume:
pato@patocontainer ~ $ docker run --rm -i -t -v patovolmariadb:/origen -v patovoldb:/destino alpine sh -c "cp -avr /origen/* /destino"
'/origen/aria_log.00000001' -> '/destino/aria_log.00000001'
'/origen/aria_log_control' -> '/destino/aria_log_control'
...
pato@patocontainer ~ $ docker run --rm -i -t -v patovolmariadb:/origen -v patovolrp:/destino alpine sh -c "cp -avr /origen/* /destino"
...
Start the containers and validate they are running:
pato@patocontainer ~ $ docker start patomariadb patomariarp
patomariadb
patomariarp
pato@patocontainer ~ $ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
638f5ce36f85 patomx/patomariadb "docker-entrypoint.s…" 6 minutes ago Up 18 seconds 3306/tcp patomariarp
9480dd3937c1 patomx/patomariadb "docker-entrypoint.s…" 7 minutes ago Up 19 seconds 3306/tcp patomariadb
pato@patocontainer ~ $ docker volume ls
DRIVER VOLUME NAME
local patovoldb
local patovolmariadb
local patovolrp
Master Slave Replication
Configure Replication on Master
Access the newly created Master container with a shell session docker exec -it patomariadb bash
and generate the configuration file, defining the unique server_id
and the name and format of the binary log:
pato@patocontainer ~ $ docker exec -it patomariadb bash
root@9480dd3937c1:/# nano /etc/mysql/conf.d/replication.cnf
# MariaDB Replication Configuration
[mariadb]
server_id=1
log_bin=master-bin
binlog-format=mixed
log_slave_updates=on
Then connect to the database and create a user for the replication:
pato@9480dd3937c1:/# mysql
MariaDB [(none)]> GRANT REPLICATION SLAVE ON *.* TO 'replicador'@'%' IDENTIFIED BY '********';
Query OK, 0 rows affected (0.007 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.015 sec)
Finally restart the database container for the new configuration to be loaded:
pato@patocontainer ~ $ docker restart patomariadb
Configure Replication on Slave
Access the newly created Slave container with a shell session docker exec -it patomariarp bash
and generate the configuration file, defining the unique server_id and the name and format of the binary log:
pato@patocontainer ~ $ docker exec -it patomariarp bash
root@638f5ce36f85:/# nano /etc/mysql/conf.d/replication.cnf
# MariaDB Replication Configuration
[mariadb]
server_id=11
log_bin=slave-bin
binlog-format=mixed
log_slave_updates=on
Finally restart the database container for the new configuration to be loaded:
pato@patocontainer ~ $ docker restart patomariarp
Generate Test Data and Objects
Connect to Master database and generate a table and insert a row:
pato@patocontainer ~ $ docker exec -it --user pato patomariadb bash
pato@9480dd3937c1:/$ mysql
MariaDB [(none)]> create database taller ;
Query OK, 1 row affected (0.012 sec)
MariaDB [(none)]> use taller;
Database changed
MariaDB [taller]> create table r1 (i1 int auto_increment primary key, c1 varchar(20), d1 datetime) ;
Query OK, 0 rows affected (0.085 sec)
MariaDB [taller]> insert into r1 (c1,d1) values ('Before Master Slave',now());
Query OK, 1 row affected (0.021 sec)
MariaDB [taller]> commit ;
Query OK, 0 rows affected (0.000 sec)
MariaDB [taller]> select * from r1;
+----+---------------------+---------------------+
| i1 | c1 | d1 |
+----+---------------------+---------------------+
| 1 | Before Master Slave | 2020-05-22 17:49:14 |
+----+---------------------+---------------------+
1 row in set (0.000 sec)
Initial Data Copy
Freeze any activity in Master database:
pato@patocontainer ~ $ docker exec -it --user pato patomariadb bash
pato@9480dd3937c1:~$ mysql
MariaDB [(none)]> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.013 sec)
Then backup the Master database:
pato@9480dd3937c1:~$ mysqldump --all-databases > masterfull.sql
pato@9480dd3937c1:~$ mysql
Get the binary log coordinates for the starting point of replication:
MariaDB [(none)]> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 | 1029 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.000 sec)
Unfreeze activity in Master:
MariaDB [(none)]> UNLOCK TABLES;
Query OK, 0 rows affected (0.000 sec)
Restore Backup in Slave
Transfer Backup from the Master node to the Slave node:
pato@patocontainer ~ $ docker cp patomariadb:/home/pato/masterfull.sql .
pato@patocontainer ~ $ docker cp masterfull.sql patomariarp:/home/pato
Restore the backup:
pato@patocontainer ~ $ docker exec -it --user pato patomariarp bash
pato@638f5ce36f85:~$ mysql < masterfull.sql
Start Replication
Configure Slave database with the binlog position master-bin.000001
- 1029
from the initial copy and then modify the replication to use GTID position:
pato@638f5ce36f85:~$ mysql
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='patomariadb',
-> MASTER_USER='replicador',
-> MASTER_PASSWORD='********',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='master-bin.000001',
-> MASTER_LOG_POS=1029,
-> MASTER_CONNECT_RETRY=10;
Query OK, 0 rows affected (0.117 sec)
MariaDB [(none)]> CHANGE MASTER TO MASTER_USE_GTID = slave_pos ;
Query OK, 0 rows affected (0.011 sec)
Start the Slave and validate the status:
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.024 sec)
MariaDB [(none)]> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: patomariadb
Master_User: replicador
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 1029
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 1329
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Using_Gtid: Slave_Pos
Gtid_IO_Pos: 0-1-4
...
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
...
1 row in set (0.001 sec)
OK our Master Slave replication is set and running!
Test Master Slave Replication
In order to validate that the replication is working we are going to create one more table and data:
pato@patocontainer ~ $ docker exec -it --user pato patomariadb bash
pato@9480dd3937c1:/$ mysql
MariaDB [(none)]> use taller
Database changed
MariaDB [taller]> create table r2 (i2 int auto_increment primary key, c2 varchar(20), d2 datetime) ;
Query OK, 0 rows affected (0.153 sec)
MariaDB [taller]> insert into r2 (c2,d2) values ('After Master Slave',now());
Query OK, 1 row affected (0.018 sec)
MariaDB [taller]> commit;
Query OK, 0 rows affected (0.000 sec)
MariaDB [taller]> select * from r2;
+----+--------------------+---------------------+
| i2 | c2 | d2 |
+----+--------------------+---------------------+
| 1 | After Master Slave | 2020-05-22 18:00:10 |
+----+--------------------+---------------------+
1 row in set (0.033 sec)
Verify that the data and objects were replicated from the Master to the Slave, the ones from the initial copy table r1 - Before Master Slave
and from the replication table r2 - After Master Slave
:
pato@patocontainer ~ $ docker exec -it --user pato patomariarp bash
pato@638f5ce36f85:/$ mysql
MariaDB [(none)]> use taller
Database changed
MariaDB [taller]> select * from r1;
+----+---------------------+---------------------+
| i1 | c1 | d1 |
+----+---------------------+---------------------+
| 1 | Before Master Slave | 2020-05-22 17:49:14 |
+----+---------------------+---------------------+
1 row in set (0.026 sec)
MariaDB [taller]> select * from r2;
+----+--------------------+---------------------+
| i2 | c2 | d2 |
+----+--------------------+---------------------+
| 1 | After Master Slave | 2020-05-22 18:00:10 |
+----+--------------------+---------------------+
1 row in set (0.000 sec)
OK the data and table were replicated from the Master to the Slave!
Conclusion
We successfully generated and configured a Master Slave Replication using Docker containers inside a virtual machine from the Google Cloud Platform and validated it’s working.
As you can see the basic setup is quite straightforward. After this you can try more functionalities like filtering tables, failover and switchover, and multiple slaves.