- PVSM.RU - https://www.pvsm.ru -
Это пост про жизнь после Getting Started with Bareos, и о чем пришлось дольше всего читать всеобъемлющий мануал [1].
Стородж
Если вы уже погоняли тестовые задания в песочнице и умеете переписываться с бареосом через bconsole, то пролеземте под кат.
У нас просто организация, не ИТ-профиля, не
Потому что доступен виндовый клиент. Как известно, Bareos — это драматический форк Bacula, заслуженной и проверенной. Но во время выбора бакула зажимала исходники (да и бинари) своего fd для Windows, поэтому нет. Veeam хорош, но стóит как кресло стадиона ФК «Зенит». Был DPM, но сколько мы с Антоаном из техподдержки Майкрософта с ним не боролись, любви так и не возникло.
была описана неоднократно. Кто такой директор и чем он занимается с другими демонами — можно почитать, например, здесь [3]. Замечу только, что dir и sd крайне желательно должны быть одной версии, версия fd не так важна. По ощущениям от чейнджлогов, версию лучше иметь 16 или выше.
По DPM-овской привычке хотел создать большое задание и в него много напихать. Оказалось, что маленькие задания удобнее: при неудачном выполнении маленькое быстрее выполнится повторно и лучше пролезает через спулер (об этом дальше). На процесс восстановления размер задания не влияет, разве что задание с сотнями тысяч файлов может подтормаживать на этапе их выбора.
Виртуальные машины (ВМ) работают на кластерах Hyper-V. В пределах кластера на нодах настройки fd одинаковы, хостнеймом у всех указано имя кластера. В директоре в качестве клиента тоже указан кластер со своим кластерным адресом. ВМ может переехать на другой том кластера, поэтому указываем не конкретный путь, а путь к скрипту:
FileSet {
# в названии набора файлов указываем имя виртуалки, как это удобно
Name = "VM_lamachine-fs"
Include {
# указываем имя ВМ (наличие/отсутствие "example.com" тоже важно)
File = "\|C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -file c:/cmd/search-vm.ps1 -machine lamachine.example.com"
Options {
# диски ВМ очень хорошо жмутся
Compression = LZO
# исключаем большой лишний файл
RegexFile = ".*/Virtual Machines/.*.bin"
Exclude = yes
}
}
}
А вот c:cmdsearch-vm.ps1, который и отдаёт путь к машине:
Param(
[string]$level,
[string]$machine = "NOEXISTENTVM.example.com"
)
Import-Module failoverclusters
$backuppath = @()
$Cluster = Get-Cluster
$ClusterMachines = @()
$ClusterMachines += Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
if ($ClusterMachines.Count -eq 0 ) {
"NO MACHINES"
exit 2
}
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
$path = $VM.Path.Replace('','/')
$backuppath += $path
foreach ($HardDrive in $VM.HardDrives){
$drivepath = $HardDrive.Path | Split-Path -Parent
$drivepath = $drivepath.Replace('','/')
if ($drivepath -notin $backuppath){
$backuppath += $drivepath
}
}
}
$backuppath
Перед бэкапом делается снапшот, после бэкапа он удаляется, для этого есть пара чьих-то грубо допиленных скриптов.
#Copyright disclaimer:
# Copyright (C) 2015, ITHierarchy Inc (www.ithierarchy.com). ALl rights reserverd.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Param(
[string]$level,
[string]$machine = "noexist.example.com",
#[string]$prefix = "",
[int]$DayOfWeekForFullBackup = 2
)
Import-Module failoverclusters
"Processing $machine via $env:computername"
$dow = [int]$(get-date).DayOfWeek
if ($dow -eq $DayOfWeekForFullBackup){
$prefix="Weekly"
}
$DateStamp=$(((get-date)).ToString("yyyyMMddTHHmmss"))
if ($level -eq "Full"){$Backup=" Bacula -*"}Else{$Backup=" Bacula -$level*"}
#$HyperVPath="C:Hyper-V" #Set path to your Hyper-V Machines to be backed up
#Sort out Actual Volume path to VM
#$VMDrive=$HyperVPath.Substring(0,1)
#$volume=Get-Volume $VMDrive
#$TrueHyperVPath=$($HyperVPath.Replace("$($VMDrive):",$($Volume.path)))
#Get List of VMs
$Cluster = Get-Cluster
# let's initialize it like array (for simplier size check)
$ClusterMachines = @()
$ClusterMachines += Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
if ($ClusterMachines.count -gt 1){
"Ambiguous machine name"
exit 2
}
if ($ClusterMachines.count -ne 1){
"Machine not found: absent, not in failover cluster or something"
exit 2
}
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
write-host "Working on VM $($vm.Name) @ '$($vm.Path)'"
$CurrentSnapShots = $VM | Get-VMSnapshot
foreach ($SnapShot in $CurrentSnapShots){
if ($SnapShot.Name -like ("$($prefix)Backup*")){
write-host "Removing VM Checkpoint '$($SnapShot.Name)'"
$SnapShot | Remove-VMSnapshot # -ComputerName $ClusterMachine.OwnerNode
$LoopCount=0
do {
Write-host "Waiting for snapshot '$($SnapShot.name)' to delete..."
Start-Sleep -s 10
$LoopCount=$LoopCount+1
}while ($VM.Status -eq "Merging disks" -and $LoopCount -lt 30)
}
}
$label = "$($prefix)Backup-$level-$DateStamp"
write-host "Creating Checkpoint $label ($($VM.Name))"
$VM | Checkpoint-VM -SnapshotName $label
}
Удаление:
#Copyright disclaimer:
# Copyright (C) 2015, ITHierarchy Inc (www.ithierarchy.com). ALl rights reserverd.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Param(
[string]$level,
[string]$machine = "noexist.example.com",
[string]$vmmserver = "vldvmm.example.com"
)
Import-Module failoverclusters
$Cluster = Get-Cluster
$ClusterMachines = Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
# FIXME foreach по идее лишний
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
write-host "Working on VM $($vm.Name) @ '$($vm.Path)'"
$CurrentSnapShots = $VM | Get-VMSnapshot
foreach ($SnapShot in $CurrentSnapShots){
if ($SnapShot.Name -like ("Backup*")){
write-host "Removing VM Checkpoint '$($SnapShot.Name)'"
$SnapShot | Remove-VMSnapshot # -ComputerName $ClusterMachine.OwnerNode
$LoopCount=0
do {
Write-host "Waiting for snapshot '$($SnapShot.name)' to delete..."
Start-Sleep -s 10
$LoopCount=$LoopCount+1
}while ($VM.Status -eq "Merging disks" -and $LoopCount -lt 30)
}
}
}
Снапшот можно не удалять, тогда получится делать инкрементальные бэкапы (в скрипте есть зачатки такой функциональности — DayOfWeekForFullBackup).
Мы используем ленточные библиотеки: такая двухюнитовая двухъюнитовая двухвершковая коробка с кассетами, одним или двумя стриммерами и роботом-авточейнджером. Bacula, а по наследству и Bareos, с лентами отлично дружат (лучше, чем с HDD). Что меня смутило — в одной библиотеке бареос обнаружил два авточейнджера, такого быть не должно. Выяснилось, что устройство было программно разделено на две «логические библиотеки» ещё со времён борьбы с DPM. Идём в админку устройства и отключаем это ненужно, теперь в системе правильное количество чейнджеров — один. Устройства покажет команда «ls /dev/tape/by-id/», с суффиксом "-nst" — пишущий драйв, без оного — робот-авточейнджер.
Что касается использования двух приводов для параллельной записи в один пул (набор томов): это сократило бы время записи, но делать так не стали. В выделенное окно бэкапов и так вписываемся, а вот расход плёнки может увеличиться. Но если кто захочет параллельную запись, то не забудьте Prefer Mounted Volumes
установить в No
. Писать же в два разных пула можно без проблем и оверхеда.
Scratch-пулы. Хочу обратить на них внимание: из них бареос берёт кассеты для добавления в другие пулы, в которые он собирается писать. Незнакомую кассету без метки бареос в рабочий пул добавлять не станет. Поэтому все новые ленты добавляем в пул Scratch:
label barcodes storage=mylittlestorage slot=1 pool=Scratch
Можно добавить не в Scratch, а сразу в рабочий пул, но если пулов несколько, то не всегда можно предсказать, сколько кассет в каком понадобится. Поэтому пусть берёт сам по необходимости.
Размер блоков и файлов нужно поставить побольше, это благотворно скажется на скорости лент. «If you are configuring an modern drive like LTO-4 or newer, you probably will want to set the Maximum File Size to 20GB», так что не скромничайте.
Чтобы у бареоса не возникло искушения что-нибудь записать на кассету, которая уже находится в далёком сейфе, лучше перед выемкой сменить ей статус с Append на Used:
update volume=KYF389L6 volstatus=Used
Этой же командой можно менять другие свойства кассеты, скажем, переместить в другой пул:
update volume=KYF389L6 pool=Used
Кассету легко выкрасть (ну, легче, чем IBM DS8800), поэтому данные крайне желательно зашифровать. Можно сделать это средствами самой писалки, но я люблю софтовые решения как более универсальные и гибкие. Просто не забудьте [4].
Бывает, что бареос уже когда-то писал метку на кассету, но записи об этой кассете в базе не имеет. Второй раз label не сработает («error: already labeled»), есть команда add, но в моём случае она приводила к проблемам, после неё использовать кассету не получалось. На этот случай родился такой однострочник (выполняется в bash на сервере sd, сам bareos-sd должен быть остановлен):
mtx -f /dev/sg10 load 25 && mt -f /dev/st0 rewind && mt -f /dev/st0 weof && mt -f /dev/st0 rewind && mtx -f /dev/sg10 unload
Если не даёт сделать unload, то предварительно
mt -f /dev/st0 offline
Это когда данные пишутся сначала на SSD (или хотя бы быстрый HDD), а потом уже на ленту. По сравнению с последовательным выполнением, сокращается время работы стриммера (он пишет быстрее) и общее время выполнения заданий, если их много. Если задание одно, то время использования привода также сократится, но общее время выполнения задания вырастет.
Чтобы работало, сначала на стороне sd нужно указать расположение и размер спулера:
Device {
Name = Drive-0
...
# для спулинга
Maximum Concurrent Jobs = 20
Spool Directory = /mnt/backup/spool
Maximum Spool Size = 1950 G
Maximum Job Spool Size = 1200 G
}
а затем уже включить для конкретных заданий:
JobDefs {
Name = "SundayTape"
...
Spool Data = Yes
}
У меня эта директива в шаблоне «ленточного» задания, а для «дисковых» заданий спулинг практически бесполезен.
Принципы такие:
Размер спулера и количество одновременных заданий зависят от общего количества заданий, размеров заданий, скорости чтения данных (которая может упираться в скорость сети или спулера), скорости записи ленты, соотношений размеров и скоростей разных заданий, человеческих желаний (побыстрее получить результат, или поменьше занимать писалку, или поменьше тратить кассет). Всё это можно связать адовым матаном, но я рекомендую настроить спулинг как бог на душу положит, потому что даже упрощённые правила непросты:
Allow Mixed Priority
)Количество одновременно выполняемых заданий ограничивается много где, ищите в документации «Concurrent Jobs =». Мне оказалось удобно везде поставить большое число с запасом, и ограничивать нужным числом на конкретном устройстве (sd device [5]).
Линуксовая привычка — лезть во внутренности, расковыривать и грепать. То же самое хотелось и с файлами-томами бареоса, чтобы можно было найти нужный том и восстановить даже при неработающем директоре. Для этого попробовал на каждое задание создавать новый файл с именем, содержащим имя задания. Пришлось удалять устаревшие тома скриптом по крону, а ещё следить, чтобы у каждого тома было задание в базе и наоборот. Бареос быстро начал обрастать жуткими костылями, решено было отказаться от человекочитаемого именования, использовать бессмысленные имена и Recycle (очистка и повторное использование файла для другого задания). Всё-таки без директора никуда, при потере серверной в первую очередь нужно восстанавливать именно его.
А ещё IBM рекомендует [6] хранить одно задание в одном файле, и пока что я с ними согласен.
Некоторые отчётные удобства на улице^W^W тоже пришлось добавить скриптами. Самым востребованным оказался скрипт, возвращающий статус последнего запуска задания.
#!/bin/bash
RED='33[0;31m'
NC='33[0m' # No Color
GREEN='33[0;32m'
YELLOW='33[0;33m'
JOBS=`su - postgres -c "psql -d bareos -c "WITH summary AS (
SELECT name,jobstatus,jobid,
ROW_NUMBER() OVER(PARTITION BY name ORDER BY starttime DESC) AS rk
FROM job p WHERE starttime > current_date - INTERVAL '5 days')
SELECT s.* FROM summary s WHERE s.rk=1;"" | grep "1$" | sed 's/ //g'`
#echo "$JOBS"
for job in $JOBS; do
jobstatus=`echo $job | cut -d '|' -f2`
jobname=`echo $job | cut -d '|' -f1`
jobid=$(echo $job | cut -d '|' -f3)
if [ "$jobstatus" == "R" ]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$YELLOW running$NC ($jobstatus)"
elif [ "$jobstatus" == "W" ]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$YELLOW warning$NC ($jobstatus)"
elif [ "$jobstatus" == "T" ]; then
if [[ $1 == "printall" ]]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$GREEN OK$NC ($jobstatus)"
fi
else
printf "%-30s" "$jobname ($jobid)"
echo -e "$RED failed$NC ($jobstatus)"
fi
done
Первоначальный вариант скрипта проверял ещё и факт шифрования, но это оказалось перебдением. Если возникают проблемы с шифрованием, то задание фатально завершается, что будет видно опять же по статусу.
#!/bin/bash
JOBS=`su - postgres -c "psql -d bareos -c "
SELECT name,starttime,jobstatus
FROM job p WHERE starttime > current_date - INTERVAL '62 days' AND name = '$1'
ORDER BY starttime DESC LIMIT 1;"" | sed 's/ //g' | grep "|.$"`
for job in $JOBS; do
jobname=`echo $job | cut -d '|' -f1`
jobstatus=`echo $job | cut -d '|' -f3`
if [ "$jobstatus" == "E" ] || [ "$jobstatus" == "f" ]; then
#echo "Job $jobname failed ($jobstatus)."
echo "3"
exit
elif [ "$jobstatus" == "W" ]; then
#echo "Job $jobname with warning ($jobstatus)."
echo "1"
exit
elif [ "$jobstatus" != "T" ] && [ "$jobstatus" != "R" ]; then
#echo "Job $jobname not ok ($jobstatus)."
echo "2"
exit
elif [ "$jobfiles" == 0 ] || [ "$jobbytes" == 0 ] ; then
#echo "Job $jobname is empty."
echo "4"
exit
else
echo "0"
exit
fi
done
Скрипт для дискаверинга (LLD) приколочен к формату вывода bconsole и легко может сломаться, но пока работает. И JSON лепится руками, но пока тоже работает.
#!/bin/bash
FIRST=true
JOBS=$(echo "show jobs" | bconsole | grep "^ *Name = |Enabled = no" | sed 'N;/n Enabled = no/d;P;D' | grep -v -e "-test"$" | cut -d'=' -f 2 | grep -o "[a-zA-Z0-9_-]*" )
echo '{
"data": ['
for job in $JOBS; do
if [ "$FIRST" = false ]; then
echo -n ","
fi
FIRST=false
echo ""
echo " {"
echo " "{#JOBNAME}": "$job""
echo -n " }"
done
echo '
]
}'
А ещё я люблю stacked-графики в заббиксе, вот, например, занятый разными заданиями объём пленки:
Видно, что синее задание пора поделить на несколько маленьких.
Задавайте вопросы, софтина чёткая, хотя и с характером, мне хочется поспособствовать её распространению.
И не забывайте проверять свои бэкапы. [9]
Автор: muon
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/rezervnoe-kopirovanie/263430
Ссылки в тексте:
[1] всеобъемлющий мануал: http://doc.bareos.org/master/html/bareos-manual-main-reference.html
[2] хостинг: https://www.reg.ru/?rlink=reflink-717
[3] здесь: https://habrahabr.ru/company/simnetworks/blog/313124/
[4] не забудьте: http://doc.bareos.org/master/html/bareos-manual-main-reference.html#x1-39200030
[5] sd device: http://doc.bareos.org/master/html/bareos-manual-main-reference.html#directiveDirStorageMaximum%20Concurrent%20Jobs
[6] IBM рекомендует: http://www.ibm.com/developerworks/ru/library/l-Backup_4/
[7] репликой постгреса: https://www.8host.com/blog/replikaciya-baz-dannyx-postgresql-po-tipu-masterslave/
[8] отсюда: https://github.com/bareos/fastlzlib/
[9] проверять свои бэкапы.: http://checkyourbackups.work/
[10] Источник: https://habrahabr.ru/post/275259/
Нажмите здесь для печати.