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 !

FreeBSD Jail и Bacula

Введение

//draft, unformatted

Ниже представлен howto по организации резервного копирования на базе FreeBSD в качестве ОС и свободного продукта Bacula (http://www.bacula.org/). Результатом статьи является клетка bacula в репозитории имиджей CBSD, которую вы всегда можете получить через:

			 cbsd repo action=get sources=img name=bacula
		

и использовать в свое удовольствие.

Статья разбита на 2 части — непосредственно настройка Bacula и написанию скрипта, призванного снять рутину с системных инженеров путем автоматизации типовых конфигураций по шаблонным файлам. На детальном конфигурированиии самой Bacula особого внимания заострять не будем, поскольку ей посвящено немало статей и проект имеет исчерпывающую документацию, которая, как предполагается — изучена.

Принятые условности

  • Скрипт будем создавать на примере фермы серверов под управлением FreeBSD/jail, однако ничего не мешает адаптировать эту схему под вашу FavoriteOS — bacula имеет фаловые агенты для большинства современных ОС: MacOSX, Linux и Windows.
  • Для бОльшей солидности, представим себе, что обслуживаемая ферма имеет несколько десятков физических нод, размещающих на себе несколько сотен клеток, с которыми ежедневно могут происходить различные телодвижения — миграция с одной ноды на другую, переименовывание, удаление и создание новых.
  • Bacula-server будет запущен в клетке с именем bacula и FQDN: bacula.my.domain, который ресолвится по данному имени на всех учавствующих в резервном копировании серверах, а также, доступен для них по портам tcp/9xxx
  • Сам сервер, на котором запущена клетка Bacula, имеет достаточный объем жесткого диска для резервных копий, доступный клетке Bacula — это может быть выполнено запуском самой клетки на этом партишене, либо посредством bacula.fstab или zfs mount, примонтировано в директорию /var/bacula внутри клетки.
  • В Bacula, мы будем использовать один общий пул (Default) на все данные, тип пула — File. Те, если вы используете ленточные накопители, конфигурация будет немного иной.
  • В качестве пароля файловых демонов, договоримся использовать запись вида ${node}srvpassword, где ${node} — имя ноды.

Часть 1/2: Настройка сервера.

создание клетки и инсталляция ПО

На сервере, выбранном в качестве Backup сервера, создаем стандартную клетку (например через cbsd jconstruct-tui) с именем bacula и полным именем bacula.my.domain. (разумеется, здесь может быть любое ваше имя) и устанавливаем необходимый софт через порты или pkg:

На момент написания статьи, порт bacula-server по-умолчанию сконфигурирован на использование PgSQL. Если вы пользуетесь pkg и желаете использовать SQLite3 как подразумевается статьей, можно использовать соответствующий репозиторий nox от CBSD (http://www.bsdstore.ru/ru/downloads.html) либо собрать из портов. Узнать, с какими опциями собран софт на репозитории можно через pkg rquery. Вариант настройки Bacula+PgSQL можно посмотреть в конце статьи, однако, даже для нескольких десятков физических нод и нескольких сотен клеток, автор посчитал подъем СУБД PgSQL — избыточным решением.

			 pkg install bacula-server
		

Настройка Bacula

Файловая иерархия Bacula

Теперь определимся с файловой иерархией конфигурационных файлов и выполним настройку Bacula. Стандартное местоположение конфигурационных файлов bacula-server в инсталляции по-умолчанию в FreeBSD: /usr/local/etc/bacula/

				 /usr/local/etc/bacula/bacula-dir.conf   — конфигурационный файл директора
				 /usr/local/etc/bacula/bacula-fd.conf    — конфигурационный файл агента (файловый демон/клиент)
				 /usr/local/etc/bacula/bacula-sd.conf    — конфигурационный файл стореджа
				 /usr/local/etc/bacula/bconsole.conf     — конфигурационный файл для консоли
		

Скопируем стандартные конфигурационные файл в рабочие:

			 cd /usr/local/etc/bacula
			 cp bacula-dir.conf.sample bacula-dir.conf
			 cp bacula-sd.conf.sample bacula-sd.conf
			 cp bacula-fd.conf.sample bacula-fd.conf
			 cp bconsole.conf.sample bconsole.conf
			 touch includes.conf
		

Подготовка Bacula server

Для того, чтобы не проводить огромное количество правок в одном конфигурационном файле bacula-dir.conf, вынесем через @include макрос те файлы, которые будем корректировать и/или будут генерироваться автоматически. Для большего удобства, будем подразумевать следующую иерархию конфигурационных файлов:

  • /usr/local/etc/bacula/ — корень конфигурации Bacula
  • /usr/local/etc/bacula/address/ — каталог, содержащий параметр Address и пароль авторизации файлового демона для физических нод. Также, на эти файлы будут указывать символические ссылки для адреса клеток (ссылка будет указывать на адрес той физической ноды, на которой хостится клетка.
  • /usr/local/etc/bacula/fileset/ — выделенные в отдельную локацию списки путей на физических серверах (включая пути относящиеся к клеткам), которые следует включить или исключить из бекапа.
  • /usr/local/etc/bacula/hosts/ — конфигурация для бекапа физических машин
  • /usr/local/etc/bacula/jails/ — конфигурация для бекапа клеток

Настройка bacula-dir

bacula-dir.conf

Произведем в bacula-dir.conf минимальные правки для запуска сервера:

В секции Director задаем имя директора:

				Name = bacula-dir
		

Если дисковая подсистема достаточно быстрая (уровень raid>5+) и пропускная способность сети выше 50-100 Mbit/s, имеет смысл увеличить максимальное количество параллельных задач с 1 до, к примеру, 10:

				Maximum Concurrent Jobs = 10
		

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

Внимание: устанавливайте свои сгенерированные случайным образом пароли. Эти пароли могут быть любой последовательностью и не передаются по сети.

Password = "consolepassword"

В секции JobDefs изменим имя:

				Client = bacula-fd
		

в секции Job, описывающий задание по-умолчанию, поменяем имя BackupClient1 на более говорящее свое имя:

				Name = "bacula.my.domain"
		

В секции Job, описыващий тип Restore, поменяем имя клиента на соответствующего локальному демону:

				Client = backup1-fd
		

В секции FileSet опишем пути, которые будем сохранять у локального клиента:

			 Include {
				Options {
					signature = MD5
				}
				File = /etc
				File = /root
				File = /usr/local/etc
			}

			Exclude {
			}
		

В секции Client установим имя, адрес и пароль клиента bacula

				Name=bacula-fd
				Address=bacula.my.domain
				Password="filedaemonpassword" 
		

В секции Storage установим адрес и пароль storage-демона:

				Address=bacula.my.domain
				Password="storagepassword" 
		

В секции Catalog укажем, что в качестве бакенда будем использовать SQLite3 базу, как наименее требовательный движек:

				dbdriver = "dbi:sqlite3";
		

В секциях Messages переназначим лог-файл в более подходящее место и исправим email на тот, который мы проверяем (в примере: root@localhost):

				append = "/var/log/bacula/bacula.log" = all, !skipped
		

Откорректируем пул Default (если вы используете ленточный накопитель, настройка будет иной), добавив метку, нужное количество возможных файлов-библиотек, их максимальные объемы и срок ротации. В нашем примере будем импользовать префикс Vol в именах библиотек, максимальный объем каждого ограничим 100Gb, максимальное число которых — 100 (те, объем хранилища под резервные копии отводится 10 Tb). Повторное использование — через 65 дней.

				LabelFormat = "Vol" 
				Maximum Volume Bytes = 50G
				Maximum Volumes = 50
				Maximum Volume Files = 0
		

Остальные параметры закомментируем (либо они будут вынесены в подключаемых файлах), добавив путь к остальной конфигурации через файл /usr/local/etc/bacula/includes.conf:

				@/usr/local/etc/bacula/includes.conf
		

Финальный вид bacula-dir.conf будет таким:

		Director {
			Name = bacula-dir
			DIRport = 9101
			QueryFile = "/usr/local/share/bacula/query.sql" 
			WorkingDirectory = "/var/db/bacula" 
			PidDirectory = "/var/run" 
			Maximum Concurrent Jobs = 10
			Password = "consolepassword" 
			Messages = Daemon
		}

		JobDefs {
			Name = "DefaultJob" 
			Type = Backup
			Level = Incremental
			Client = bacula-fd
			FileSet = "Full Set" 
			Schedule = "WeeklyCycle" 
			Storage = File
			Messages = Standard
			Pool = File
			Priority = 10
			Write Bootstrap = "/var/db/bacula/%c.bsr" 
		}

		Job {
			Name = "bacula.my.domain" 
			JobDefs = "DefaultJob" 
		}

		Job {
			Name = "BackupCatalog" 
			JobDefs = "DefaultJob" 
			Level = Full
			FileSet="Catalog" 
			Schedule = "WeeklyCycleAfterBackup" 
			RunBeforeJob = "/usr/local/share/bacula/make_catalog_backup.pl MyCatalog" 
			RunAfterJob  = "/usr/local/share/bacula/delete_catalog_backup" 
			Write Bootstrap = "/var/db/bacula/%n.bsr" 
			Priority = 11
		}

		Job {
			Name = "RestoreFiles" 
			Type = Restore
			Client = bacula-fd
			FileSet="Full Set"                  
			Storage = File                      
			Pool = Default
			Messages = Standard
			Where = /tmp/bacula-restores
		}

		FileSet {
			Name = "Full Set" 
			Include {
				Options {
					signature = MD5
				}
				File = /etc
				File = /root
				File = /usr/local/etc 
		}

			Exclude {
			}
		}

		Schedule {
			Name = "WeeklyCycle" 
			Run = Full 1st sun at 23:05
			Run = Differential 2nd-5th sun at 23:05
			Run = Incremental mon-sat at 23:05
		}

		Schedule {
			Name = "WeeklyCycleAfterBackup" 
			Run = Full sun-sat at 23:10
		}

		FileSet {
			Name = "Catalog" 
			Include {
				Options {
					signature = MD5
				}
				File = "/var/db/bacula/bacula.sql" 
			}
		}

		Client {
			Name = bacula-fd
			Address = localhost
			FDPort = 9102
			Catalog = MyCatalog
			Password = "backup1.my.domainsrvpassword" 
			File Retention = 30 days
			Job Retention = 6 months
			AutoPrune = yes
		}

		Storage {
			Name = File
			Address = bacula.my.domain
			SDPort = 9103
			Password = "storagepassword" 
			Device = FileStorage
			Media Type = File
		}

		# Generic catalog service
		Catalog {
			Name = MyCatalog
			dbdriver = "dbi:sqlite3";
			dbname = "bacula"; dbuser = "bacula"; dbpassword = "" 
		}

		Messages {
			Name = Standard
			mailcommand = "/usr/local/sbin/bsmtp -h localhost -f \"\(Bacula\) \<%r\>\" -s \"Bacula: %t %e of %c %l\" %r" 
			operatorcommand = "/usr/local/sbin/bsmtp -h localhost -f \"\(Bacula\) \<%r\>\" -s \"Bacula: Intervention needed for %j\" %r" 
			mail = root@localhost = all, !skipped            
			operator = root@localhost = mount
			console = all, !skipped, !saved
			append = "/var/log/bacula/bacula.log" = all, !skipped
			catalog = all
		}

		Messages {
			Name = Daemon
			mailcommand = "/usr/local/sbin/bsmtp -h localhost -f \"\(Bacula\) \<%r\>\" -s \"Bacula daemon message\" %r" 
			mail = root@localhost = all, !skipped            
			console = all, !skipped, !saved
			append = "/var/log/bacula/bacula.log" = all, !skipped
		}

		Pool {
			Name = Default
			Pool Type = Backup
			Recycle = yes
			AutoPrune = yes
			Volume Retention = 65 days
			LabelFormat = "Vol" 
			Maximum Volume Bytes = 100G
			Maximum Volumes = 100
		}

		@/usr/local/etc/bacula/includes.conf
		

Запуск bacula-dir

Создадим каталоги для логов и архивов, дав им соответствующего владельца:

				mkdir -m 740 /var/log/bacula /var/bacula
				chown bacula:bacula /var/log/bacula /var/bacula
		

Создадим SQLite3 базу и необходимую иерархию таблиц в /var/db/bacula/bacula.db:

				sh /usr/local/share/bacula/create_sqlite3_database 
				sh /usr/local/share/bacula/make_sqlite3_tables 
		

Выставим флаг старта сервиса bacula-dir и запустим его:

				sysrc bacula_dir_enable=YES
				service bacula-dir start
		

Половина работы выполнена ;)

Bacula Storage daemon

Нижеописанная конфигурация подразумевает использование в качестве стореджа для бекапа непосредственно дисковое пространство, на котором запущена клетка Bacula.

Сконфигурируем /usr/local/etc/bacula/bacula-sd.conf

В секции Storage укажем соответствующее серверу имя:

		Name = bacula-sd
		

В секции Director укажем корректное имя и соответствующий пароль для авторизации SD с директором:

				Name = bacula-dir
				Password = "storagepassword" 
		

В секции Device укажем путь, где будут находится непосредственно резервные копии. Это может быть любой путь в пределах доступности клетки, который в свою очередь может быть подмонтирован отдельно через fstab клетки, либо подразумеваем, что клетка сама по себе запущена на достаточно объемном накопителе. В нашем случае, путь к корню копий является /var/bacula:

				Archive Device = /var/bacula
		

Финальный вид /usr/local/etc/bacula/bacula-sd.conf в нашем случе будет следующим:

		Storage {
			Name = bacula-sd
			SDPort = 9103
			WorkingDirectory = "/var/db/bacula" 
			Pid Directory = "/var/run" 
			Maximum Concurrent Jobs = 20
		}

		Director {
			Name = bacula-dir
			Password = "storagepassword" 
		}

		Director {
			Name = bacula-mon
			Password = "storagepassword" 
			Monitor = yes
		}

		Device {
			Name = FileStorage
			Media Type = File
			Archive Device = /var/bacula
			LabelMedia = yes;
			Random Access = Yes;
			AutomaticMount = yes;
			RemovableMedia = no;
			AlwaysOpen = no;
		}

		Messages {
			Name = Standard
			director = bacula-dir = all
		}
		

Добавим SD в rc.conf и запустим:

			 sysrc bacula_sd_enable=YES
			 service bacula-sd start
		

bacula fd

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

В /usr/local/etc/bacula-fd.conf дадим имя и пароль нашему файловому демону. Финальный вид, файл будет иметь следующий вид:

		Director {
			Name = bacula-dir
			Password = "bacula.my.domainsrvpassword" 
		}

		FileDaemon{
			Name = backup.my.domain
			FDport = 9102
			WorkingDirectory = /var/db/bacula
			Pid Directory = /var/run
			Maximum Concurrent Jobs = 20
		}

		# Send all messages except skipped files back to Director
		Messages {
			Name = Standard
			director = bacula-dir = all, !skipped, !restored
		}
		

Добавим FD в rc.conf и запустим:

			 sysrc bacula_fd_enable=YES
			 service bacula-fd start
		

bacula console

Для доступа в Bacula с помощью агентов (bat, bacula-web), в том числе для доступа bconsole непосредственно на самом сервере, изменим имя и пароль в соответствующем файле /usr/local/etc/bacula/bconsole.conf. Пароль должен соответствовать тому, который вы установили в bacula-dir в секции Directory. В нашем примере, /usr/local/etc/bacula/bconsole.conf будет иметь следующий вид:

		Director {
				 Name = bacula-dir
				 DIRport = 9101
				 address = localhost
				 Password = "consolepassword" 
			}
		

Обновление пула

Для обновления данных пула Default из конфигурационного файла, необходимо выполнить update pool from resource в CLI:

		# bconsole

		*update
		Automatically selected Catalog: MyCatalog
		Using Catalog "MyCatalog" 
		Update choice:
				 1: Volume parameters
				 2: Pool from resource
				 3: Slots from autochanger
				 4: Long term statistics
		Choose catalog item to update (1-4): 2
		Automatically selected Pool: Default
		..

		*exit
		

Часть 2/2: скрипт для создания конфигураций FreeBSD нод и клеток.

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

Установка CBSD в клетку

Примечание: установка порта CBSD необходима только для получения файла jmap.txt через вызов cbsd jailmapdb. Если вы уже имеете в ферме актуальный jmap.txt, вы можете просто синхронизировать этот файл в клетку с bacula. В данном примере, предполагаем, что клетка будет самодостаточной и будет иметь всю информацию по нодам внутри себя.

Если вы будете синхронизировать jmap.txt в клетку из другого источника, этот шаг можно пропустить.

Скачаем через pkg:

				pkg install cbsd
		

Или установим из портов:

			 % make -C /usr/ports/sysutils/cbsd install
		

Проинициализируем CBSD, указав workdir например, в /root/jails, поскольку базу клетки мы обычно монтируем в read-only и привычное для CBSD место /usr/jails будет недоступно для записи.

		env workdir="/root/jails" /usr/local/cbsd/sudoexec/initenv
		// задаем любой пароль пользователю cbsd, он использоваться не будет

		Do you want to activate every 5 minutes activity reporter into log (cbsdsar)?
		//отвечаем no, внутри клетки этот функционал не нужен

		nodeip: persistent (when possible) managment IP address for node interconnection. e.g: 10.0.0.10
		//вводим любой IP, внутри клетки этот функционал не нужен

		jnameserver: default DNS nameserver (comma separated for multiple) for jails resolv.conf, e.g.: 10.0.0.10,8.8.8.8
		//вводим любой IP, внутри клетки этот функционал не нужен

		nodeippool: pool of IP addresses from which jail can work
		//вводим любой IP, внутри клетки этот функционал не нужен

		nat_enable: configure NAT for RFC1918 Network?
		//отвечаем no, внутри клетки этот функционал не нужен

		fbsdrepo: shall i use the official FreeBSD repository for fetching base via repo?
		//отвечаем no, внутри клетки этот функционал не нужен

		mdtmp: do you want to use memory disk (8 mb default) for temporary operation? 0 — for disable or N (in mb) for disk size e.g: 8
		//отвечаем 0, внутри клетки этот функционал не нужен

		parallel: do you want to stop/start jail in parallel mode? (0 — no parallel or positive value (in seconds) as timeout for next parallel sequence) e.g: 5
		//любое значение, внутри клетки этот функционал не нужен

		stable: if you want to use STABLE_X branch instead of RELEASE_X_Y for base and kernel, choose '1', e.g: 0 (use release)
		//отвечаем 0, внутри клетки этот функционал не нужен

		Configure RSYNC services for jail migration?
		//отвечаем no, внутри клетки этот функционал не нужен

		Configure NAMED service for resolving?
		//отвечаем no, внутри клетки этот функционал не нужен
		

Теперь CBSD внутри клетки, готова для команд cbsd node node=add и jailmapdb.

Темплейты

Конфигурационный файл Bacula для каждой клетки будет содержать всю нужную информацию о параметрах копирования (частота, время, список локаций для копирования и исключений, приоритет и т.д.); единственное, что у этих данных будет обновляться автоматически — это физическое расположение клетки. В связи с этим, адрес сервера для клетки мы вынесем в отдельное место и предоставим управление его содержимим скрипту bacula-helper. Кроме того, напишем пару шаблонов, которые будут использованы при создании новых конфигураций в автоматическом режиме. Создадим общий набор путей для исключений не нужных в копировании путей на физических серверах, которые подойдут для всех. Персональные настройки можно будет дописывать уже после создания конфигурации — скрипт их перезаписывать не будет. Будем предполагать, что все клетки на серверах инициированы (workdir) в каталоге /usr/jails. Если это не так, или имеете другие предпочтения, вы можете откорректировать пути как пожелаете. Все темплейты будем хранить в каталоге /root/etc/bacula, они в последствии будут использованы bacula-helper.

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

/root/etc/bacula/freebsd-default-exclude

			 File = /dev
			 File = /proc
			 File = /tmp
			 File = /usr/compat/linux/sys
			 File = /usr/compat/linux/proc
			 File = /usr/obj
			 File = /usr/ports
			 File = /usr/src
			 File = /var/tmp
			 File = /var/crash
			 File = /var/db/freebsd-update
			 File = /var/db/portsnap
			 File = /var/db/pkg
			 File = /var/cache
			 File = /usr/jails/basejail
			 File = /usr/jails/src
			 File = /usr/jails/tmp
			 File = /usr/jails/export
			 File = /usr/jails/import
			 File = /usr/jails/var/db/sar
			 File = /usr/jails/jails
			 File = /usr/jails/jails-data
			 File = /usr/jails/jails-system
		

Создадим общий набор путей для включения в резервное копирование при бекапе физических, которые подойдут для всех серверов. К примеру, для клиентов на FreeBSD такой вариант:

/root/etc/bacula/freebsd-default-fileset

			 File = /boot
			 File = /root
			 File = /etc
			 File = /var/db/pkg
			 File = /var/db/ports
			 File = /usr/local/etc
			 File = /var/backups
			 File = /var/run/dmesg.boot
			 File = /var/named
			 File = /var/cache
			 File = /usr/jails
		

Таким же образом, создадим общий набор путей для исключений при бекапе FreeBSD клеток, подходящие всем системам:

/root/etc/bacula/jails-exclude.tpl

			 File = /usr/jails/jails-data/${jname}-data/dev
			 File = /usr/jails/jails-data/${jname}-data/proc
			 File = /usr/jails/jails-data/${jname}-data/tmp
			 File = /usr/jails/jails-data/${jname}-data/usr/compat/linux/sys
			 File = /usr/jails/jails-data/${jname}-data/usr/compat/linux/proc
			 File = /usr/jails/jails-data/${jname}-data/usr/obj
			 File = /usr/jails/jails-data/${jname}-data/usr/ports
			 File = /usr/jails/jails-data/${jname}-data/usr/src
			 File = /usr/jails/jails-data/${jname}-data/var/tmp
			 File = /usr/jails/jails-data/${jname}-data/var/crash
			 File = /usr/jails/jails-data/${jname}-data/var/db/freebsd-update
			 File = /usr/jails/jails-data/${jname}-data/var/db/portsnap
			 File = /usr/jails/jails-data/${jname}-data/var/db/pkg
			 File = /usr/jails/jails-data/${jname}-data/var/cache
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/basejail
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/src
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/tmp
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/export
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/import
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/var/db/sar
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/jails
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/jails-data
			 File = /usr/jails/jails-data/${jname}-data/usr/jails/jails-system
		

Общий набор путей для включения в резервное копирование FreeBSD клеток, подходящие всем:

/root/etc/bacula/jails-fileset.tpl

			 File = /usr/jails/jails-rcconf/rc.conf_${jname}
			 File = /usr/jails/jails-fstab/fstab.${jname}
			 File = /usr/jails/jails-system/${jname}
			 File = /usr/jails/jails-data/${jname}-data
		

Шаблон для создания конфигурации ноды

/root/etc/bacula/hosts.tpl

		Client {
		@/usr/local/etc/bacula/address/${node}-address

		Name = ${node}-fd
		FDPort = 9102
		Catalog = MyCatalog
		File Retention = 65 days
		Job Retention = 65 days
		AutoPrune = yes
		Maximum Concurrent Jobs = 5
		}

		JobDefs{
		Name = "${node}-jobdef" 
		Type = Backup
		Level = Incremental
		Client = ${node}-fd
		FileSet = "${node}-full" 
		Schedule = "${node}-cycle" 
		Storage = File
		Messages = Standard
		Pool = Default
		Priority = 10
		}

		Job {
		Name = "${node}-job" 
		JobDefs = "${node}-jobdef" 
		Write Bootstrap = "/var/db/bacula/${node}.bsr" 
		Maximum Concurrent Jobs = 5
		}

		FileSet {
		 Name = "${node}-full" 
		 Include {
			Options {
			signature = MD5
			compression = GZIP
		}

		@/usr/local/etc/bacula/fileset/freebsd-default-fileset
		}

		Exclude {
				@/usr/local/etc/bacula/fileset/freebsd-default-exclude
		}

		}

		Schedule {
			Name = "${node}-cycle" 
			Run = Full 1st fri at 01:00
			Run = Differential 2nd-5th fri at 01:00
			Run = Incremental mon-sun at 01:00
		}
		

Шаблон для создания конфигурации клетки.

/root/etc/bacula/jails.tpl

		Client {
		@/usr/local/etc/bacula/address/${node}-address
		Name = ${node}-fd
		FDPort = 9102
		Catalog = MyCatalog
		File Retention = 65 days
		Job Retention = 65 days
		AutoPrune = yes
		Maximum Concurrent Jobs = 5
		}                                                                                      

		JobDefs {
		Name = "${node}-jobdef" 
		Type = Backup
		Level = Incremental
		Client = ${node}-fd
		FileSet = "${node}-full" 
		Schedule = "${node}-cycle" 
		Storage = File
		Messages = Standard
		Pool = Default
		Priority = 10                                                                       
		}

		Job {
		Name = "${node}-job" 
		JobDefs = "${node}-jobdef" 
		Write Bootstrap = "/var/db/bacula/${node}.bsr" 
		Maximum Concurrent Jobs = 5
		}

		FileSet {
			Name = "${node}-full" 
			Include {
				Options {
				 signature = MD5
				 compression = GZIP
		}

		@/usr/local/etc/bacula/fileset/freebsd-default-fileset
		}

		Exclude {
				@/usr/local/etc/bacula/fileset/freebsd-default-exclude
		}

		}

		Schedule {
			Name = "${node}-cycle" 
			Run = Full 1st fri at 01:00
			Run = Differential 2nd-5th fri at 01:00
			Run = Incremental mon-sun at 01:00
		}
		

И наконец, шаблон куска адреса и составной пароля физической ноды, который будет подключается из файла конфигурации ноды.

/root/etc/bacula/nodeaddr.tpl
			 Address = ${node}
			 Password = "${node}srvpassword" 
		

CBSD

В данном случае CBSD (а конкретнее — jmap) будет служить в качестве указателя на ноду, где какая клетка размещена. Для обработки этой информации, осуществлением мониторинга за создаваемыми или удаляемыми клетками в ферме, напишем sh-скриптик bacula-helper, который будет связующим звеном между Bacula и cbsd. Кроме этого, скрипт будет автоматически создавать конфигурации к отсутствующем в Bacula конфигурациям. Данный функционал не вставляет новые конфигурации серверов или клеток в общий список задач — это специально вынесено на усмотрение инженера, но в случае уже имеющейся конфигурации, при изменения адреса физической ноды или при миграции клетки с одной ноды в ферме на другую, изменения вступят в силу. О любых изменениях в конфигураци, скрипт будет высылать отчет на электронную почту (переменная RCPTTO). Включать или не включать новые ноды и клетк оставляем на усмотрение системного администратора.

		#!/bin/sh
		BACULADIR="/usr/local/etc/bacula" 
		ADDRDIR="${BACULADIR}/address" 
		JAILDIR="${BACULADIR}/jails" 
		FILESETDIR="${BACULADIR}/fileset" 
		HOSTSDIR="${BACULADIR}/hosts" 
		CFGDIR="/root/etc/bacula" 
		RCPTTO="root@localhost" 
		MYNAME="${0##*/}" 
		FLAG="clean" 
		CBSD=/usr/local/bin/cbsd

		# fatal error. Print message end quit with exitval
		err()
		{
				local _retval=$1
				shift
				echo "$*" 1>&2

				mail -s "${MYNAME}: critical error" ${RCPTTO} << EOF
		host: `hostname`
		Problem: $*
		EOF

				[ "${_retval}" = "0" ] || exit ${_retval}
		}

		#init cfg and send notify
		initcfg()
		{
				local _size _i _modify=0

				for _i in ${linklog} ${conflog}; do
						_size=`stat -f %z ${_i}`
						[ ${_size} -gt 0 ] && _modify=$(( _modify + 1 ))
				done

				if [ ${_modify} -gt 0 ]; then
						mail -s "${MYNAME}: config modify" ${RCPTTO} << EOF
		`cat ${linklog}`
		`cat ${conflog}`
		EOF

						echo "reload" |/usr/local/sbin/bconsole > /dev/null 2>&1
						#let bacula-dir time for reloading
						sleep 2
						/usr/sbin/service bacula-dir status >/dev/null 2>&1|| err 1 "bacula is not running!" 
				fi

		}

		make_jail()
		{

				while read line; do
						eval echo "${line}" 
				done < "${CFGDIR}/jails.tpl" > ${JAILDIR}/${jname} && chown root:bacula ${JAILDIR}/${jname}

				cat >> ${conflog} << EOF
		jail config created: ${jname}
		Please add by hands into ${BACULADIR}/includes.conf if you want to backup this:
		@${JAILDIR}/${jname}

		EOF
		}

		make_hosts()
		{

				while read line; do
						eval echo "${line}" 
				done < "${CFGDIR}/hosts.tpl" > ${HOSTSDIR}/${node} && chown root:bacula ${HOSTSDIR}/${node}

				if [ ! -f "${ADDRDIR}/${node}-address" -o ${FORCE} -eq 1 ]; then
						while read line; do
								eval echo "${line}" 
						done < ${CFGDIR}/nodeaddr.tpl > ${ADDRDIR}/${node}-address && chown root:bacula ${ADDRDIR}/${node}-address
				fi

				cat >> ${conflog} < ${FILESETDIR}/jails-${jname}-fileset && chown root:bacula ${FILESETDIR}/jails-${jname}-fileset

				echo "default jail fileset created: ${jname}" >> ${conflog}
		}

		make_jail_exclude()
		{

				while read line; do
						eval echo "${line}" 
				done < "${CFGDIR}/jails-exclude.tpl" > ${FILESETDIR}/jails-${jname}-exclude && chown root:bacula ${FILESETDIR}/jails-${jname}-exclude

				echo "default jail exclude created: ${jname}" >> ${conflog}
		}

		# (re-)create for symlinks
		symlink()
		{
				ln -sf ${ADDRDIR}/${node}-address ${ADDRDIR}/${jname}-jail-address && echo "link changed: ${jname}-jail-address -> ${node}-address" >> ${linklog}
		}

		## MAIN ##
		FORCE=0
		[ "$1" = "force" ] && FORCE="1" 

		for i in $BACULADIR $ADDRDIR $JAILDIR $FILESETDIR $HOSTSDIR;  do
				[ ! -d "${i}" ] && mkdir ${i}
		done

		for i in freebsd-default-exclude freebsd-default-fileset; do
				[ ! -f "${FILESETDIR}/${i}" -o $FORCE -eq 1 ] && cp ${CFGDIR}/${i} ${FILESETDIR}/${i}
		done

		. /etc/rc.conf

		[ ! -f "${cbsd_workdir}/var/db/jmap.txt" ] && err 1 "No such jmap.txt. Please run: cbsd jailmapdb update=1" 

		jailmaptmp=`mktemp -t ${MYNAME} -t ${MYNAME}`
		jaildeltmp=`mktemp -t ${MYNAME}`
		jailremovetmp=`mktemp -t ${MYNAME}`
		jailexisttmp=`mktemp -t ${MYNAME}`
		conflog=`mktemp -t ${MYNAME}`
		linklog=`mktemp -t ${MYNAME}`

		trap "rm -f ${jailmaptmp} ${jaildeltmp} ${jailremovetmp} ${jailexisttmp} ${conflog} ${linklog}" HUP INT ABRT BUS TERM  EXIT
		jailexst=$(ls /usr/local/etc/bacula/jails/ > ${jailexisttmp})

		while read line; do
				line=${line%%=*}
				echo ${line}
		done < "${cbsd_workdir}/var/db/jmap.txt" > ${jailmaptmp}

		grep -v -f ${jailmaptmp} ${jailexisttmp} > ${jaildeltmp}

		while read LINE;do
				echo "Remove jail: $jaildel$LINE" 
		done < ${jaildeltmp} > ${jailremovetmp}

		mail -E -s "Bacula jail config remove" "${RCPTTO}" < ${jailremovetmp}

		for node in $(${CBSD} node mode=list);do
				[ ! -f "${HOSTSDIR}/${node}" -o ${FORCE} -eq 1 ] && make_hosts
		done

		for jname in $(${CBSD} jailmapdb all=1 quiet=1);do
				node=$(${CBSD} jailmapdb ${jname} quiet=1 | awk {'print$1'})
				[ ! -f "${JAILDIR}/${jname}" -o ${FORCE} -eq 1 ] && make_jail
				[ ! -f "${FILESETDIR}/jails-${jname}-fileset" -o ${FORCE} -eq 1 ] && make_jail_fileset
				[ ! -f "${FILESETDIR}/jails-${jname}-exclude" -o ${FORCE} -eq 1 ] && make_jail_exclude
				echo `readlink ${ADDRDIR}/${jname}-jail-address` | grep ${node} > /dev/null 2>&1
				SYMTEST=$?
				[ ${SYMTEST} -ne 0 -o ${FORCE} -eq 1 ] && symlink
		done

		initcfg
		

Crontab и активация конфигураций.

На данном этапе, осталось надобавлять через cbsd node mode=add все ноды, которые мы хотим бекапить (либо копировать jmap.txt в соответствующий каталог с любого сервера, где список нод поддерживается в актуальном состоянии.

Поставим скрипт на выполнение, к примеру, один раз в сутки, например в 23:00 в пользовательском cron пользователя root:

crontab -e:

		..
		0 22 * * * /usr/bin/lockf -s -t0 /tmp/jailmapdb /usr/local/bin/cbsd jailmapdb update=1 > /dev/null 2>&1
		0 23 * * * /usr/bin/lockf -s -t0 /tmp/backupmap /root/bin/bacula-helper > /dev/null 2>&1
		..
		

(если список нод копируется откуда-то, а не генерируется внутри клетки bacula, первая строчка с jailmapdb — не нужна)

Последний шаг — добавление новых конфигураций в Bacula. Для этого мы выбрали файл /usr/local/etc/bacula/includes.conf, в который добавим то, что должно копироваться. Например, файл может быть таким:

		# Client includes
		@/usr/local/etc/bacula/hosts/s1.my.domain
		@/usr/local/etc/bacula/hosts/s2.my.domain

		# FreeBSD Jails
		@/usr/local/etc/bacula/jails/jail1
		@/usr/local/etc/bacula/jails/jail2
		@/usr/local/etc/bacula/jails/jail3
		@/usr/local/etc/bacula/jails/jail4
		@/usr/local/etc/bacula/jails/jail5
		@/usr/local/etc/bacula/jails/jail6
		

выполним перечитывание конфигурации, чтобы изменения вступили в силу:

			 echo "reload" | bconsole
		

Заключение

Суммируем полученные плюсы, полученные в результате проделанной работы:

  • Слежение за появляемыми, удаляемыми и мигрирующимими окружениями передано автоматике. Рост общего числа серверов и клеток никак не сказывается на занятости системного администратора; исключаются случаи, когда мысли «сейчас сделаем окружение, а бекап — чуть попозже» — забываются, а каждая миграция клетки не требует постоянных правок конфигураций.
  • Созданы типовые шаблоны для конфигураций, в которых перечислены исключения и выборки локаций для резервного копирования;
  • Общий шаблон позволяет копировать всю клетку. В случае, если физический сервер погибает, системный инженер запускает restore на любую подходящую систему, после чего выполняет старт клетки. Подобный подход позволяет ввести в эксплуатацию сервер через несколько минут после установки чистой ОС (которая занимает 5-10 минут)
  • В случае, когда скрипт замечает миграцию клетки, на Email оператора шлется письмо «bacula-helper: config modify» информационного характера:
    				link changed: gitlab-jail-address -> s1.bsdstore.ru-address
    				ln -sf s1.bsdstore.ru-address gitlab-jail-address
    				
  • В случае, когда скрипт замечает новую клетку в ферме, создается ее конфигурация, а на Email оператора шлется соответствующее письмо с предложением включить новые конфиги в пул:
    				link changed: syslogd-jail-address -> devsrv.bsdstore.ru-address
    				jail config created: syslogd
    				
    				Please add by hands into /usr/local/etc/bacula/includes.conf if you want to backup this:
    				@/usr/local/etc/bacula/jails/syslogd
    				default jail fileset created: syslogd
    				default jail exclude created: syslogd