Ads 468x60px

понедельник, 15 октября 2012 г.

Debian squezee. High availability система на Dovecot + Exim

Исходные данные.
Задача: создать резервный почтовый сервер, который будет подхватывать роль основного, при выходе из строя главного.
Дано:
Два сервера mail01 и mail02 с настроенной связкой dovecot 2.0 exim 4.72.
ПО для организации кластера heartbeat.
Синхронизация imap папок средствами dsync из пакета Dovecot 2.
Синхронизация фалов параметров exim и dovecot средствами rsync.
База данных (postgresql) пользователей синхронизируется средствами Slony.
сетевые интерфейсы.
Три IP адреса, два персональных для каждого сервера и третий общий, будет подниматься на резервном в случае падения основного сервера.
cluster IP 192.168.30.11
mail01:
eth1 192.168.30.14
mail02:
eth3 192.168.30.13
общая схема.
                                      {Internet}
                                    192.168.30.11
                               +----------+----------+
                           +---+---+ {heartbeat} +---+---+
                           |  eth1 |             |  eth3 |
                           |       |             |       |
                           | mail01|   {dsync}   | mail02|
                           +-------+ - - - - - - +-------+
Настройка кластера по IP.
Установка ПО.
Команды выполняемые на каждом сервере:
$ sudo aptitude update
$ sudo aptitude upgrade
$ sudo aptitude install heartbeat
Настройка heartbeat
На сервере mail01:
Создание основного файла конфигурации
mail01$ sudo gunzip /usr/share/doc/heartbeat/ha.cf.gz
mail01$ sudo cp /usr/share/doc/heartbeat/ha.cf /etc/ha.d/
Указание интерфейса, на котором heartbeat будет работать с общим IP
mail01$ sudo sed -i "s/#bcast\teth0/bcast\teth1/" /etc/ha.d/ha.cf; cat /etc/ha.d/ha.cf | grep bcast
список задействованных серверов, после node должен быть результат вывода команды uname -n, для основного и резервного сервера соответственно:
mail01$ sudo sed -i 's/#node.*$/node mail01/' /etc/ha.d/ha.cf
mail01$ sudo sed -i '0~2 s/node.*$/node mail02/' /etc/ha.d/ha.cf; cat /etc/ha.d/ha.cf | grep node
Файл совместной аутентификации серверов
mail01$ sudo cp /usr/share/doc/heartbeat/authkeys /etc/ha.d/
mail01$ sudo sed -i "s/#auth\s1/auth 3/" /etc/ha.d/authkeys; cat /etc/ha.d/authkeys | grep aut
secret - заменить на ваш пароль
mail01$ sudo sed -i "s/#3.*/3 md5 secret/" /etc/ha.d/authkeys; cat /etc/ha.d/authkeys | grep md5
mail01$ sudo chmod 600 /etc/ha.d/authkeys
файл ресурсов (в нашем случае IP адрес):
mail01$ echo "mail01 IPaddr::192.168.30.11/24/eth1" > haresources
mail01$ sudo mv haresources /etc/ha.d
Переносим основной и файл аутентификации на второй сервер:
mail01$ scp /etc/ha.d/ha.cf user@mail02:
mail01$ sudo scp /etc/ha.d/authkeys user@mail02:
На сервере mail02:
переносим файлы в директорию /etc/ha.d/
mail02$ sudo mv ha.cf /etc/ha.d/
mail02$ sudo mv authkeys /etc/ha.d/
изменяем интерфейс в основном файле настроек
mail02$ sudo sed -i "s/bcast\teth1\t/bcast\teth3\t/" /etc/ha.d/ha.cf;cat /etc/ha.d/ha.cf | grep bcast
файл ресурсов
mail02$ echo "mail01 IPaddr::192.168.30.11/24/eth3" > haresources
mail02$ sudo mv haresources /etc/ha.d
Стартуем службу на каждом сервере:
$ sudo service heartbeat start
Синхронизация.
Общесистемные настройки.
1. Даем пользователю, под которыми будет выполняться синхронизация, право без пароля выполнять sudo rsync и sudo dsync, добавляем следующее в /etc/sudoers на master сервере:
# Host alias specification
Host_Alias      MAILHOST=mail01,mail02

# Cmnd alias specification
Cmnd_Alias MAILSYNC=/usr/bin/rsync,/usr/bin/dsync

# User privilege specification
mailuser4sync       MAILHOST=(root) NOPASSWD:MAILSYNC
2. На slave машине, под пользователем mailuser4sync создаем ключ для ssh и копируем его на master:
$ ssh-keygen -t rsa -b 2048 -f .ssh/key4mailsync
$ ssh-copy-id -i .ssh/key4mailsync.pub mailuser4sync@master
Почтовых папок.
3. В dovecot есть вариант настройки встроенной репликации: replication howto, но у меня не пошло. Поэтому я сделал скрипт mailboxsync.pl для синхронизации при помощи dsync, который помещаем в домашнюю папку mailuser4sync на slave:
#!/usr/bin/perl
#mailboxsync.pl
use warnings;
use strict;
use DBI; # подключаем класс работы с базами

# строка путь к ssh ключу
my $ssh='ssh -i /home/mailuser4sync/.ssh/key4mailsync';
# параметры удаленной машины
my $remoteuser="mailuser4sync";
my $remotehost="mail01";
my $remotecmd="sudo /usr/bin/dsync";
# имя базы, имя пользователя базы, пароль 
my ($dbname,$dbuser,$dbpass) = ('vmail','vmail','secret');

# подключение к локальнoй базе
 my $dbh = DBI->connect("dbi:Pg:dbname=$dbname", $dbuser, $dbpass,
                         { RaiseError => 1,  # в случае ошибки на строне базы данных прерывать работу perl
                          AutoCommit => 0 }) # отключение автоматической фиксации изменнений
             or die $DBI::errstr;
# пример выбоки данных
my $sth=$dbh->prepare("Select username From users order by username");
$sth->execute();
my $users = $sth->fetchall_arrayref();
$sth->finish();
 $dbh->disconnect();
# формируем массив пользователей 
my @userList;
$userList[$#userList+1] = $_->[0] foreach @$users;
my $totalUsers = scalar @userList;
# количесвто ящиков в одном потоке
my $cnt4fork = 5;
# количество потоков
my $numFork = int $totalUsers/$cnt4fork;
$numFork = 1 if $cnt4fork > $totalUsers;

foreach my $i (1..$numFork) {
    my $pid = fork();
    if ($pid) {
        # parent
        waitpid($pid,0);
    } elsif ($pid == 0) {
        # child
        my $startUser = ($i-1)*$cnt4fork;
        my $endUser = ($i)*$cnt4fork-1;
        $endUser = $totalUsers-1 if $i == $numFork;
        foreach my $j($startUser..$endUser){
            system('/usr/bin/dsync',"-u$userList[$j]","mirror","$ssh $remoteuser\@$remotehost $remotecmd -u$userList[$j]");
        }
        exit(0);
    } else {
        die "couldn’t fork: $!\n";
    }
}

Файлов конфигурации.
4. Так же на slave машине в домашней папке пользователя mailuser4sync создаем скрипт для синхронизации mailetcsync.sh:
#!/bin/bash
# проводим синхронизацию и считаем количество переданных файлов
CNT=$(rsync --stats -a --delete -e 'ssh -i /home/mailuser/.ssh/key4mailsync' --rsync-path='sudo rsync' bear@debmail03:/etc/dovecot/ /etc/dovecot/ | grep 'files transferred' | awk '{print $5}')
# если передача данных состоядась то рестартуем службу
if [ $CNT -ge 1 ]
then service dovecot restart
fi
CNT=$(rsync --stats -a --delete -e 'ssh -i /home/mailuser/.ssh/key4mailsync' --rsync-path='sudo rsync' bear@debmail03:/etc/exim4/ /etc/exim4/ | grep 'files transferred' | awk '{print $5}')
if [ $CNT -ge 1 ]
then service exim4 restart
fi
Настройки cron.
5. Список задач от имени root в крон на slave:
$ sudo crontab -l
на выходе должно быть примерно следующее
# m h dom mon dow command
0 * * * * /home/mailuser4sync/mailetcsync.sh
*/15 * * * * /home/mailuser4sync/mailboxsync.pl
Примечание. Для корректного использования ssl соединений, необходимо синхронизировать файлы сертификатов.

Комментариев нет: