Мастер-мастер репликация MySql на Docker

Вы когда-нибудь задумывались, почему Docker так популярен? Docker позволяет легко развернуть необходимое вам окружение в считанные минуты и по мере необходимости добавлять в ваше окружение нужный функционал и быстро его разворачивать практически на любой “машине”*.

В этой статье я собираюсь показать как настроить Master-Master репликацию между двумя Docker контейнерами Mysql.

Требования к железу для установки докер (eng): https://docs.docker.com/datacenter/ucp/1.1/installation/system-requirements/

Инструкция по установке, где вы можете посмотреть как установить Docker для вашей ОС: https://docs.docker.com/engine/installation/

Шаг 1 – Подготовка структуры папок и конфигураций mysql

Прежде всего мы создадим структуру каталогов, как показано ниже, для каждого, отдельно взятого mysql сервера.

~/server#/backup – Тут будут лежать необходимые нам sql файлы

~/server#/data – Точка входа, откуда будем монтировать данные. При каждом перезапуске, в этом каталоге будут сохраняться данные.

~/server#/log – Логи mysql сервера

~/server#/conf.d – Каталог будет содержать файлы конфигурации.

Конфигурация mySQL:

~/server1/conf.d/server1.cnf:

[mysqld]
server-id = 101
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = mydata
bind-address = 0.0.0.0 
character_set_server = utf8
collation_server = utf8_general_ci
 
[mysql]
 default_character_set = utf8

~/server1/backup/initdb.sql

use mysql;
create user 'replicator'@'%' identified by 'repl1234or';
grant replication slave on *.* to 'replicator'@'%'; 
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
SHOW VARIABLES LIKE 'server_id';

~/server2/conf.d/server2.cnf

[mysqld]
server-id = 102 # Remember this is only Integer per official documentation
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = mydata
bind-address = 0.0.0.0
character_set_server = utf8
collation_server = utf8_general_ci
[mysql]
default_character_set = utf8

~/server2/backup/initdb.sql

use mysql;
create user 'replicator'@'%' identified by 'repl1234or';
grant replication slave on *.* to 'replicator'@'%'; 
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
SHOW VARIABLES LIKE 'server_id';

 

Шаг 2 – Запуск Docker контейнеров с нашими конфигурациями

После того как мы сделали все нужные нам приготовления мы можем запустить контейнеры с серверами.

Запускаем первый контейнер:

docker run --name mysql1 -e MYSQL_ROOT_PASSWORD=mysql1pass -e MYSQL_DATABASE=mydata -dit -p 33061:3306 -v /opt2/mysql/server1/conf.d:/etc/mysql/mysql.conf.d/   -v /opt2/mysql/server1/data:/var/lib/mysql -v /opt2/mysql/server1/log:/var/log/mysql -v /opt2/mysql/server1/backup:/backup -h  mysql1 mysql

Запускаем второй контейнер:

docker run --name mysql2 --link mysql1 -e MYSQL_ROOT_PASSWORD=mysql2pass -e MYSQL_DATABASE=mydata -dit -p 33062:3306 -v /opt2/mysql/server2/conf.d:/etc/mysql/mysql.conf.d/   -v /opt2/mysql/server2/data:/var/lib/mysql -v /opt2/mysql/server2/log:/var/log/mysql -v /opt2/mysql/server2/backup:/backup -h  mysql2 mysql

После запуска каждой нужно немного подождать пока все сервисы внутри контейнера запустятся. Также, обратите внимание, что мы связали контейнер mysql2 с контейнером mysql1 во время запуска командой docker run.

Шаг 3 – Свяжем контейнер mysql1 с контейнером mysql2

Решение скорее экспериментальное, так как, в момент запуска mysql1 у нас еще нет контейнера mysql2. Но в статьях на stackoverflow было найдено решение которое позволило связать mysql1 с mysql2 внутри интерфейса docker0. Главное, что докер просто создает запись хоста в связанном контейнере. Сделаем тоже самое только руками. Следует отметить что при перезапуске контейнеров их IP адреса могут меняться и вам придется пройти эту процедуру еще раз.

Итак. Мы возьмем IP контейнера mysql2 и потом сделаем запись в hosts файл в контейнере  mysql1.

# find out IP Address of mysql2

mysql2ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql2)

#Append the new IP as new host entry in mysql1's host file.

docker exec -i mysql1 sh -c "echo '$mysql2ip mysql2 mysql2' >> /etc/hosts"

# Check if the above command worked

docker exec -i mysql1 sh -c "cat /etc/hosts"

Проверим соединение между двумя контейнерами:

docker exec -ti mysql2 sh -c "ping mysql1"
docker exec -ti mysql1 sh -c "ping mysql2"

Если все пингуется то можно переходить к следующему шагу.

Шаг 4 – Создание пользователя для репликации и проверка лога

Mysql1 – нужно подключится и выполнить скрипт /backup/initdb.sql

/opt2/mysql$ docker exec -ti mysql1 sh -c "mysql -uroot -p"
Enter password:
mysql> source /backup/initdb.sql
Database changed
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154 | mydata | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 101 |
+---------------+-------+
1 row in set (0.01 sec)

 

Mysql2 – та же операция что и для mysql1

/opt2/mysql$ docker exec -ti mysql2 sh -c "mysql -uroot -p"
Enter password:
mysql> source /backup/initdb.sql
Database changed
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154 | mydata | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 102 |
+---------------+-------+
1 row in set (0.01 sec)


Шаг 5 – Установка источника репликации для контейнеров

Mysql1:

/opt2/mysql$ docker exec -ti mysql2 sh -c "mysql -uroot -p"
Enter password:
mysql>> stop slave; 
mysql>> CHANGE MASTER TO MASTER_HOST = 'mysql1', MASTER_USER = 'replicator', 
   ->> MASTER_PASSWORD = 'repl1234or', MASTER_LOG_FILE = 'mysql-bin.000003', 
   ->> MASTER_LOG_POS = 154; 
mysql>> start slave;
mysql>> show slave status\g

Mysql2:

/opt2/mysql$ docker exec -ti mysql1 sh -c "mysql -uroot -p"
Enter password:
mysql>> stop slave; 
mysql>> CHANGE MASTER TO MASTER_HOST = 'mysql2', MASTER_USER = 'replicator', 
   ->> MASTER_PASSWORD = 'repl1234or', MASTER_LOG_FILE = 'mysql-bin.000003',
   ->> MASTER_LOG_POS = 154; 
mysql>> start slave;
mysql>> show slave status\g

 

Шаг 6 – Тестирование Master-Master репликации

Для того чтобы протестировать репликацию просто создадим таблицу в контейнере mysql1 и посмотрим появиться ли таблица в контейнере mysql2, а затем удалим таблицу из mysql2 и посмотрим что бы она была удалена из mysql1.

Создадим таблицу:

use mydata;
create table students ('id' int,  'name' varchar(20));

Посмотрим появилась ли она в mysql2:

show tables in mydata;

Должны увидеть примерно следующее:

+-------------------+
| Tables_in_mydata |
+-------------------+
| students |
+-------------------+
1 row in set (0.00 sec)

Удалим таблицу в mysql2:

DROP TABLE students;

И посмотрим результат команды show tables в контейнере mysql1:

Empty set (0.00 sec)

Если все шаги пройдены и у вас нет таблиц то можно сказать что репликация Master – Master в mysql работает.

Источники:

P.S. Хотите больше статей по докеру или mysql? пишите в комментариях какие темы вас больше всего интересуют.

P.S.S. В планах написать статью о том как мы внедряли у себя на проекте Docker. (стек: микросервисы на Java, фронт на Symfony + Elasticsearch + Socket.io + …)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.