# Rsync

## Rsync

## **Репликация файлов через rsync: мониторинг с помощью Zabbix**

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Linux/Rsync/cce18e419be29381533694fe2ab7cd78.png)

В [предыдущей статье](https://habr.com/ru/company/first/blog/690318/) мы рассказывали о том, как настроить и контролировать репликацию базы данных MySQL или MariaDB. Однако, если речь идет о создании отказоустойчивого интернет-магазина или аналогичного проекта, нужно реплицировать не только базу данных, но и файлы. Это могут быть файлы изображений товаров, html-страниц, стилей CSS, скрипты и другие файлы.

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

В этой статье мы расскажем, как настроить репликацию файлов при помощи программы rsync, а также как организовать мониторинг репликации файлов с помощью Zabbix.

Мы будем исходить из предположения, что файлы пользователя shopusr2 реплицируются с мастер-сервера host01master на резервный сервер host01slave.

При этом репликации подлежат все файлы из каталога /home/shopusr2/data, за исключением файлов, перечисленных в файле исключений, расположенном на резервном сервере host01slave.

#### **Установка программы rsync**

Для установки программы rsync в ОС Debian 11 используйте следующие команды:

```
# apt update
# apt install rsync
```

Чтобы узнать версию установленной программы, запустите ее с параметром --version:

```
# rsync --version
rsync  version 3.2.3  protocol version 31
```

Исходные коды программы можно загрузить на сайте <https://rsync.samba.org/>, а также здесь: <https://github.com/WayneD/rsync/>.

После установки rsync на мастер-сервере нужно отредактировать файл конфигурации /etc/rsyncd.conf. Также нужно создать файлы для ограничения доступа и для исключения из репликации файлов и каталогов, не требующих синхронизации между мастер-сервером и резервным сервером.

#### **Настройка на мастер-сервере**

На мастер-сервере, с которого будут копироваться файлы на резервный сервер, необходимо подготовить файл конфигурации /etc/rsyncd.conf, а также файлы паролей для реплицируемых пользователей.

Для файлов паролей установите владельцем пользователя root и укажите для атрибутов значение 0600.

#### **Подготовка файла конфигурации и файлов с паролями**

Создайте на мастер-сервере файл /etc/rsyncd.conf с таким содержимым:

```
uid = root
gid = root
use chroot = yes
max connections = 4
syslog facility = local5
[shopusr2]
        path = /home/shopusr2/data
        comment = shopusr2
        list = yes
        auth users = shopusr2
        secrets file = /home/shopusr2/data/rsyncd.secrets
```

Параметры **uid** и **gid** задают, соответственно, группу и пользователя, от имени которого будет выполнена синхронизация содержимого заданного каталога. В данном случае операции будут выполняться от имени пользователя root.

Параметр **use chroot** со значением yes предписывает программе rsync при выполнении операции менять корневой каталог на указанный в параметре **path**. Такое изменение выполняется из соображений безопасности.

Что же касается параметра **path**, то он задает путь к каталогу, для которого нужно выполнить синхронизацию файлов.

Для того чтобы не перегружать сервер в процессе репликации файлов, мы задали в файле конфигурации параметр **max connections**. Он задает максимальное количество одновременных подключений к сервису rsync, запущенному на мастер-сервере.

Параметр **syslog facility** задает уровень детализации сообщений от сервиса rsync для syslog. Можно указывать значения local0, local1, local2, local3, local4, local5, local6 и local7.

Далее в файле конфигурации /etc/rsyncd.conf должны следовать блоки определения синхронизируемых каталогов. В нашем случае это блок **\[shopusr2]**.

В нем задан путь **path** к каталогу /home/shopusr2/data, содержимое которого будет реплицироваться на сервер бекапов, произвольный комментарий **comment**, а также параметры **auth users** и **secrets file**, ограничивающие доступ к этому каталогу.

Параметр **list** позволяет просматривать список файлов и потребуется нам только для отладки.

Файл доступа на мастер-сервере /home/shopusr2/data/rsyncd.secrets должен содержать такую строку:

```
shopusr2:********
```

Здесь после двоеточия укажите пароль доступа, который будет нужен резервному серверу для подключения.

Установите для файла rsyncd.secrets владельца и права следующим образом:

```
# chown root:root /home/shopusr2/data/rsyncd.secrets
# chmod 0600 /home/shopusr2/data/rsyncd.secrets
```

После этого перезапустите сервис rsync и проверьте, что он работает:

```
# service rsync restart
# service rsync status
```

#### **Настройка файрвола на мастер-сервере**

Из соображений безопасности нужно ограничить доступ к порту 873 на мастер-сервере с помощью файрвола, разрешив его только для адреса IP резервного сервера.

#### **Настройка на резервном сервере**

На сервере реплики подготовьте для каждого реплицируемого пользователя файлы исключений и файлы паролей.

#### **Файл исключений**

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

```
.bash_history
.cache
.config
.filemgr-tmp
.local
.mc
.nano
.viminfo
.ssh
*.tar.gz
*.sql
*.xls
*.xlsx
bash_history
bin-tmp
cache
data
etc
logs
mod-tmp
php-bin
rsync.secrets
rsync
sphinx.socket
ssl
temp
test
tmp
```

Конечно, вам нужно будет самим определить содержимое файла исключений для своего сайта.

#### **Файл паролей**

Файлы паролей на резервном сервере должны содержать только строку пароля. Их нужно разместить в каталоге реплицируемого пользователя и назначить владельцем этого пользователя. Для нашего случая файл паролей находится здесь:

```
/home/shopusr2/data/rsync.secrets
```

Установите для файла паролей атрибут 0600:

```
# chmod 0600 /home/shopusr2/data/rsync.secrets
```

#### **Проверка репликации вручную**

Проверьте, что после запуска сервис rsync занял порт 873 на мастер-сервере:

```
# netstat -lupin | grep 873
tcp  0 0 0.0.0.0:873       0.0.0.0:*     LISTEN      22395/rsync
tcp6 0 0 :::873            :::*          LISTEN      22395/rsync
```

На время тестирования уберите символ комментария со строки list = yes в файле конфигурации /etc/rsyncd.conf на мастер-сервере и перезапустите rsync.

Далее на сервере реплики обратитесь к мастер-серверу по его адресу IP:

```
$ rsync xxx.xxx.xxx.xxx::
shopusr2 shopusr2
```

В ответ на эту команду на консоли появится список пользователей. В нашем случае здесь будет один пользователь shopusr2.

Просмотрите файлы от имени этого пользователя, указав пароль из файла rsync.secrets:

```
# sudo -u shopusr2 rsync xxx.xxx.xxx.xxx::shopusr2
Password:
```

На консоли появится список файлов, доступных для репликации:

```
drwxr-xr-x 4,096 2021/09/15 19:12:58 .
-rw------- 740 2021/09/07 15:33:36 .Xauthority
-rw------- 14,160 2021/09/15 19:12:58 .bash_history
-rw-r--r-- 289 2020/10/09 09:38:10 .bash_profile
-rw-r--r-- 11 2021/03/05 14:20:34 .fmsettings
-rw-r--r-- 53 2018/04/30 10:34:03 .gitconfig
-rw------- 102 2021/06/28 14:08:51 .lesshst
-rw------- 1,773 2020/12/03 00:53:11 .mysql_history
...
drwxr-x--x 4,096 2018/08/11 12:32:25 php-bin
drwxr-xr-x 4,096 2021/03/05 14:21:02 ssl
drwxr-xr-x 4,096 2020/02/14 10:20:16 temp
drwxr-xr-x 4,096 2021/09/08 14:59:54 www
```

После этого проверьте работу команды репликации:

```
# sudo -u shopusr2 /usr/bin/rsync -urltvvv --delete-after --password-file=/home/shopusr2/data/rsync.secrets shopusr2@ xxx.xxx.xxx.xxx::shopusr2 /home/shopusr2/data --exclude-from /home/ shopusr2/rsync/exclude_shopusr2.txt --bwlimit=6000 > /home/shopusr2/data/rsync/rsync_log.txt
```

Параметры этой команды описаны в следующем разделе этой статьи. Результат выполнения синхронизации будет записан в журнал rsync\_log.txt.

#### **Программа запуска и контроля репликации**

Для запуска и контроля результатов выполнения репликации файлов мы используем программу run\_rsync\_free.pl, доступную здесь: [ссылка на GitHub](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/run_rsync_free.pl).

Вам необходимо отредактировать программу, указав адрес IP и домены своих серверов. Кроме того, вместо сервиса keepalived вы можете использовать другие средства переключения с мастер-сервера на сервер бекапов, и это тоже необходимо учесть при подготовке своей программы репликации и мониторинга.

#### **Проверка хоста и его состояния**

Сразу после запуска программа проверяет, что она работает на резервном сервере, и этот сервер находится в состоянии BACKUP. Для этого программа определяет имя хоста, а также проверяет содержимое файла node\_keepalive\_state.txt, в который сервис keepalived записывает состояние хоста:

```
my $node_keepalive_state_file = '/home/shopusr/node_keepalive_state.txt';
my $state_file_content = read_file($node_keepalive_state_file);
my $host = hostname;
if($host eq 'host01slave.domain.ru' and $state_file_content=~/INSTANCE_myshop_BACKUP/)
{
  if( $debug) { print "do replication \n"; }
  …
}
else
{
  print 'Can run files replication only for BACKUP state and for host host01slave.domain.ru'."\n";
  print 'Host: '.$host.', state: '.$state_file_content."\n";
}
```

Если имя хоста определилось как host01slave.domain.ru, а файл состояния keepalived содержит строку «INSTANCE\_myshop\_BACKUP», запускается процесс репликации. В противном случае репликация не выполняется, а на консоль выводится сообщение об ошибке.

#### **Запуск репликации файлов**

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

```
my $lock_file = '/tmp/.rsync_lock';
sub _locked
{
  return 1 if ( -e $lock_file );
}
sub _lock
{
  open( FILE, ">$lock_file" );
  close FILE;
}
sub _unlock
{
  unlink($lock_file);
}
```

Функция do\_sync запускает программу /usr/bin/rsync, которая синхронизирует файлы:

```
sub do_sync($$)
{
  my ($user, $master_server_ip) = @_;
  my $begin = time();
  my $log='/home/'.$user.'/data/rsync/rsync_log.txt';
  my $cmd = 'sudo -u '.$user.' /usr/bin/rsync -urltvvv --delete-after --password-file=/home/'
.$user.'/data/rsync.secrets '.$user.'@'.$master_server_ip.'::'.$user.' /home/'.$user.'/data --exclude-from /home/shopusr2/data/rsync/exclude_'.$user.'.txt --bwlimit=6000 > '.$log;
  my @rqout = ();
  @rqout = split /\n/, `$cmd`;
  my $status;
  my $rc;
  my $rsync_rc = $?;
  if($rsync_rc == 0)
  {
    $status = analyze_log($log);
    $rc="ok";
  }
  else
  {
    $rc=$rsync_rc;
  }
  my $end = time();
  my $diff = $end - $begin;
  return {'rc' => $rc, 'sync_status_from_log' => $status, 'sync_duration' => $diff, 'user' => $user,  'master_server_ip' => $master_server_ip};
}
```

В качестве параметров этой функции нужно передать имя пользователя, для которого выполняется репликация файлов, а также адрес IP мастер-сервера.

При запуске rsync мы используем следующие параметры:

* u — нужно выполнять только обновление файлов, но не перезаписывать обновленные файлы;
* r — обрабатывать каталоги рекурсивно;
* l — сохранять ссылки;
* t — сохранять информацию о дате и времени файла;
* vvv — выводить информацию о результатах работы в подробном виде;
* delete-after — удалять файлы завершения передачи;
* password-file — взять пароль из файла, указанного в этом параметре;
* exclude-from — взять список исключений из файла, указанного в этом параметре;
* bwlimit — ограничить скорость передачи данных значением, указанным в Кбайт/c.

Полный список параметров программы rsync можно посмотреть, например, [здесь](http://www.opennet.ru/man.shtml?category=1\&russian=0\&topic=rsync).

Если копирование файлов завершилось успешно, то подробный журнал копирования будет записан в переменную $log для дальнейшего анализа функцией analyze\_log. В противном случае сообщение об ошибке будет сохранено в переменной $rc.

Функция do\_sync возвращает хэш с кодом завершения rc, результатом анализа журнала синхронизации файлов sync\_status\_from\_log, длительностью процесса синхронизации sync\_duration, а также именем пользователя user и адресом IP мастер-сервера master\_server\_ip.

#### **Анализ результатов синхронизации файлов**

Задачей функции analyze\_log является разбор файла журнала, созданного программой rsync в процессе синхронизации файлов. В ходе разбора функция отыскивает сообщения об ошибках, отфильтровывая «безобидные» сообщения:

```
sub analyze_log
{
  my ($log) = @_;
  my $action = {};
  my $errors = [];
  my $rc={};
  open( FILE, "<$log" );
  while (<FILE>)
  {
    if (m/recv_file_name/)
    {
      $action->{ recv_file_name }++;
    }
    elsif (m/recv_generator/)
    {
      $action->{ recv_generator }++;
    }
    elsif (m/recv_files/)
    {
      $action->{ recv_files }++;
    }
    elsif (m/is\suptodate/)
    {
      $action->{ is_uptodate }++;
    }
    elsif (m/\[generator\]\smake_file/)
    {
      $action->{ make_file }++;
    }
    elsif (m/delete_in_dir/)
    {
      $action->{ delete_in_dir }++;
    }
    elsif (m/Permission\sdenied/)
    {
      $action->{ permission_denied }++;
      push @$errors, $_;
    }
    elsif (m/is\snewer/)
    {
      $action->{ is_newer }++;
      push @$errors, $_;
    }
    elsif(m/opening\stcp\sconnection/
          || m/Connected\sto/
          || m/sending\sdaemon\sargs/
          || m/receiving\sfile\slist/
          || m/expand\sfile_list/
          || m/received\s\d+\snames/
          || m/done/
          || m/recv_file_list\sdone/
          || m/get_local_name\scount/
          || m/generator\sstarting\spid/
          || m/\[generator\]\spushing\slocal\sfilters\sfor/
          || m/\[generator\]\sprotecting\sfile/
          || m/\[generator\]\sprotecting\sdirectory/
          || m/\[generator\]\spopping\slocal\sfilters/
          || m/delta-transmission\senabled/
          || m/generate_files\sphase/
          || m/deleting\sin/
          || m/generate_files\sfinished/
          || m/sent\s\d+([\.,]\d+)*\sbytes/
          || m/total\ssize\sis/
          || m/_exit_cleanup/
          || m/set\smodtime\sof/
          || m/got\sfile_sum/
          || m/renaming/
          || m/delete_item/
          || m/deleting\s/
          || m/generating\sand\ssending\ssums/
          || m/count=/
          || m/recv\smapped/
          || m/parse_filter_file/
          || m/add_rule/

          # упоминания файлов и папок
          || m/^[^(\s]+$/ # любые символы кроме скобок и пробелов (это имя папки или файла)
          )
    {
      # nothing to do
    }
    # все остальное считаем ошибками
    else
    {
      $_ =~ s/^[\s\n\r\t]+//;
      $_ =~ s/[\s\n\r\t]+$//;
      if ($_)
      {
        $action->{ $_ }++;
        push @$errors, $_;
      }
    }
  }
  if ( scalar @$errors )
  {
    return { 'rc' => 'error', 'errors' => $errors };
  }
  return { 'rc' => 'ok', 'action' => $action };
}
```

Если ошибок не обнаружено, функция записывает в поле rc возвращаемого хэша строку «ok», а через хэш action передает статистику по выполненным действиям.

При ошибке в поле rc записывается строка «error», а в поле errors — ссылка на массив ошибок.

#### **Подготовка данных для отправки в Zabbix**

На следующем этапе наша программа записывает в хэш $sync\_info информацию для отправки в Zabbix:

```
my $sync_info;
my $shopusr2_error_rc = 0;
if($sync_info-> { rc } ne 'ok')
{
  $shopusr2_error_rc = 1;
}
my $shopusr2_warning_rc = $sync_info->{sync_status_from_log }->{ rc };
if($shopusr2_warning_rc eq 'error')
{
  $shopusr2_warning_rc = 1;
}
else
{
  $shopusr2_warning_rc = 0;
}
my $shopusr2_sync_duration = $sync_info-> { sync_duration };
```

Прежде всего, при ошибке в переменную $shopusr2\_error\_rc записывается значение 1, а если команда rsync отработала правильно, то значение 0.

Если же ошибка была обнаружена в результате анализа журнала функцией analyze\_log, то эта ситуация рассматривается как предупреждение. В переменную $shopusr2\_warning\_rc при этом записывается значение 1.

Появление предупреждения означает, что нужно проанализировать журнал выполнения программы rsync. При этом следует понять, насколько критична ошибка и как ее можно устранить. Если ошибка не критична, можно добавить соответствующий фильтр в функцию analyze\_log. Возможно, потребуется отредактировать файл исключений.

И, наконец, в переменную $shopusr2\_sync\_duration записывается длительность выполнения команды синхронизации файлов.

#### **Отправка результатов репликации в Zabbix**

Для отправки данных в Zabbix используется программа zabbix\_sender. Для этой программы подготавливается файл с данными, который затем отправляется на все серверы Zabbix:

```
open(my $fh, '>', $zabbix_sender_data_file) or die "Не могу открыть '$zabbix_sender_data_file' $!";
print $fh $hostname." shopusr2_sync.Error ".$shopusr2_error_rc."\n";
print $fh $hostname." shopusr2_sync.Warning ".$shopusr2_warning_rc."\n";
print $fh $hostname." shopusr2_sync.SyncDuration ".$shopusr2_sync_duration."\n";
close $fh;

my @zabbix_server_ip_array = split(',', $zabbix_server_ip);
foreach my $server_ip (@zabbix_server_ip_array)
{
  my $trap_cmd = $zabbix_sender.' -vv -z '.$server_ip.' -i '.$zabbix_sender_data_file;
  if ($debug) {
     print "Trap cmd: ".$trap_cmd."\n";
  };
  my @trapout = ();
  @trapout = split /\n/, `$trap_cmd`;
  if ($debug) { print Dumper(\@trapout); }
}
```

Адреса серверов Zabbix передаются программе run\_rsync\_free.pl при ее запуске в качестве параметра.

#### **Запуск программы синхронизации через crontab**

Для запуска программы run\_rsync\_free.pl каждые 10 минут вы можете использовать такое задание crontab:

```
*/10 * * * * /usr/bin/perl /home/shopusr2/data/run_rsync_free.pl xxx.xxx.xxx.xxx,yyy.yyy.yyy.yyy host01slave
```

Здесь вместо xxx.xxx.xxx.xxx и yyy.yyy.yyy.yyy укажите адреса ваших серверов Zabbix через запятую.

#### **Шаблон для Zabbix**

Мы подготовили шаблон мониторинга репликации файлов для Zabbix (рис. 1), доступный здесь: [ссылка на GitHub](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/shop2you_rsync_template.xml).

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Linux/Rsync/4fe1a6927f341940fa4688c6c458d471.png)

Рис. 1. Шаблон мониторинга репликации файлов для Zabbix

В шаблоне определены метрики для обнаружения ошибок и предупреждений, появляющихся в процессе репликации, а также для контроля времени, необходимого для выполнения репликации.

Также в шаблоне предусмотрены триггеры, показанные на рис. 2.

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Linux/Rsync/0bfe6368fc9f0ab46cbd83d6b977ca4b.png)

Рис. 2. Триггеры шаблона мониторинга репликации файлов

Эти триггеры срабатывают, если возникают ошибки и предупреждения, а также если данные мониторинга репликации не поступают на сервер Zabbix слишком долго.

*Автор: Александр Фролов.*
