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

в 7:46, , рубрики: backup, badoo, puppet, баду, Блог компании Badoo, бэкап, ит-инфраструктура, системное администрирование, метки: , , , ,

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

Большинство статей в наш блог пишут разработчики. Мы решили исправить эту несправедливость и добавить немного 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.ableevs*' | /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/

Автор: ableev

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js