Бюджетное решение для бэкапа целого офиса

от автора

в
Большинство статей в наш блог пишут разработчики. Мы решили исправить эту несправедливость и добавить немного DevOps. Сегодня поговорим о важном ― о бэкапах.
Так как Badoo активно развивается и количество сотрудников постоянно увеличивается, мы пришили к выводу, что централизованное резервное копирование гораздо удобнее, чем частичное копирование и хранение информации в различных местах.
В статье мы рассмотрим, как различными способами «забэкапить» довольно большое количество рабочих станций с помощью одного хранилища, не прибегая к серьёзным вложениям и избегая громоздкой реализации.
Заранее оговоримся, что бэкап не охватывает 100% сотрудников, так как не все хранят свои данные на локальных машинах, поэтому у нас не было цели сделать бэкап обязательно-принудительным.
Одной из основных сложностей централизованного бэкапа стало то, что сотрудники используют разные операционные системы.

Как же мы смогли собрать всех на одном сервере?

Примерная статистика, основанная на использовании нашей системы:
Mac OS ~ 66%;
Linux ~ 27%;
Windows ~ 7%.

А теперь подробнее, что скрывается за этими тремя ОС и каким образом мы будем настраивать их у пользователя.
1) Mac OS ― через Time Machine (в последних версиях Mac OS поддерживается из коробки, ниже 10.6 у нас просто нет), на стороне сервера — Netatalk;
2) Windows ― стандартными средствами через «Архивация и восстановление» (Backup and restore), на стороне сервера — Samba;
3) Linux ― несколько вариантов: samba, rsync (доступ по паролю); полноценный ssh отключён за ненадобностью и в целях безопасности.

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

Администратору нужно выбрать уже существующую учетную запись или завести новую, сгенерировать пароль и указать тип операционной системы.

Аппаратная часть

В качестве хранилища был собран сервер с 24 дисками по 3.5 дюйма и 3 TБ ― большой объём за малые деньги.
Каждый диск монтируется отдельно, RAID или LVM не используется ― при выходе из строя одного из дисков его можно быстро заменить; также решается вопрос с недостатком свободного места: из всех дисков мы выжимаем максимум объёма.
«Что будет, если умрёт один из дисков, на котором были бэкапы пользователей?» ― спросите вы. Попросим забэкапиться ещё раз после замены диска. Вероятность того, что один из 24 дисков умрёт вместе с ноутбуком сотрудника, действительно мала. В крайнем случае мы попытаемся восстановить утраченную информацию.
Главная функция сервера ― хранение информации, поэтому описывать CPU и память не имеет смысла, любые современные процессоры справятся с этим заданием.

Готовим диски

Форматируем и монтируем каждый диск:

parted /dev/sd${i} -s mklabel gpt parted /dev/sd${i} mkpart primary 0GB 2996GB mkfs.ext3 /dev/sd${i}1 

Удаляем зарезервированное пространство суперпользователя:

tune2fs -m 0 /dev/sd${i}1 

В /etc/fstab для каждого раздела прописываем

UUID=${UUID}          /storage/sd${i}1           ext3        noatime,acl,user_xattr,usrquota             0 0 

В итоге получаем диски, смонтированные в директорию /storage/sd${i}, где ${i} ― одна из букв нашего диска.

Монтировать диски лучше с привязкой по UUID, т.к. не исключено «перемешивание» дисков, а с таким количеством устройств нам придётся долго восстанавливать правильные пути после внезапной перезагрузки сервера.
Всех пользователей мы будем ограничивать квотой в файловой системе стандартными средствами Linux, поэтому подготовим для этого диски:

quotacheck -cu /storage/sd${i} 

Программная часть

Netatalk

В данном решении самое сложное ― Mac OS X, поэтому начнём с настройки afp.
Установим необходимые пакеты:

rpm -Uvh libdb-4_8-4.8.30-18.6.x86_64.rpm rpm -Uvh db-utils-4.8.30-18.6.x86_64.rpm rpm -Uvh netatalk-2.2.4-3.7.x86_64.rpm rpm -Uvh netatalk-devel-2.2.4-3.7.x86_64.rpm 

Netatalk будем использовать версии 2.*, т.к. в версии 3.* не поддерживается использование переменных в указаниях путей (http://netatalk.sourceforge.net/3.0/htmldocs/afp.conf.5.html, раздел VARIABLE SUBSTITUTIONS: The use of variables in paths is not supported for now).

Стоит заметить, что пакет Netatalk мы собирали со следующими флагами:

--with-cracklib --with-bdb --enable-tcp-wrappers --enable-zeroconf 

В /etc/netatalk/AppleVolumes.default добавим строчку

~/TimeMachine "BackupMachine" allow:@backupuser cnidscheme:dbd options:usedots,upriv,tm volsizelimit:250000 dbpath:/local/netatalk/db/$u 

в которой:

allow:@backupuser ― разрешает подключаться пользователям, находящимся в группе backupuser;
BackupMachine ― имя, которое будет отображаться как подключённый диск, физически смонтированный в ~/TimeMachine относительно пользователя;
volsizelimit:250000 ― ограничит пользователя квотой в 250 гб, но только если пользователю не задана системная квота. Т.к. в нашем случае мы используем системные квоты, эта опция бесполезна;
tm ― обязательная опция, позволяет TimeMachine на стороне клиента распознать выделенный ресурс, как валидный для бэкапа;
dbpath:/local/netatalk/db/$u ― путь к информации по метаданным пользователя. Нужна в том случае, когда строится список директорий и файлов, которые мы забэкапили. Будет практичней, если это вынести на отдельный диск, например, на SSD;
переменная $u подставляет имя пользователя, которое нам так нужно и не работает в третьей версии.

Включаем логирование afpd.
В /etc/nettalk/afpd.conf добавим строчку

 -setuplog "default log_info /var/log/afpd.log" -keepsessions -transall -savepassword 

в которой:
keepsessions ― сохраняет сессии при выключении afpd;
transall ― включает оба протокола ― AFP-over-Appletalk и AFP-over-TCP;
savepassword ― позволяет запомнить пароль пользователя в локальном keygen (без этой опции TimeMachine в Mac OS 10.8 не работает).

В /etc/netatalk/netatalk.conf
увеличим максимальное количество пользователей до 100

AFPD_MAX_CLIENTS=100 

С Netatalk закончили. Подключиться можно стандартным приложением Time Machine, используя адрес вида afp://%SERVERNAME%/

Samba

Samba будет использоваться для подключения как в Windows, так и в Linux.
Настройка довольно проста: в /etc/samba/smb.confдобавляем

[global]         security = user         workgroup = Badoo         netbios name = BadooBackup         local master = no         domain master = no         preferred master = no         socket options = TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE SO_RCVBUF=8192 SO_SNDBUF=8192 [homes]         comment = Home Directories         valid users = %S         writable = yes         create mask = 0700         directory mask = 0700         browseable = No         read only = No 

На этом настройка закончена. В Windows можно подключаться через «Проводник», в Linux ― автоматически монтировать при входе в систему.

Управление доступом

Итак, мы закончили с аппаратной частью и приложениями. Осталось разобраться с тем, как предоставлять пользователям несколько способов доступа.
Система управления пользователями у нас уже есть, значит, будем использовать привычные для нас манифесты Puppet.

Данные о пользователях будем хранить в интуитивно понятной таблице MySQL:

| backupusers | CREATE TABLE `backupusers` (   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,   `uid` int(11) NOT NULL,   `username` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,   `backup_username` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',   `backup_server` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'backupmsk',   `password` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',   `password_smb` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,   `shell` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '/bin/false',   `map_drive` varchar(6) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'sdc',   `quota` int(5) NOT NULL DEFAULT '250',   `sftp` tinyint(1) NOT NULL DEFAULT '0',   `isactive` tinyint(1) NOT NULL DEFAULT '0',   `os` int(1) DEFAULT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |  

Фреймворк записывает данные именно в эту таблицу.
Несколько особенностей:
поле `map_drive` ― названия сервера и диска, которые будут использоваться для текущего пользователя. Не задается администратором, распределяется автоматически в зависимости от занятого места в том или ином разделе и на сервере. Если места для кого-то хватать не будет, то данные будут перенесены в другой раздел;
поле `isactive` показывает, разрешено ли сотруднику пользоваться сервером для бэкапа. Если все ОС будут неактивны, перейдёт в значение 0. Данные пользователя при этом не удалятся (полезно, например, при потере ноутбука);
поле `sftp` позволяет пользователю использовать rsync (об этом ниже). Этот способ позволит «продвинутым» коллегам бэкапить свои данные, используя самописные скрипты.

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

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

    define backupuser_dirs($name,$map_drive,$home="/home/${name}") {         file {             "$home": owner => $name, ensure => symlink, target => "/storage/${map_drive}/${name}", require => File["/storage/${map_drive}/${name}"];             "/storage/${map_drive}/${name}": owner => $name, ensure => directory, backup => false, mode => 0711;             "$home/TimeMachine": owner => $name, ensure => directory, backup => false, mode => 0711, require => File["$home"];             }     } 

А вот отрывок манифеста для Puppet одного из пользователей:

   @user { "i.ableev": 	        ensure => $hostname ? {                  /^%servername%$/ => present, 	# создаем пользователю доступ именно на этом сервере, где он явно объявлен                 default => absent, 	# во всех остальных случаях доступ, даже если он и был, отзывается                 },           home    => "/home/i.ableev", 	# указываем домашнюю директорию; (!) является симлинком на /storage/$map_drive/$name          uid     => "1217",         groups => ['backupuser'], 	# указываем, в какую группу добавить пользователя         password     =>  'V2UgYXJlIGhpcmluZyEgaHR0cDovL2NvcnAuYmFkb28uY29tL2pvYnMvCg==', 	# пароль используется при использовании Netatalk и rsync         shell   => "/bin/false", 	# отключаем пользователю shell, чтобы ограничить доступ по ssh         }        @backupuser_dirs { "i.ableev":         name => "i.ableev",         map_drive =>"sdh", 	# директория, в которой будет располагаться директория бэкапов пользователя вида /storage/$map_drive/$name         require => User["i.ableev"];         }        @exec { "i.ableev_quota":             command => "/usr/sbin/setquota -u i.ableev 262144000 262144000 0 0 -a",             # выделяем пользователю 250 гб …              path        => "/usr/sbin",                 onlyif      => "/usr/bin/test `/usr/sbin/repquota -ua | /usr/bin/egrep '^i.ableev\s*' | /usr/bin/awk {'print \$4'}` -ne \"262144000\"",             # … но выделяем её в том случае, если квота не равна 250 гб.         }    @line { "i.ableev_smb": 	# добавляем в файл /etc/samba/smbpasswd строчку вида: 	# @user:$uid:$hash                             file => '/etc/samba/smbpasswd',                             line => 'i.ableev:1217:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:5CDA711BBD899465D8F57D12BDF2BF68:[U          ]:LCT-5058462B:', 		# хеш пароля генерируется на этапе формирования манифеста скриптом 	}   

Теперь у пользователей есть возможность подключаться к серверу, используя Mac OS, Windows или Linux.

rsync

Для предоставления доступа через rsync (но не ssh), мы будем использовать chroot плюс ограниченный по возможностям shell. Манифест и функция в таком случае будут выглядеть несоколько иначе:

    define backupuser_dirs_sftp($name,$map_drive,$home) {             file {                 "/home/${name}": owner => $name, ensure => symlink, target => "${home}", require => File["$home"];                 "$home": ensure => directory, owner => root, mode => 0755;                 "$home/sftp": owner => $name, ensure => directory, backup => false, mode => 0711, require => File["$home"];                 }     }                          @user { "i.ableev":                             ensure => $hostname ? {                                     /^backupmsk$/ => present,                                     default => absent,                                     },                                home    => "/storage/sdh/i.ableev",                             uid     => "1217",                             groups => ['backupuser'],                             password     => 'V2UgYXJlIGhpcmluZyEgaHR0cDovL2NvcnAuYmFkb28uY29tL2pvYnMvCg==', 		# задаём пароль для входа                             shell   => "/bin/badooshell", 		# ограниченный shell позволяет использовать только rsync                             }                             @backupuser_dirs_sftp { "i.ableev":                             name => "i.ableev",                             map_drive =>"sdh",                             home => "/storage/sdh/i.ableev", 			# путь к директории ~/sftp ― туда будут складываться бэкапы                             require => User["i.ableev"];                             }                             @file { "/storage/sdh/i.ableev/bin": 			# путь к chroot’у ― здесь будет лежать наш badooshell                             ensure => directory,                             recurse => true,                             purge => true,                             force => true,                             backup => false,                             owner => root,                             group => root,                             source => "puppet:///modules/officebackup/bin/"; 			# отсюда он скачивается                             }                             @file { "/storage/sdh/i.ableev/lib64": 	# минимальный набор библиотек, необходимый для работы  rsync: ld-linux-x86-64.so.2  libc.so.6  libpopt.so.0                             ensure => directory,                             recurse => true,                             purge => true,                             force => true,                             backup => false,                             owner => root,                             group => root,                             source => "puppet:///modules/officebackup/lib64/";                             }  

Все манифесты готовы.

Результаты

Что мы получили в итоге:

  • недорогой сервер с 72 терабайтами полезных данных;
  • на одном сервере находятся бэкапы всех типов операционных систем пользователей;
  • предоставлен доступ всем, кто хочет делать бэкапы.

Enjoy!

Илья Аблеев, ableev, сотрудник эксплуатации Badoo Development

 

Оригинал комикса: dilbert.com/strips/comic/2007-11-21/

ссылка на оригинал статьи http://habrahabr.ru/company/badoo/blog/177349/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *