Запихать Mysql в Kubernetes оказалось не очень хорошей идеей и я решил основательно пересмотреть инфраструктуру своего pet-проекта и за основу будет принят кластер из трех серверов. На каждом узле кластера будет развернут сервер Mysql в кластерном режиме.
В этом издевательстве над логикой мы настроим кластер MySQL с использованием Group Replication (встроенный механизм репликации в MySQL 5.7 и выше).
Серверная инфраструктура проекта
- s-rain-01 — 178.72.166.7
- s-rain-02 — 139.100.193.124
- s-rain-03 — 45.12.231.103
Созданные VPS в Selectel
- Три сервера с Ubuntu 24.04.
- На каждом сервере — 4 ГБ оперативной памяти и два vCPU.
- Открытые порты:
3306(MySQL) и33061(Group Replication). - Корректно настроенные DNS-имена shiskitech.ru и запись в
/etc/hostsи /etc/hostname.
Установка MySQL на всех серверах
Выполните на каждом из трёх серверов:
# apt update
# apt install -y mysql-server
Запустите и включите автозапуск MySQL:
# systemctl enable mysql
# systemctl start mysql
Защитите установку MySQL (установите пароль root, удалите анонимных пользователей и т. д.):
# mysql_secure_installation
Шаг 2. Настройка конфигурации MySQL
На каждом сервере отредактируйте файл конфигурации MySQL:
# nano /etc/mysql/mysql.conf.d/mysqld.cnf
Добавьте или измените следующие параметры:
[mysqld]
# Уникальный идентификатор сервера (должен быть разным на каждом узле)
server-id = 1 # На node1: 1, на node2: 2, на node3: 3
# Включение бинарного лога (обязательно для репликации)
log-bin = mysql-bin
# Формат бинарного лога
binlog-format = ROW
# Режим проверки бинарного лога
binlog-checksum = NONE
# Автоматическое обновление бинарного лога
auto-increment-increment = 3
auto-increment-offset = 1 # На node1: 1, на node2: 2, на node3: 3
# Группа репликации
gtid-mode = ON
enforce-gtid-consistency = ON
# Разрешить репликацию с любых хостов (в продакшене ограничьте IP)
bind-address = 0.0.0.0
# Включение Group Replication
plugin-load = "group_replication.so"
#БД, которые нужно/не нужно реплицировать
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
#Не вести журнал бин-лога для БД
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
#Сохранять логи с мастера в свой бин-лог, чтобы передать слейв-серверу
log-slave-updates
#log_slave_updates = 1
# Сколько дней хранить бин-логи
expire_logs_days = 7
# Максимальный размер бин-лога
max_binlog_size = 500M
# Настройка Group Replication
group_replication_group_name = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot = off
group_replication_local_address = "NODE_IP:33061" # Замените NODE_IP на IP текущего узла
group_replication_group_seeds = "NODE1_IP:33061,NODE2_IP:33061,NODE3_IP:33061" # Замените IP на реальные
group_replication_ip_allowlist= "NODE1_IP,NODE2_IP,NODE3_IP" # Замените IP на реальные и здесь без указания порта!
skip-name-resolve
# Настройка портов
port = 3306
Важно: замените NODE_IP, NODE1_IP, NODE2_IP, NODE3_IP на реальные IP-адреса ваших серверов и обратите внимание, что у Selectel вам необходимо для связи хостов создать глобальный роутер и у хоста указываем адрес из внутренней сети.
Сохраните файл и перезапустите MySQL:
# systemctl restart mysql
Шаг 3. Настройка безопасности и пользователей
На каждом сервере подключитесь к MySQL:
# mysql -u root -p
Создайте пользователя для Group Replication:
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'secure_password';
mysql> GRANT BACKUP_ADMIN ON *.* TO 'repl'@'%';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
mysql> FLUSH PRIVILEGES;
Если у вас нет особого желания потом разбираться с ошибками вида:
Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection. Error_code: MY-002061
То можно создать пользователя repl со старым типом пароля (mysql_native_password).
ALTER USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'secure_password';
Шаг 4. Настройка первого узла (Primary)
Подключитесь к первому узлу (mysql-node1):
# mysql -u root -p
Выполните следующие команды:
-- Блокируем таблицы для консистентности
SET GLOBAL group_replication_bootstrap_group = ON;
-- Запускаем Group Replication
START GROUP_REPLICATION;
-- Проверяем статус
SELECT * FROM performance_schema.replication_group_members;
-- Загружаем плагин для клонирования
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
Убедитесь, что статус узла — ONLINE.
SELECT * FROM performance_schema.replication_group_members;
Разрешаем список узлов с которых разрешена репликация.
SET GLOBAL group_replication_ip_allowlist="213.171.29.99, 45.155.204.127, 185.135.81.157";
Запросим статус мастер-сервера:
mysql> show master status;
+------------------+----------+--------------+---------------------------------------------+------------------------------------------------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+---------------------------------------------+------------------------------------------------------------------------------------+
| mysql-bin.000003 | 233 | | information_schema,mysql,performance_schema | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-2,
b624ddc1-60a8-11f1-a308-fa163ea808b8:1-5 |
+------------------+----------+--------------+---------------------------------------------+------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
Проверяем, что все необходимые порты обслуживаются сервером.
# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 8281/mysqld
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN 526/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1/init
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 526/systemd-resolve
tcp6 0 0 :::33060 :::* LISTEN 8281/mysqld
tcp6 0 0 :::33061 :::* LISTEN 8281/mysqld
tcp6 0 0 :::22 :::* LISTEN 1/init
udp 0 0 127.0.0.54:53 0.0.0.0:* 526/systemd-resolve
udp 0 0 127.0.0.53:53 0.0.0.0:* 526/systemd-resolve
udp 0 0 213.171.29.99:68 0.0.0.0:* 705/systemd-network
Разрешаем доступ к портам для определенных серверов.
# ufw allow from 213.171.29.99 to any port 3306
# ufw allow from 213.171.29.99 to any port 33060
# ufw allow from 213.171.29.99 to any port 33061
Проверяем статус Firewall.
# ufw status
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
Anywhere ALLOW 213.171.29.99
Anywhere ALLOW 45.155.204.127
Anywhere ALLOW 185.135.81.157
3306 ALLOW 213.171.29.99
33060 ALLOW 213.171.29.99
33061 ALLOW 213.171.29.99
3306 ALLOW 45.155.204.127
33060 ALLOW 45.155.204.127
33061 ALLOW 45.155.204.127
3306 ALLOW 185.135.81.157
33060 ALLOW 185.135.81.157
33061 ALLOW 185.135.81.157
22 (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443/tcp (v6) ALLOW Anywhere (v6)
Шаг 5. Добавление остальных узлов
Для второго узла (mysql-node2)
Аналогично разрешаем доступ с узлов репликации.
# ufw allow from 213.171.29.99 to any port 3306
# ufw allow from 213.171.29.99 to any port 33060
# ufw allow from 213.171.29.99 to any port 33061
Проверяем доступность портов на мастер-сервере.
# telnet 213.171.29.99 3306
Trying 213.171.29.99...
Connected to 213.171.29.99.
Escape character is '^]'.
caching_sha2_password^]
telnet> quit
Connection closed.
Подключитесь к mysql-node2:
# mysql -u root -p
Добавляем:
SET GLOBAL group_replication_ip_allowlist="213.171.29.99, 45.155.204.127, 185.135.81.157";
Выполните:
-- Отключаем bootstrap (только для первого узла)
SET GLOBAL group_replication_bootstrap_group = OFF;
-- Клонируем базу с мастера
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
SET GLOBAL clone_valid_donor_list = '10.10.10.2:3306';
CLONE INSTANCE FROM 'repl'@'10.10.10.2':3306 IDENTIFIED BY 'secure_password';
-- Запускаем Group Replication
CHANGE REPLICATION SOURCE TO SOURCE_USER='repl', SOURCE_PASSWORD='secure_password' FOR CHANNEL 'group_replication_recovery';
START GROUP_REPLICATION;
-- Проверяем статус
SELECT * FROM performance_schema.replication_group_members;
На этапе подключения slave-узлов меняйте переметр group_replication_group_seeds сначала два узла участвующие в репликации потом добавляем третий.
Для третьего узла (mysql-node3)
Повторите шаги для mysql-node2.
Шаг 6. Проверка работоспособности кластера
На любом узле выполните:
SELECT * FROM performance_schema.replication_group_members;
Ожидаемый результат: все три узла должны иметь статус ONLINE.
Создайте тестовую базу данных и таблицу на одном узле:
CREATE DATABASE test_cluster;
USE test_cluster;
CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO test_table (id, name) VALUES (1, 'Test');
Проверьте, что данные синхронизированы на других узлах:
USE test_cluster;
SELECT * FROM test_table;
Статус кластера:
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | 5f75347a-60b9-11f1-bd56-fa163ea808b8 | s-rain-01 | 3306 | ONLINE | PRIMARY | 8.0.46 | XCom |
| group_replication_applier | bcd33b10-60a8-11f1-8903-fa163e6ebcc3 | s-rain-02 | 3306 | RECOVERING | SECONDARY | 8.0.46 | XCom |
| group_replication_applier | c1f043e7-60a8-11f1-bf6e-fa163ee378b1 | s-rain-03 | 3306 | RECOVERING | SECONDARY | 8.0.46 | XCom |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
3 rows in set (0.00 sec)
Шаг 7. Настройка автоматического запуска
На каждом узле включите автоматический запуск Group Replication:
SET PERSIST group_replication_start_on_boot = ON;
В конфиге серверов меняем параметр.
group_replication_start_on_boot = on
Шаг 8. Дополнительные настройки и мониторинг
Настройка мониторинга
Создайте скрипт для мониторинга состояния кластера:
# nano /usr/local/bin/check_mysql_cluster.sh
#!/bin/bash
mysql -e "SELECT * FROM performance_schema.replication_group_members\G" | grep -E "(MEMBER_STATE|MEMBER_HOST)"
Сделайте скрипт исполняемым:
# chmod +x /usr/local/bin/check_mysql_cluster.sh
Настройка резервного копирования
Используйте mysqldump для регулярного бэкапа:
# mysqldump -u root -p --single-transaction --all-databases > /backup/mysql_backup_$(date +%Y%m%d).sql
Шаг 9. Устранение типичных проблем
Проблема: узел не присоединяется к кластеру
Проверьте, что порты 3306 и 33061 открыты:
# ufw allow 3306
# ufw allow 33061
Убедитесь, что group_replication_local_address и group_replication_group_seeds указаны корректно.
Проверьте логи MySQL:
# tail -f /var/log/mysql/error.log
Проблема: ошибка синхронизации данных
- Проверьте GTID:
SHOW GLOBAL VARIABLES LIKE 'gtid_executed';
- При необходимости сбросьте GTID (только в тестовой среде):
RESET MASTER;
Важные замечания
- Если в логах сообщение про несовпадение ключей: надо указать стянуть ключ с мастера
CHANGE REPLICATION SOURCE TO GET_SOURCE_PUBLIC_KEY=1; - Количество узлов: для Group Replication рекомендуется нечётное количество узлов (3, 5 и т. д.) для обеспечения кворума.
- Сетевые задержки: убедитесь, что между узлами минимальные сетевые задержки (менее 10 мс).
- Резервное копирование: регулярно создавайте бэкапы, так как Group Replication не заменяет резервное копирование.
- Безопасность: используйте сложные пароли, ограничьте доступ к MySQL только с доверенных IP-адресов.
- Мониторинг: настройте мониторинг (например, с помощью Prometheus + MySQL Exporter) для отслеживания состояния кластера.
Дополнительно
Пересоздание базы данных.
Остановите базу данных.
# systemctl stop mysql
Удалите хранилище.
# rm -rf /var/lib/mysql/*
Инициализируем базу данных.
# mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql
Запускаем базу данных.
# systemctl start mysql
Отключаем обязательный SSL
В конфигурационный файл добавляем опцию.
require_secure_transport = OFF
Создаем пользователя с native password
CREATE USER 'username'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_secure_password';




