UMGUM.COM 

Bacula Jobs configuration ( Формируем описание резервируемых ресурсов. )

1 ноября 2018  (обновлено 22 января 2019)

OS: "Linux Debian Lenny/Squeeze/Wheezy/Jessie/Stretch".
Application: "Bacula Director 5.2/7.4".

Это продолжение инструкции первичной настройки сервера резервного копирования "Bacula", описываемой в отдельной публикации.

Задача: выработать методику резервного копирования по принципу "одно задание - один том"; при этом количество файлов "томов" принципиально не ограничиваем, а удаление неактуальных (устаревших) "томов" будем осуществлять автоматически вызываемым скриптом, ориентирующимся на срок хранения данных в "пуле", задаваемый при конфигурировании параметров задания резервного копирования.


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

Предполагается, что запись данных производится в "volume" (том), который когда-то изначально представлял собой кассету с магнитной лентой, а теперь может эмулироваться простым файлом. Условно "тома" объединяются в "pool" (пулы), представляющие собой наборы кассет, предназначавшиеся для хранения определённого набора данных. Задачи резервного копирования привязываются к "пулам", чтобы не ограничиваться характеристиками конкретных "томов". В свою очередь "пулы" привязываются к физическим устройствам хранения вроде "ленточных библиотек" или СХД. Ну а вершиной системы хранения данных является "storage", к которому подключаются физические устройства хранения. Выглядит это примерно так:

Director (центр управления) -> Storage (сервер хранения) -> Device ("стример" или директория ФС) -> Pool (группа "томов") -> Volume (лента или файл).

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

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

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

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

Формируем набор описаний резервируемого ресурса.

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

# vi /etc/bacula/client.d/example.net.conf

# # Задаём условное имя набора клиентских параметров и указываем параметры подключения к резервируемому узлу:

Client {

  # Задаём произвольное уникальное имя описания параметров подключения к удалённому клиенту
  # (желательно включающее FQDN сетевого узла с резервируемым сервисом)
  Name = "client-example.net"

  # Уникальный FQDN или IP-адрес клиента, по которому осуществляется подключение к удалённому "Bacula-FD"
  Address = "example.net"

  # Порт на стороне клиента для подключения к нему
  FDPort = 9102

  # Пароль для подключения к клиенту
  Password = "strongPasswordForClient"

  # Количество одновременно исполняемых заданий
  MaximumConcurrentJobs = 1

  # Используемый для хранения "мета-данных" каталог СУБД
  Catalog = "cd0.bacula.local"

  # Срок хранения в СУБД информации о файлах и статусах отработанных заданий
  # (предпочитаю сохранять эти сведения подольше, для "разбора полётов" при необходимости)
  FileRetention = 1 year
  JobRetention = 1 year

  # Разрешаем удалять из СУБД информации о файлах и статусах отработанных заданий по истечению срока их хранения
  AutoPrune = yes
}

# # Определяем резервируемую область для последующего применения в задаче:

FileSet {

  # Задаём произвольное уникальное имя области резервирования
  Name = "file-set-example.net"

  Include {
    Options {

      # Указываем способ сверки целостности передаваемых данных
      # signature = MD5
      signature = SHA1

      # Включаем сжатие файлов на стороне клиента
      compression = GZIP

      # Явно включаем поддержку компактного сохранения "разрежённых" файлов (с пустыми блоками в содержимом)
      sparse = yes

      # Явно включаем поддержку Posix ACL
      aclsupport = yes

      # Собираем данные рекурсивно, включая все дочерние каталоги и файлы
      recurse = yes

      # Указываем не изменять время последнего доступа к файлу при его резервном копировании
      noatime = yes

      # Учитывать при резервировании файлы по "жёстким" ссылкам
      hardlinks = yes

      # При необходимости отключаем ограничение выхода за рамки несущей файловой системы, разрешая выходить в иные примонтированные файловые ресурсы (NFS, SMB, etc)
      #onefs = no
    }

    File = "/etc"
    File = "/home"
    File = "/root"
    File = "/usr/local/etc"
    File = "/var/log"
    File = "/var/spool/cron"
    File = "/var/www"
  }

  Exclude {
    File = ".autofsck"
    File = ".journal"
    File = ".fsck"
    File = "lost+found"
    File = "/cdrom"
    File = "/dev"
    File = "/media"
    File = "/proc"
    File = "/run"
    File = "/selinux"
    File = "/sys"
    File = "/tmp"
    File = "/var/run"
    File = "/var/tmp"
  }
}

# # Определяем параметры "пула" хранения данных клиента для последующего применения в задаче:

Pool {

  # Задаём произвольное уникальное имя "пула" "томов"
  Name = "pool-example.net"

  # Указываем срок, после которого Bacula может начать очищать тома от данных
  # (три месяца хранения - срок достаточный для обнаружения проблемы, на мой взгляд)
  VolumeRetention = 93 days

  # Явно не ограничиваем максимальное количество "томов" в "пуле"
  MaximumVolumes = 0

  # Разрешаем использование "тома" только один раз
  MaximumVolumeJobs = 1

  # Запрещаем Bacula повторное использование "томов" по истечению срока b[ хранения - они должны будут просто удаляться
  Recycle = no
  RecycleOldestVolume = no
  PurgeOldestVolume = no

  # Разрешаем Bacula удалять устаревшие записи из СУБД по мере их исполнения
  AutoPrune = yes

  # Указание обнулять размер файлов при очистке "томов", явно высвобождая при этом место в файловой системе
  ActionOnPurge = Truncate

  # Указываем тип набора "томов" (обязательный параметр с единственным значением)
  PoolType = Backup

  # Формируем шаблон для автоматического именования "томов" в "пуле" (файлов резервных копий)
  # (без этого параметра не будет работать автоматическая разметка "томов")
  LabelFormat = "${Job}.${Year}-${Month:p/2/0/r}-${Day:p/2/0/r}_${Hour:p/2/0/r}:${Minute:p/2/0/r}.${Level}-${JobId}"
}

# # Задаём параметры исполнения непосредственно задания резервного копирования:

Job {

  # Уникальное имя задания резервного копирования (желательно включающее FQDN резервируемого сервиса)
  # (используется как опорное для именований файлов конфигураций и "томов" резервных копий)
  Name = "example.net"

  # Включаем: yes (или выключаем: no) задание
  Enabled = yes

  # Тип задания
  Type = Backup

  # Уровень резервирования (Full/Incremental/Differential, параметр будет перекрыт указанным в блоке "Schedule")
  # Level = Incremental

  # Связываем задание с описанием расписания запуска
  Schedule = "WeeklyFullDailyInc"

  # Связываем задание с описанием клиента
  # (связь с параметром "Name" блока "Client")
  Client = "client-example.net"

  # Связываем задание с описанием области резервирования
  FileSet = "file-set-example.net"

  # Связываем задание с описанием "пула" хранения данных
  Pool = "pool-example.net"

  # Указываем на используемое файловое хранилище
  Storage = "sd0.bacula.local"

  # Применяем приоритет для задания
  Priority = 10

  # Для слабых или перегруженных серверов ограничиваем скорость выкачивания данных, чтобы не мешать работе основных сервисов (always in bytes per second)
  # (доступно только с v7, как серверной, так и клиентской стороны)
  # MaximumBandwidth = 10MB/s

  # Запуск полного резервирования если обнаружено некорректное завершение предыдущего резервирования
  RerunFailedLevels = yes

  # Параметры перезапуска заданий завершившихся с ошибкой
  # (нет смысла пытаться многократно перезапустить задание - лучше почти сразу проинформировать о проблеме)
  RescheduleOnError = Yes
  RescheduleInterval = 10 minutes
  RescheduleTimes = 2

  # Указываем на блок описания обработки уведомлений
  Messages = Standard

  # Файл описания задания, с помощью которой данные могут быть восстановлены из резервной копии без наличия подключения к "Bacula Catalog"
  WriteBootstrap = "/var/lib/bacula/bsr/%n.bsr"
}

Обращаю внимание на важность ограничения количества подключений к целевому клиенту одним единственным, задаваемому опцией "Maximum Concurrent Jobs" в блоке "Client", чтобы избежать вполне реальных конфликтных ситуаций, когда задание запускается дважды и сопутствующие скрипты отрабатываются не в желательном порядке.

Так же объясню, почему я не считаю нужным многократно (параметр "Reschedule Times") пытаться выполнить задание при случаях критических сбоя в процессе или на этапе подключения к сетевому узлу. Дело в том, что сбой доступности ресурса по определению требует внимания администратора, а длительные безуспешные попытки лишь оттягивают возможность исправления проблемы. Кроме того, отсрочка исполнения задания задерживает выстроившуюся за ним очередь других заданий, усугубляя общую ситуацию.

Проверяем корректность конфигурации средствами самого "Bacula" и применяем таковую:

# bacula-dir -c /etc/bacula/bacula-dir.conf -t
# /etc/init.d/bacula-dir reload

Включение в план резервного копирования внешних файловых систем.

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

....
FileSet {
  ....
  Include {
    ....

    # Основной ресурс
    File = "/var/www"

    # Примонтированный файловый ресурс
    File = "/var/www/bigdata"
  }
}
....

Описание набора файловых ресурсов для "MS Windows".

Пример определения параметров обращения к файловым системам и набора резервируемых ресурсов для "Microsoft Windows":

....
FileSet {

  # Произвольное уникальное имя области резервирования
  Name = "file-set-example.net"

  # Включаем использование механизма "теневого копирования", позволяющего обращаться к открытым и заблокированным файлам
  EnableVSS = yes

  Include {
    Options {

      # Указываем способ сверки целостности передаваемых данных
      # signature = MD5
      signature = SHA1

      # Включаем сжатие файлов на стороне клиента
      compression = GZIP

      # Собираем данные рекурсивно, включая все дочерние каталоги и файлы
      recurse = yes

      # Указываем не изменять время последнего доступа к файлу при его резервном копировании
      noatime = yes

      # Учитывать при резервировании файлы по "жёстким" ссылкам
      hardlinks = yes

      # Указываем игнорировать регистр имён файлов и директорий (специально для Win32)
      ignorecase = yes
    }

    File = "D:/data"
  }

  Exclude {
    File = "*/temp/*"
    File = "*/tmp/*"
    File = "*.tmp"
    File = "*pagefile.sys"
    File = "*hiberfil.sys"
  }
}
....


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )