FreeBSD virtual environment management and repository

2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !

Внимание! Данные страницы описывают CBSD версии 13.0.x. Если вы используете более раннюю версию, рекомендуется сначала обновиться.

Синхронизация jail окружений через csync2 и модуль CBSD csync2

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

для доставки конфигурационных файлов. Также можете выбрать Ceph, ClusterFS и им подобных для репликации бинарных данных или целых файловых систем; вы можете использовать HASTD или ZFS Send для блочной и дискретной репликации. Но все еще остаются кейсы, когда вместо сложных и монструозных решений, идеально подходят старые добрые легковесные утилиты для синхронизации данных, такие как csync2 или lsyncd.

Конечно, они не годятся для синхронизации нескольких тысяч файлов или высоконагруженных на запись окружений. Но с ситуациями, когда вам необходимо синхронизировать контейнера с небольшим количеством файлов и редкой записью, подобные утилиты справляются идеально. К примеру, у вас есть jail контейнер, обслуживающий статические файлы для WEB сервера и вы хотите с помощью синхронизации растиражировать окружения в большом количестве. Модуль csync2 для CBSD является скриптом-оберткой для более комфортного менеджмента конфигурационного файла программы csync2, когда вам необходимо синхронизировать контейнеров на базе jail.

Как это работает: в системном CBSD каталоге каждого jail вы можете сопровождать любую конфигурацию для csync2, описывающую списки файлов и директорий контейнера для синхронизаций (или их исключения). Команда 'cbsd csync2' запускается каждую минуту из cron, склеивает эти файлы в один одноименный оригинальный конфигурационный файл /usr/local/etc/csync2.cfg и в зависимости от необходимой частоты синхронизации (может настраиваться для каждого контейнера индивидуально), запускает утилиту csync2 для того или иного контейнера.

В качестве примера, давайте создадим два синхронизируемых контейнера с именами 'repl1' и 'repl2' между двумя нодами CBSD.


1) Выполняем установку пакета csync2 и модуля 'cbsd csync2' на обеих нодах:

pkg install -y csync2
cbsd module mode=install csync2
echo 'csync2.d' >> ~cbsd/etc/modules.conf
cbsd initenv


2) Скопируем пример конфигурационного файла модуля в рабочий каталог CBSD:

cp /usr/local/cbsd/modules/csync2.d/etc/csync2.conf ~cbsd/etc/

Конфигурационный файл небольшой и позволяет оперировать параметрами:

## Каталог для логирования:
CSYNC2_CBSD_LOG_DIR="/var/log/cbsd-csync2"

## Глобальный csync2 ключ:
CSYNC2_CBSD_KEY="/usr/local/etc/cbsd_csync2.key"

## Путь к программе csync2 в системе
CSYNC2_CMD="/usr/local/sbin/csync2"

## Глобальный конфигурационный файл csync2, который в нашем случае будет автоматически генерируемым CBSD модулем csync2
CSYNC2_CFG_FILE="/usr/local/etc/csync2.cfg"

## Частота запуска операции синхронизации (не путать с частотой запуска 'cbsd csync2' модуля из crontab - см. ниже
## По-умолчанию, выполняем одну синхронизацию в 10 минут, но если вы хотите для некоторых контейнеров иметь другую частоту, используйте
## файл ~cbsd/jails-system/%jail%/etc для установки индивидуального для %jail% значения.
CSYNC2_CBSD_RUN_INTERVAL="10"


3) Создадим контейнера 'repl1' и 'repl2' на обеих нодах. Имена одинаковые, но будем использовать непересекающиеся IP адреса, поскольку в нашем случае сервера расположены в одном сегменте.

node1# cbsd jcreate ip4_addr=10.0.100.144 jname=repl1 runasap=1
node1# cbsd jcreate ip4_addr=10.0.100.145 jname=repl2 runasap=1

node2# cbsd jcreate ip4_addr=10.0.100.146 jname=repl1 runasap=1
node2# cbsd jcreate ip4_addr=10.0.100.147 jname=repl2 runasap=1


4) На каждом сервере для каждого контейнера сформируем /usr/jails/jails-system/%jail%/csync2.cfg конфигурационный файл, описывающий директории контейнеров для синхронизации. Мы будем реплицирировать весь контейнер, за исключением каталога /var/run/ где хранятся PID процессов и не будем синхронизировать логи, содержимое файлов которых уникальны для каждого контейнера, поскольку мы планируем что все контейнера будут работать. На node1: для контейнера 'repl1' и при условии, что cbsd_workdir установлен в каталог /usr/jails:


cat > /usr/jails/jails-system/repl1/csync2.cfg <<EOF
        host node1.my.domain;
        host node2.my.domain;

        include /usr/jails/jails-data/repl1-data;
        include /usr/jails/jails-system/repl1/csync2.cfg;
        exclude /usr/jails/jails-data/repl1-data/var/spool/clientmqueue;
        exclude /usr/jails/jails-data/repl1-data/var/log/*;
        exclude /usr/jails/jails-data/repl1-data/var/log/*/*.log;
        exclude /usr/jails/jails-data/repl1-data/var/run/*;
        exclude /usr/jails/jails-data/repl1-data/tmp/*;

        action
        {
                pattern /usr/jails/jails-data/repl1-data/usr/local/etc/nginx/*;
                exec "/usr/local/bin/cbsd service jname=repl1 mode=action nginx reload";
                logfile "/usr/jails/jails-system/repl1/csync2.actions.log";
                do-local;
        }

        auto younger;
EOF

такой же конфиг для контейнера 'repl2' с соответствующей разницей в путях директорий:


cat > /usr/jails/jails-system/repl2/csync2.cfg <<EOF
        host node1.my.domain;
        host node2.my.domain;

        include /usr/jails/jails-data/repl2-data;
        include /usr/jails/jails-system/repl2/csync2.cfg;
        exclude /usr/jails/jails-data/repl2-data/var/spool/clientmqueue;
        exclude /usr/jails/jails-data/repl2-data/var/log/*;
        exclude /usr/jails/jails-data/repl2-data/var/log/*/*.log;
        exclude /usr/jails/jails-data/repl2-data/var/run/*;
        exclude /usr/jails/jails-data/repl2-data/tmp/*;

        action
        {
                pattern /usr/jails/jails-data/repl2-data/usr/local/etc/nginx/*;
                exec "/usr/local/bin/cbsd service jname=repl2 mode=action nginx reload";
                logfile "/usr/jails/jails-system/repl2/csync2.actions.log";
                do-local;
        }

        auto younger;
EOF
Обратите внимание на 'node1.my.domain' и 'node2.my.domain' - это должны быть IP адреса или корректные DNS имена ваших CBSD хостов. Кроме этого, мы используем специальную директиву 'action' в качестве примера,которая будет перезагружать сервис nginx в нужном контейнере, если при синхронизации где-то были модифицированы конфигурационные файлы HTTP сервера 'nginx', который в нашем случае запущен в каждом контейнере.


5) Повторяем полностью аналогичную настройку из пункта '4' на второй ноде.


6) Сгенерируем на любой из наших хостов глобальный ключ csync2 путем запуска скрипта:

cbsd csync2

Если файл /usr/local/etc/cbsd_csync2.key отсутствует (параметр CSYNC2_CBSD_KEY), файл будет сгенерирован. Внимание! Вам необходимо распространить этот ключ на все ноды, учавствующие в синхронизации. Конечно, это удобно делать такими инструментами, как: Puppet,Chef,Salt,Ansible.


7) пометим сервис csync2 через /etc/rc.conf как активный, на всех нодах:

sysrc csync2_enable="YES"


8) Добавим в cron от пользователя 'root' запись для ежеминутного запуска 'cbsd csync2'. Это не означает, что синхронизация будет работать каждую минуту - как мы помним, частоту синхронизации мы регулируем параметром CSYNC2_CBSD_RUN_INTERVAL. Делаем на всех нодах вызов 'crontab -e' и добавляем строчку:

* * * * * /usr/bin/lockf -s -t0 /tmp/cbsd_csync2.lock /usr/bin/env NOCOLOR=1 /usr/local/bin/cbsd csync2 >> /var/log/cbsd-csync2/csync2.log 2>&1
На этом настройка завершена. Вы можете запустить несколько раз скрипт вручную, чтобы убедится, что все работает корректно:
cbsd csync2 verbose=1 force=1
Или наблюдайте логи в каталоге /var/log/cbsd-csync2 спустя несколько минут после инсталляции cron.