В последнее время на Хабре было пару интересных статей (например, раз, два и в ряде корп. блогов коллег), после прочтения которых возникла мысль, а не поделиться ли с сообществом опытом по выходу из интересных ситуаций, с которыми сталкивался работая в аутсорсе.
Сегодня про восстановление доступа к виртуальной машине с linux после удаления части операционной системы.
Если содержание будет интересно аудитории, то попробую написать ряд подобных статей.
Постановка задачи
В начале 2012 года потребовалось сделать v2v миграцию нескольких linux виртуальных машин между разными ЦОД-ами. Не помню по какой причине, но выбрали способ через rsync всех разделов (естественно, потом колдовство с настройками ядра/модулями/initrd/grub и пр. стандартные процедуры).
Поскольку сервера были «объемные», данные важные, репликация не возможна, каналы узкие, жёсткие требования downtime, сроки — вчера и т.д. и т.п., то расписали подробный план работ в несколько этапов синхронизаций с последующей досинхронизацией изменений. Важным моментом было отсутствие доступа к консоле виртуальной машины (целевая, откуда мигрировали) ибо она была в приватном облаке. Жёсткие условия диктовал Заказчик (классическое желание все сделать быстро, дешево и качественно), поэтому мы максимально себя обезопасили: о рисках предупредили, бекапы сделали сами и попросили сделать бекап приклада, пользователи сервиса о работах оповещены, весь процесс операции был проработан до мельчайших деталей, «окна» в ночное время оговорены — ничто не предвещало беды.
Начало работ
Далее как по закону Мерфи: если может что-то произойти, то это произойдет.
У нас вмешался человеческий фактор: на этапе досинхронизации администратор перепутал аргументы rsync и случайно поменял местами адреса источника и назначения. От потери данных нас спасло то, что синхронизация была от точки монтирования /usr, а администратор успел заметить и быстро прервал выполнение команды. В итоге под удар попали каталоги /usr/{bin,lib*,sbin} — часть файлов из них были удалены. Основная проблема была в том, что из-за отсутствия многих библиотек нельзя было ни открыть новую сессию, ни запустить rsync, ни восстановить все через пакетный менеджер, в общем осталось только то, что запущено + базовые утилиты без особенных зависимостей. Вечер перестал быть томным…
Далее понеслось: был организован мозговой штурм, проверка гипотез и выход из ситуации. Всем было «весело». Параллельно прорабатывался вариант с выполнение работ «с нуля» и запуск того, что осталось, но это означало бы срыв сроков и потерю измененных данных.
Описание восстановления
Сразу оговорюсь, данный алгоритм не является панацеей и не обязательно оптимальным решением, но у него большой плюс — он быстро и успешно сработал.
Идея в следующем: найти донора, скопировать недостающие данные для запуска rsync, запустить rsync, восстановить все библиотеки/команды, пройтись по системе контролем целостности пакетов/diff-ом с бекапа, затем снять нужные данные.
Тут же были подняты сканы «битого» сервера до работ, найден рабочий сервер с аналогичной ОС, который решили использовать как донора для копирования библиотек и программ с него.
Вопрос с транспортом был открытым — на «битом» сервере ничего не работает. Разве что telnet. Тогда вспомнили что через него можно легко посылать GET запросы. Если можно, значит нужно! Поскольку все в *nix хранится в виде файлов, то можно взять, преобразовать архив с нужными данными в unicode текстовый файл и передать как обычный текст (лучше рабочего способа передать данные относительно консистентными через телнет быстро не нашли).
На проблемном сервере стояла обратная задача, принять данные, сконвертировать в архив, распаковать, привести rsync в рабочее состояние, далее все как по маслу.
На рабочем сервере выполнили ряд действий (условно):
- Собираем в архив то, что потребуется:
tar zcf /tmp/usr.tgz /usr...
- Конвертируем из бинарного формата в текстовый:
cat /tmp/usr.tgz | busybox uuencode -m - > usr.txt
- Перемещаем на веб сервер, куда есть доступ с битого сервера:
mv usr.txt /var/www/html
На сломанном сервере (условно):
- Пытаемся скачать файл:
telnet workserver 80 > usr.txt GET /usr.txt
- Смотрим сколько строк занимают служебные заголовки head -30 usr.txt (можно сразу через sed отрезать base64, но для подстраховки решили посмотреть руками):
Trying workserver... Connected to workserver. Escape character is '^]'. HTTP/1.1 200 OK Date: Fri, 17 Jan 2013 13:13:50 GMT Server: Apache Last-Modified: Fri, 17 Jan 2013 13:11:32 GMT Accept-Ranges: bytes Content-Length: 262635116 Connection: close Content-Type: text/plain; charset=utf-8 begin-base64 644 - bmV0LnNoLm1lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- Удаляем первые http строки командой (удалить строки с 1 по 12 включительно, до строки begin-base64):
sed -e '1,12d' usr.txt
- Конвертируем обратно из текстового формата в бинарный:
busybox uudecode -o /root/usr.tgz usr.txt
- Распаковываем /root/usr.tgz и руками переносим файлы, что удалены;
- Проверяем заработал ли rsync, если нет — смотрим чего не хватает, если да — запускаем rsync, синхронизируем с рабочей копией служебные папки;
- Ищем что изменилось (условно):
rpm -Va | tr -s ' ' | sed -e 's/ d / /g' | sed -e 's/ c / /g' | cut -f2 -d' ' > va2.xt rpm -qf $(cat va2.xt) | sort -n | uniq > reinstall.pkg yum -y reinstall $(cat reinstall.pkg)
- В зависимости от затронутых пакетов может потребоваться ребут (после снятия бекапа изменений, проработки вариантов отката на другой сервер и 3-х кратных проверок, что все загрузится, желательно после переустановки ядра).
Итоги
Мы смогли уложиться в выделенное время. Бизнес проблемы не почувствовал. Тем не менее нами был проведен тщательный анализ ситуации и в будущем подобные ошибки уже не повторялись.
С технической стороны были отмечены следующие моменты:
- Теперь во всех ситуациях, где хранятся исходные данные, файловые системы перед работами перемонтируются в read only режим;
- Работы выполняются в screen-е;
- Все команды администраторы, проводящие работы, копируют только из текстового редактора (vi, notepad, etc) для исключения каких-либо ошибок (в этом случае администратор использовал историю для ввода команд и слегка модифицировал). Штатно никаких уходов от плана. Перед этим все проверяется на тестовых стендах, проверяются опытными администраторами;
- На особо важных операциях всегда дежурит второй более опытный администратор для анализа происходящего и при необходимости перехватывающий управление;
- Составлен ряд пакетов/ПО, которые устанавливаются на задействованные машины (после выполнения работ на некоторых удаляются по соображениям безопасности) и используются в случае не штатных ситуаций;
- Теперь данная задача добавлена в список тренировочных задач при обучении сотрудников восстановлению *nix-подобных систем, т.е. каждый администратор помимо сертификации RHCE должен уметь её решать + интересно давать её на собеседовании linux-админам :)
Автор: mikhailnk