Настройка синхронизации файлов между серверами с помощью SyncThing

SyncThing — программное обеспечение, которое позволяет выполнять синхронизацию файлов между серверами по P2P протоколу. Очень важно, что в своей работе SyncThing опирается на подсистему inotify, которая позволяет мгновенно реагировать на операции над файлами и каталогами, чтобы обеспечить минимальную задержку синхронизации, что особенно важно при наличии большого количества файлов в каталоге.

Использование пирингового протокола хорошо подходит для синхронизации между несколькими узлами, при этом автообнаружение новых узлов делает процесс добавления новых узлов тривиальным.

Задача

Синхронизация файлов между серверами — часто востребованная задача, которая наиболее просто решается с помощью Rsync. Однако, в некоторых случаях использование rsync затруднено. Например, это может быть ситуация, когда требуется как можно быстрее осуществить синхронизацию, а обработка по расписанию не подходит. В этом случае на помощь приходят утилиты, которые используют inotify — специализированный интерфейс Linux, позволяющий реагировать на изменения в файловой системе.

В более сложных конфигурациях в группе может быть несколько серверов, тогда настройка синхронизации «каждый с каждым» весьма утомительна — при добавлении к группе из N серверов еще одного, вам необходимо произвести 2xN настроек — на каждом из существующих серверов с новым и на новом сервере с существующими. Конечно, эта задача может быть автоматизирована с помощью средств управления инфраструктурой как кодом (Ansible, Chef, Puppet), но само решение, где необходимо настраивать взаимосвязь каждый с каждым выглядит весьма неудобно.

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

Далее мы рассмотрим, как с помощью SyncThing настроить синхронизацию файлов между несколькими серверами. Мы будем использовать операционную систему Linux. Руководство подойдет для любого дистрибутива, который использует systemd — Debian 9, Ubuntu 16.04, Ubuntu 18.04, CentOS 7 и т.п.

Как работает SyncThing

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

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

Задержка синхронизации. Для оптимизации производительности SyncThing задерживает синхронизацию (по умолчанию — 10 секунд), что может быть изменено, но установить задержку меньше 1 секунды невозможно.

Принцип работы. После старта серверы могут обнаруживать друг друга. Для добавления пира и обнаружения общих каталогов вы должны добавить его ID на другие серверы.

Установка SyncThing

Установка в Linux осуществляется скачиванием программного обеспечения:

wget https://github.com/syncthing/syncthing/releases/download/v1.1.1/syncthing-linux-amd64-v1.1.1.tar.gz

tar xzf syncthing-linux-amd64-v1.1.1.tar.gz

cd syncthing-linux-amd64-v1.1.1/

sudo cp syncthing /usr/local/sbin

Будем считать, что мы планируем синхронизировать сессии PHP, которые хранятся в каталоге /var/www/tmp. Сам каталог /var/www принадлежит пользователю www-data (Ubuntu, Debian) или nginx (CentOS).

Создадим файл для запуска SyncThing через systemd:

sudo tee /etc/systemd/system/syncthing.service >/dev/null

[Unit]
Description=Syncthing - Open Source Continuous File Synchronization
Documentation=man:syncthing(1)
After=multi-user.target network.target

[Service]
User=www-data
ExecStart=/usr/bin/env HOME=/var/www /usr/local/sbin/syncthing -home /var/www/syncthing -gui-address 0.0.0.0:8384
Restart=on-failure
SuccessExitStatus=3 4
RestartForceExitStatus=3 4

# Hardening
ProtectSystem=full
PrivateTmp=true
SystemCallArchitectures=native
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Ctrl^D

Для CentOS установите атрибут User= в значение nginx. Теперь включим созданную службу и запустим ее:

# убедимся, что права правильные
# Ubuntu, Debian
sudo chown -R www-data:www-data /var/www

# CentOS
sudo chown -R nginx:nginx /var/www

sudo systemctl enable syncthing.service
sudo systemctl start syncthing.service

Теперь вы можете зайти с помощью браузера на ваш сервер http://server.com:8384/, где сможете выполнить дальнейшую настройку SyncThing.

Задание имени и пароля администратора

На этом шаге мы обеспечим безопасность SyncThing, задав имя и пароль для администратора.

Сохраните форму и обновите страницу в браузере. Интерфейс попросит вас ввести имя пользователя и пароль. После ввода вы попадете в интерфейс.

Удаление каталога, созданного по-умолчанию

Поскольку мы хотим синхронизировать файлы только определенного каталога, текущий автоматически созданный каталог нам не нужен и мы его удалим.

Выполните все вышеприведенные настройки на каждом из узлов.

Создание пиринговой группы

Добавим все серверы в пиринговую группу, чтобы между ними могла производиться синхронизация данных. Данную операцию необходимо выполнить на всех узлах. После формирования группы серверы могут начать сами «проситься» на добавление к других хостам, что уменьшает количество «ручных» операций.

Определите ID каждого сервера. Для добавления серверов необходимо знать их ID, чтобы не добавить случайно посторонние серверы.

Добавьте все серверы в группу удаленных устройств, нажав на кнопку «Добавить удаленное устройство«.

Далее, для каждого удаленного устройства выполните настройку «автопринятия» каталогов. Это позволит узлам автоматически уведомлять другие узлы о доступных каталогах:

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

Задание синхронизируемого каталога

Зайдите на любой из серверов и задайте новый каталог для синхронизации, с помощью кнопки «Добавить папку«.

Два других сервера получат сообщения о желании первого сервера синхронизировать файлы с ними:

Теперь содержимое /var/www/tmp будет синхронизироваться между серверами.

Тестирование синхронизации

На первом сервере создайте файл server1

# для CentOS используйте
USERNAME=nginx
# для Ubuntu, Debian используйте
USERNAME=www-data

sudo runuser -u $USERNAME -- touch /var/www/tmp/server1

На двух других серверах убедитесь, что он синхронизировался. По умолчанию задержка синхронизации — 10 секунд, возможно придется подождать окончания синхронизации:

ls -la /var/www/tmp
итого 12
drwxr-xr-x 3 www-data www-data 4096 апр 19 03:34 .
drwxr-xr-x 6 www-data www-data 4096 апр 19 03:29 ..
-rw-r--r-- 1 www-data www-data    0 апр 19 03:33 server1
drwxr-xr-x 2 www-data www-data 4096 апр 19 03:29 .stfolder

Повторите этот тест на двух других серверах, создавая файлы server2 и server3.

Тестирование Отказа

Проверим, что без первого сервера все продолжает работать. Остановим его:

sudo systemctl stop

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

Уменьшение задержки синхронизации

Если вы желаете уменьшить время, на которое задерживается синхронизация, откройте файл конфигурации SyncThing и исправьте параметр fsWatcherDelayS=»10″ до нужного вам значения, например, до 1 секунды. Выполните эту операцию на каждом узле и перезапустите сервис SyncThing:

sudo systemctl restart syncthing.service

Дальнейшие шаги

Настройка SyncThing завершена, теперь необходимо обеспечить большую защиту и лучшую работу приложения.

Перенос GUI за Nginx

Теперь вы можете поместить пользовательский интерфейс SyncThing за обратный прокси-сервер Nginx с сертификатом Let’s Encrypt:

Для того, чтобы пользователи не могли соединяться непосредственно с GUI мимо Nginx, отредактируйте файл /etc/systemd/system/syncthing.service и замените 0.0.0.0:8384 на 127.0.0.1:8384. После этого выполните перезагрузку сервиса:

sudo systemctl daemon-reload
sudo systemctl restart syncthing.service

Настройка лимита Inotify

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

sysctl fs.inotify.max_user_watches
fs.inotify.max_user_watches = 8192

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

sysctl fs.inotify.max_user_watches
fs.inotify.max_user_watches = 524288