
Как развернуть несколько сотен серверов в географически удаленном дата-центре при отсутствии физического доступа к оборудованию? Как компания Badoo решает такую задачу?
Мы расскажем вам об этом на следующем примере.
Ниже пойдет речь о самом первом этапе конфигурирования серверного оборудования; о том, как быстро и в срок мы выполнили конкретную задачу, а не о написании оптимальных скриптов. В случае, если данная тема покажется вам интересной, мы с удовольствием расскажем и об установке ОС на сервера и настройке рабочего окружения, в чём тоже имеются свои тонкости.
Итак, перед нами была поставлена задача развернуть несколько сотен новых серверов, только что прибывших в два наших дата-центра.
При успешном выполнении, на выходе мы должны получить:
- описание всей «железной» составляющей по каждому серверу;
- соответствие заказанного оборудования полученному (бывают случаи, что приходит не та конфигурация, которую заказывали);
- готовые к установке ОС и ПО сервера (с обновленными версиями прошивок RAID, ROM и т.д., сконфигурированными RAID-массивами, без проблем с «железом»).
- сервера смонтированы в стойки/шкафы и включены;
- известны заводские логины и пароли;
- все сервера имеют IPMI-интерфейс (интерфейс управления);
- на серверах отсутствуют какие-либо предустановки от производителя (в частности, не сконфигурирован RAID, не выставлены настройки энергопотребления);
- все сервера подключены к сетевому оборудованию минимум двумя интерфейсами, находятся в заранее известном VLAN;
- новые сервера получают свои IP-адреса динамически, соответственно, они доступны сразу после включения;
- известно, сколько серверов каких конфигураций должно было быть в поставке.
Чаще всего, подобного рода задачи предлагают решать с помощью dd, PXE-сервера и rsync, постановки задач, привлекая сотрудников дата-центра. Но мы подошли к вопросу иначе.
Найденное нами решение предполагает некоторую автоматизацию. Пожалуйста, примите к сведению, что все приведенные ниже скрипты носят исключительно ознакомительный характер и не претендуют на безупречность.
Для выполнения поставленной задачи нам потребовалось:
- несколько текстовых файлов, которые по окончании работ удаляются;
- несколько совсем простых скриптов, использующих expect;
- настроенный сервер сетевой загрузки (в нашем случае это xCAT);
- настроенный и рабочий образ ОС (неважно какой, главное, чтобы в этот образ входили все нужные нам утилиты);
- настроенная система инвентаризации оборудования (в нашем случае это glpi project).
ILOHOSTNAME1 ILOPASSWORD1 ILOHOSTNAME2 ILOPASSWORD2
Эти данные мы получили с наклеек, имеющихся на каждом сервере, с помощью сканера штрих-кодов. Стандартный логин был известен заранее – Administrator. Пример наклейки:

Теперь можно было запускать команду, которая собирала нам соответствия hostname и IP:
for i in $(cat nodes | awk {'print $1'}); do j=$(cat nodes | grep $i | awk {'print $2'}); ssh DHCPD_SERVER_FQDN "sudo cat /var/log/messages | grep $i | tail -1 | sed 's/$/ '$j'/g'"; done
В результате мы получали строки наподобие приведенных ниже, складывали их в файл nodeswip:
Jul 1 10:31:23 local@DHCPD_SERVER dhcpd: DHCPACK on 10.10.10.213 to 9c:8e:99:19:3a:68 (ILOUSE125NDBF) via 10.10.10.1 W3G554L7 Jul 1 10:31:35 local@DHCPD_SERVER dhcpd: DHCPACK on 10.10.10.210 to 9c:8e:99:19:b6:aa (ILOUSE125NDBA) via 10.10.10.1 BJCP691P Jul 1 10:31:47 local@DHCPD_SERVER dhcpd: DHCPACK on 10.10.10.211 to 9c:8e:99:19:58:7c (ILOUSE125NDBG) via 10.10.10.1 67MG91SV
Теперь нам требовалось создать стандартного пользователя с набором доступных ему прав на всех IPMI интерфейсах новых серверов. Здесь же нужно было получить MAC адреса net и mgm интерфейсов для дальнейшей структуризации. Для этого мы выполнили команду
for i in $(cat nodeswip | awk {'print $8'}); do j=$(grep $i nodeswip|awk {'print $14'}); expect expwip.sh $i $j | grep Port1NIC_MACAddress; done;
где sh-скрипт expwip.sh выглядел следующим образом:
#!/usr/bin/expect set timeout 600 set ip [lindex $argv 0] set pass [lindex $argv 1] spawn ssh Administrator@$ip set answ "$pass" set comm1 "create /map1/accounts1 username=deployer password=PASSWORD name=deployer group=admin,config,oemhp_vm,oemhp_power,oemhp_rc" expect "Administrator@$ip's password:" send "$answ\r" expect "</>hpiLO->" send "$comm1\r" expect "</>hpiLO->" send "show /system1/network1/Integrated_NICs\r" expect "</>hpiLO->" send "exit\r" expect eof
Полученный список MAC-адресов net интерфейсов наших серверов добавлялся в табличный редактор, что позволяло нам видеть все соответствия.
Затем мы выполняли действия по формированию конфига для DHCP-сервера, после чего отправляли сервера в netboot. После этого нам нужно было отправить IPMI-интерфейсы в перезагрузку для того, чтобы они заняли намеченные для них адреса. Это делалось с помощью команды
expect reset_ilo.sh $i $j
где $i – это адрес сервера, полученый ранее, $j – это заводской пароль администратора
Скрипт reset_ilo.sh выглядел так:
#!/usr/bin/expect set timeout 600 set ip [lindex $argv 0] set pass [lindex $argv 1] spawn ssh Administrator@$ip set answ "$pass" set comm1 "reset /map1" expect "Administrator@$ip's password:" send "$answ\r" expect "</>hpiLO->" send "$comm1\r" expect eof
Далее мы переходили к автоматическому формированию RAID-массивов, обновлению всех возможных версий firmware на «железе», получению исчерпывающей информации по компоновке серверов в удобном виде. Все эти операции выполнялись при сетевой загрузке.
Сначала стартовал init-скрипт, который «готовил» RAID-массив:
LD=`/usr/sbin/hpacucli ctrl slot=0 logicaldrive all show|awk '$0 ~ /RAID 5/ || /RAID 0/ || /RAID 1/ {print $1" "$2}'` LD=${LD:-NULL} if [ "$LD" != "NULL" ]; then /usr/sbin/hpacucli ctrl slot=0 $LD delete forced; fi /usr/sbin/hpacucli ctrl slot=0 create type=ld drives=`/usr/sbin/hpacucli ctrl slot=0 physicaldrive all show|awk '$1 ~ /physicaldrive/{split($2,arr,":");print $2}'|tr "\n" ","|sed 's/,$//'` raid=1+0 if [ `/usr/sbin/hpacucli ctrl slot=0 physicaldrive all show | grep physicaldrive | wc -l` -gt 1 ]; then r=`/usr/sbin/hpacucli ctrl slot=0 physicaldrive all show | grep physicaldrive | wc -l`; let t=$r%2; if [ $t -ne 0 ]; then let tl=$r-1; /usr/sbin/hpacucli ctrl slot=0 create type=ld drives=`/usr/sbin/hpacucli ctrl slot=0 physicaldrive all show|grep physicaldrive | head -$tl|awk '$1 ~ /physicaldrive/{split($2,arr,":");print $2}'|tr "\n" ","|sed 's/,$//'` raid=1+0; /usr/sbin/hpacucli ctrl slot=0 array all add spares=`/usr/sbin/hpacucli ctrl slot=0 physicaldrive all show|grep physicaldrive | tail -1|awk '$1 ~ /physicaldrive/{split($2,arr,":");print $2}'|tr "\n" ","|sed 's/,$//'`; fi; fi
В результате мы получали 1+0 или «зеркало». Затем выполнялся запуск агента, который отправлял информацию о «железе» в нашу систему инвентаризации. Мы используем fusion inventory agent, в настройках которого не меняли ничего, кроме адреса сервера сбора информации. Результат виден в интерфейсе Fusion Inventory:

Последним запускался скрипт, который обновлял все firmware на «железе». Для этого использовались несколько классов в puppet, которые выполнялись на новых серверах. Ниже приведен пример класса, который «смотрит» на текущую конфигурацию сервера и, в случае необходимости, обновляет версию прошивки RAID-контроллера до требуемой. По такому же сценарию выполнялись и остальные обновления прошивок «железа».
class hp_raid_update_rom { exec { "updateraid": command => "wget -P /tmp/ http://WEBSERVER/install/soft/firmware/hp/raid/5_12/CP015960.scexe; wget -P /tmp/ http://WEBSERVER/install/soft/update_hp_raid_firmware_512.sh; chmod +x /tmp/CP015960.scexe; chmod +x /tmp/update_hp_raid_firmware_512.sh; /tmp/update_hp_raid_firmware_512.sh; echo '5.12' > /tmp/firmware_raid", onlyif => "/usr/bin/test `/sbin/lspci | grep -i 'Hewlett-Packard Company Smart Array G6' | wc -l` != '0' && /usr/bin/test `/usr/sbin/hpacucli ctrl all show detail | grep -i firmware | awk {'print \$3'}` != '5.12' && ( [ ! -f /tmp/firmware_raid ] || [ `cat /tmp/firmware_raid` != '5.12' ])", path => "/usr/bin:/bin", require => Exec["remove_report_file", "remove_empty_report_file"], } exec { "remove_report_file": command => "/bin/rm /tmp/firmware_raid", onlyif => "[ -f /tmp/firmware_raid ] && [ `cat /tmp/firmware_raid` == `/usr/sbin/hpacucli ctrl all show detail | grep -i firmware | awk {'print \$3'}` ]", path => "/usr/bin:/bin", } exec { "remove_empty_report_file": command => "/bin/rm /tmp/firmware_raid", onlyif => "[ -f /tmp/firmware_raid ] && [ `cat /tmp/firmware_raid | wc -l` == '0' ]", path => "/usr/bin:/bin", } }
Таким образом, мы решили поставленную задачу, используя лишь собственные ресурсы. Все наши машины были готовы к установке боевой ОС, установке ПО и началу обслуживания пользователей Badoo.
Все вышеизложенное описывает лишь подготовительный этап настройки оборудования, за рамками статьи остались вопросы установки ОС и конфигурирования рабочего окружения. Если вас интересует данная тема, мы с удовольствием подготовим материал о хСАТ и puppet и поделимся нашими способами решения специфических задач с помощью этих инструментов.
Ваши предложения, вопросы и замечания по вышеизложенному вы можете смело оставлять в комментариях ― мы всегда открыты для диалога!
Компания Badoo