Построение отказоустойчивого кластера с синхронизацией файлов посредством lsyncd и MySQL репликацией

Построение отказоустойчивого кластера с синхронизацией файлов посредством lsyncd и MySQL репликацией

Roman Bogachev VMware Specialist | Drone Pilot | Traveler

Кластерное решение из двух серверов с репликацией данных MySQL (master-master), синхронизацией файлов через lsyncd, и распределенным DNS на базе BIND

Производим установку веб-сервера и MySQL по желанию. В моем случае NGINX + MySQL.

Подготавливаем систему для синхронизации файлов

Для синхронизации файлов, нам необходимо сделать беспарольный доступ по SSH между серверами, для этого сгенерируем пару ключей:

1
2
ssh-keygen -t rsa (passphrase не указываем)
scp /root/.ssh/id_rsa.pub root@10.2.0.2:/root/.ssh/authorized_keys2

и аналогично на втором сервере:

1
2
ssh-keygen -t rsa (passphrase не указываем)
scp /root/.ssh/id_rsa.pub root@10.1.0.2:/root/.ssh/authorized_keys2

Для синхронизации файлов я пробовал использовать Unison, но, к сожалению, необходимого функционала у него нет, поэтому в данном примере будет рассматриваться lsyncd (Rsync + inotify)

Устанавливаем lsyncd

Пакет lsyncd есть в базовых репозиториях CentOS

1
2
yum install lsyncd
chkconfig lsyncd on

Можете не пытаться запускать, поскольку без рабочего конфига вы просто получите ошибку:

1
2
Starting lsyncd: Error: Nothing to watch!
[FAILED]

Создаем конфиг для lsyncd

Конфиг пишется на языке Lua.
Мануалы можно найти на GitHub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
settings {
logfile = "/var/log/lsyncd/lsyncd.log",
statusFile = "/var/log/lsyncd/lsyncd-status.log",
statusInterval = 20
}

sync {
default.rsync,
source = "/sync_folder/",
target = "192.168.2.2:/sync_folder/",
exclude = {"*.tmp", "*.log", "*.cache" },
delete=true,
rsync = {
compress = true,
acls = true,
verbose = true,
owner = true,
group = true,
rsh = "/usr/bin/ssh -p 22 -o StrictHostKeyChecking=no" }
}

Конфиг проще сделать один раз и дальше разнести на все ноды, закомментировав лишний для каждого конкретного сервера блок.

Комментарии — это все что находится между --[[ и ]]

Запускаем lsyncd

1
/etc/init.d/lsyncd start

В случае получения ошибки решение очень простое

1
2
3
4
5
6
7
8
[root@Leader lsyncd]# /etc/init.d/lsyncd start
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
Starting lsyncd: shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
[ OK ]
[root@Leader lsyncd]# cd /
[root@Leader /]# /etc/init.d/lsyncd start
Starting lsyncd: [ OK ]
[root@Leader /]#

Если ничего не работает и в логах наблюдаем ошибку, то отключаем SElinux :)

1
rsync: Failed to exec /usr/bin/ssh: Permission denied (13)

Настраиваем репликацию MySQL

В данном случае мы будем использовать master-master. Для репликации будем использовать нового пользователя. Создаем его на обоих серверах.

Подключаемся к базе

1
2
3
4
5
mysql -u root -p
>
CREATE USER replication;
GRANT REPLICATION SLAVE ON *.* TO replication IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

На leader сервере в /etc/my.cnf в секции [mysqld] добавляем:

1
2
3
4
5
6
7
8
9
10
server-id=1
relay-log=master1-relay-bin
master-host = IP_второго_сервера
master-user = replication
master-password = password
master-port = 3306
slave-skip-errors = all
log-bin=mysql-bin
auto_increment_increment = 2
auto_increment_offset = 1

на follower сервере соответственно:

1
2
3
4
5
6
7
8
9
10
server-id=2
relay-log=master2-relay-bin
master-host = IP_первого сервера
master-user = replication
master-password = password
master-port = 3306
slave-skip-errors = all
log-bin=mysql-bin
auto_increment_increment = 2
auto_increment_offset = 2

Перезагружаем MySQL на обоих серверах:

1
service mysqld restart

Проверить состояние репликации можно следующим образом:

1
mysql> SHOW SLAVE STATUS;

Вывод будет приблизительно следующий:

1
2
3
4
5
6
7
SHOW SLAVE STATUS;
+----------------------------------+----------------+-------------+-------------+---------------+------------------+---------------------+--------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+
| Slave_IO_State | Master_Host | Master_User | Master_Port | Connect_Retry | Master_Log_File | Read_Master_Log_Pos | Relay_Log_File | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error |
+----------------------------------+----------------+-------------+-------------+---------------+------------------+---------------------+--------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+
| Waiting for master to send event | IP_второго_сервера | replication | 3306 | 60 | mysql-bin.000008 | 106 | master1-relay-bin.000016 | 251 | mysql-bin.000008 | Yes | Yes | | | | | | | 0 | | 0 | 106 | 553 | None | | 0 | No | | | | | | 0 | No | 0 | | 0 | |
+----------------------------------+----------------+-------------+-------------+---------------+------------------+---------------------+--------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+
1 rows in set (0.03 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
show slave status \G
*************************** 1. row ***************************
Slave_IO_State : Waiting for master to send event
Master_Host : IP_второго_сервера
Master_User : replication
Master_Port : 3306
Connect_Retry : 60
Master_Log_File : mysql-bin.000008
Read_Master_Log_Pos : 106
Relay_Log_File : master1-relay-bin.000016
Relay_Log_Pos : 251
Relay_Master_Log_File : mysql-bin.000008
Slave_IO_Running : Yes
Slave_SQL_Running : Yes
Replicate_Do_DB :
Replicate_Ignore_DB :
Replicate_Do_Table :
Replicate_Ignore_Table :
Replicate_Wild_Do_Table :
Replicate_Wild_Ignore_Table :
Last_Errno : 0
Last_Error :
Skip_Counter : 0
Exec_Master_Log_Pos : 106
Relay_Log_Space : 553
Until_Condition : None
Until_Log_File :
Until_Log_Pos : 0
Master_SSL_Allowed : No
Master_SSL_CA_File :
Master_SSL_CA_Path :
Master_SSL_Cert :
Master_SSL_Cipher :
Master_SSL_Key :
Seconds_Behind_Master : 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno : 0
Last_IO_Error :
Last_SQL_Errno : 0
Last_SQL_Error :
1 rows in set (0.02 sec)

Настройка репликации завершена.

Настройка Leader DNS-сервера

Для начала установим BIND и его утилиты

1
yum install bind bind-utils -y

Затем необходимо сделать небольшие модификации в конфигурационном файле /etc/named.conf:

Заменяем 1.1.1.1 адресом первого сервера, 2.2.4.4 ip-адресом второго сервера:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//

options {
listen-on port 53 { 127.0.0.1; 1.1.1.1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
allow-query { localhost; any;};
allow-transfer { localhost; 2.2.4.4; };
recursion yes;

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

/* Path to ISC DLV key */
bindkeys-file "/etc/named.iscdlv.key";

managed-keys-directory "/var/named/dynamic";
};

logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};

zone "." IN {
type hint;
file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

listen-on можно закомментировать, чтобы он был доступен на всех интерфейсах;
recursion необходимо выключить, чтобы предотвратить сервер от DDoS-reflection;
allow-transfer директива добавляет второй сервер в whitelists и разрешает трансфер между ними;
allow-query меняем на any

Далее необходимо добавить новые зоны для первого домена, мы должны добавить следующие строки в named.conf ниже существующих зон.

1
2
3
4
5
6
7
8
9
10
11
zone"your-domain.com" IN {
type master;
file "/var/named/forward.your-domain.com";
allow-update { none; };
};

zone"4.2.2.in-addr.arpa" IN {
type master;
file "/var/named/reverse.your-domain.com";
allow-update { none; };
};

После сохранения named.conf с вышеуказанными изменениями, мы готовы создать файлы зон.

Cоздадим forward.your-domain.com в директории /var/named со следующим содержимым:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$TTL 300
@ IN SOA ns1.your-domain.com. root.your-domain.com. (
2014061200 ;Serial
300 ;Refresh
300 ;Retry
300 ;Expire
300 ;Minimum TTL
)
@ IN NS ns1.your-domain.com.
@ IN NS ns2.your-domain.com.
@ IN A 1.1.1.1
@ IN A 2.2.4.4
ns1 IN A 1.1.1.1
ns2 IN A 2.2.4.4

и reverse.your-domain.com в той же директории

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$TTL 300
@ IN SOA ns1.your-domain.com. root.your-domain.com. (
2014061200 ;Serial
300 ;Refresh
300 ;Retry
300 ;Expire
300 ;Minimum TTL
)
@ IN NS ns1.your-domain.com.
@ IN NS ns2.your-domain.com.
@ IN PTR your-domain.com.
ns1 IN A 1.1.1.1
ns2 IN A 2.2.4.4
1 IN PTR ns1.your-domain.com.
4 IN PTR ns2.your-domain.com.

Стартуем и добавляем в автозапуск named

1
2
chkconfig named on
service named start

Добавляем правила в /etc/sysconfig/iptables

1
2
-A INPUT -p udp -m state --state NEW --dport 53 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 53 -j ACCEPT

Перезапускаем iptables

1
service iptables restart

Проверяем конфигурацию и синтаксис зон

1
[root@Leader /]# named-checkconf /etc/named.conf
1
2
3
[root@Leader /]# named-checkzone your-domain.com /var/named/forward.your-domain.com 
zone your-domain.com/IN: loaded serial 2014061200
OK
1
2
3
[root@Leader /]# named-checkzone your-domain.com /var/named/reverse.your-domain.com 
zone your-domain.com/IN: loaded serial 2014061200
OK

Настройка Follower DNS-сервера

Для начала установим BIND и его утилиты

1
yum install bind bind-utils -y

Затем необходимо сделать небольшие модификации в конфигурационном файле /etc/named.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//

options {
listen-on port 53 { 127.0.0.1; 2.2.4.4; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
allow-query { localhost; any; };
recursion no;

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

/* Path to ISC DLV key */
bindkeys-file "/etc/named.iscdlv.key";

managed-keys-directory "/var/named/dynamic";
};

logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};

zone "." IN {
type hint;
file "named.ca";
};

zone"your-domain.com" IN {
type slave;
file "slaves/your-domain.com.fwd";
masters { 1.1.1.1; };
};

zone"1.1.1.in-addr.arpa" IN {
type slave;
file "slaves/your-domain.com.rev";
masters { 1.1.1.1; };
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

Добавляем демон в автозагрузку и запускаем

1
2
chkconfig named on
service named start

Теперь прямая и обратная зоны автоматически скопируются с Leader DNS-сервера в /var/named/slaves/, проверяем:

1
2
[root@Follower slaves]# ls 
your-domain.com.fwd your-domain.com.rev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# cat your-domain.com.fwd
$ORIGIN .
$TTL 300 ; 5 minutes
your-domain.com IN SOA ns1.your-domain.com. root.your-domain.com. (
2014061200 ; serial
300 ; refresh (5 minutes)
300 ; retry (5 minutes)
300 ; expire (5 minutes)
300 ; minimum (5 minutes)
)
NS ns1.your-domain.com.
NS ns2.your-domain.com.
A 1.1.1.1
A 2.2.4.4
$ORIGIN your-domain.com.
ns1 A 1.1.1.1
ns2 A 2.2.4.4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#cat nothing-special.ru.rev
$ORIGIN .
$TTL 300 ; 5 minutes
1.1.1.in-addr.arpa IN SOA ns1.your-domain.com. root.your-domain.com. (
2014061200 ; serial
300 ; refresh (5 minutes)
300 ; retry (5 minutes)
300 ; expire (5 minutes)
300 ; minimum (5 minutes)
)
NS ns1.your-domain.com.
NS ns2.your-domain.com.
PTR your-domain.com.
$ORIGIN 1.1.1.in-addr.arpa.
4 PTR ns2.your-domain.com.
1 PTR ns1.your-domain.com.
ns1 A 1.1.1.1
ns2 A 2.2.4.4

Добавляем информацию о новых DNS-серверах

1
2
3
4
5
6
cat << EOT > /etc/resovl.conf
search your-domain.com
nameserver 1.1.1.1
nameserver 2.2.4.4
nameserver 8.8.8.8
EOT

Проверяем

Проверяем Leader сервер

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
dig ns1.your-domain.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.23.rc1.el6_5.1 <<>> ns1.your-domain.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8141
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1

;; QUESTION SECTION:
;ns1.your-domain.com. IN A

;; ANSWER SECTION:
ns1.your-domain.com. 300 IN A 1.1.1.1

;; AUTHORITY SECTION:
your-domain.com. 300 IN NS ns1.your-domain.com.
your-domain.com. 300 IN NS ns2.your-domain.com.

;; ADDITIONAL SECTION:
ns2.your-domain.com. 300 IN A 2.2.4.4

;; Query time: 38 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Sun Jun 22 01:12:49 2014
;; MSG SIZE rcvd: 104

Проверяем Follower сервер

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
dig ns2.your-domain.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.23.rc1.el6_5.1 <<>> ns2.your-domain.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36189
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1

;; QUESTION SECTION:
;ns2.your-domain.com. IN A

;; ANSWER SECTION:
ns2.your-domain.com. 300 IN A 2.2.4.4

;; AUTHORITY SECTION:
your-domain.com. 300 IN NS ns1.your-domain.com.
your-domain.com. 300 IN NS ns2.your-domain.com.

;; ADDITIONAL SECTION:
ns1.your-domain.com. 300 IN A 1.1.1.1

;; Query time: 39 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Sun Jun 22 01:15:59 2014
;; MSG SIZE rcvd: 104
1
2
3
4
5
6
7
8
nslookup your-domain.com
Server: 1.1.1.1
Address: 1.1.1.1#53

Name: your-domain.com
Address: 1.1.1.1
Name: your-domain.com
Address: 2.2.4.4