Сегодня про восстановление доступа к виртуальной машине с 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-админам :)
Комментарии (22)
izzholtik
05.04.2017 18:31+1netcat позволяет пересылать файлы гораздо удобнее. *морщится*
https://superuser.com/questions/98089/sending-file-via-netcat
$ whereis nc
nc: /bin/nc.openbsd
Tallanvor
05.04.2017 21:59Возможно, побуду К.О., но если всё так трепетно 100500 раз проверялось перед запуском, то почему не использовался ключ --dry-run для rsync перед реальным выполнением?
Но за метод — отдельное «спасибо», отправил в копилку.
Мало ли как оно в будущем сложится ;)
mikhailnk
05.04.2017 22:04Прогон rsync -n не всегда уместен с т.з. результата ибо данные могут меняться во время синхронизации рабочей систему, а могут и нет.
Человеческий фактор не всегда предугадаешь. После того случая — только копипаст уже отработанного.
Merkat0r
05.04.2017 22:56+1бекапы сделали сами
дак и достали бы весь */*/bin (ну или ldd rsync и тока их), НО
Проверяем заработал ли rsync, если нет — смотрим чего не хватает, если да — запускаем rsync,
Почему было просто не взять static-linked rsync ?:)
т.е. каждый администратор помимо сертификации RHCE должен уметь её решать + интересно давать её на собеседовании linux-админам
А зачем сертификация? Чтобы еще раз доказать, что она бесполезна? :)mikhailnk
05.04.2017 23:28Бекапы приклада. ОС можно восстановить в любом случае и довольно быстро.
Да, думали на эту тему, решили, что быстрее и надёжнее будет восстановить все как было + на static-linked пришлось потратить время на поиск/закачку и пр. Но как вариант это сработает.
Сертификация как результат не важна. А вот подготовка — другое дело. Опыт не всегда перекрывает все темы разом и, как правило, без системный.
AlexeySaff
06.04.2017 10:21dry-run в rsync для проверки никто не отменял.
влезли в жопу, а потом героически ее победилиmikhailnk
06.04.2017 10:27Про dry-run — см. выше, он не всегда уместен. Попробуйте проанализировать результат на часто меняющихся данных с множеством файлов (например, кеш с много млрд файлов или огромный массив изменяемых данных (бд)).
Про геройство — кто бы спорил :) Но факт остаётся фактом, ни кто не застрахован от ошибок. Главное из любой ситуации важно выйти и сделать выводы, чтобы в будущем подобные ситуации не повторялись.darken99
06.04.2017 14:13А вы, простите, БД файлами копируете? :)
mikhailnk
06.04.2017 14:29+1Зависит от задачи. Частенько бывало и такое (например, когда репликация не возможна, а объём десятки-сотни Гб). Естественно, финальный прогон когда база остановлена.
Сейчас есть другие средства миграции/конвертеры и пр., которые позволяют более-менее мигрировать без головной боли.
BcTpe4HbIu
06.04.2017 12:40При живом баше можно было обойтись без nc на принимающем сервере.
На доноре:
nc -l -p 8080 < test.tgz
На принимающем:
cat - > test.tgz < /dev/tcp/donor.server/8080
mikhailnk
06.04.2017 12:47да, верно, это еще один из вариантов транспорта, но все же конверт в UUE лучше проделать ибо могут быть коллизии при передачи непечатаемых символов.
4144
06.04.2017 19:24Можно попробовать запустить на сервере, на котором происходят работы:
1. sshfs смонтировать директорию с другого сервера.
2. открыть ssh соединение на тот сервер, откуда смонтирована директория.
3. запустить mc.
Если на текущем сервере что-то повреждается, то по ssh можно сразу сделать исправление на удаленном сервере. потом при помощи mc и sshfs скопировать на сервер с повреждением.
Можно заменить mc на busybox или еще что-то. но с mc сложнее еще раз ошибиться.mikhailnk
06.04.2017 21:56В данному случае даже новую сессию открыть не получалось (дубликат текущей, из-за отсутствие библиотек) + для sshfs требуется fuse, который не входит в минимальную установку. Если же работает запуск отдельных сессий, то проще scp/rsync использовать.
Вариантов решения много, но главная проблема — транспорт.
4144
07.04.2017 00:22это не инструкция как исправить уже случившуюся проблему, а инструкция для предварительных действий.
В такой конфигурации я удалил libc, но все нормально восстановилось. скопировал через sshfs и mc распакованный пакет.mikhailnk
07.04.2017 01:15«Правильное решение» в данном случае должно было быть на административном уровне, а не техническом ибо все мы люди и человеки, но любой косяк технаря должен быть предусмотрен заранее.
На техническом можно было развернуть резервную систему в ОЗУ и при необходимости переключиться на нее. Вот только там могли быть другие косяки и другие ветви развития событий…
PinGniX
Не совсем понятно как Вы запустили telnet если он хранится как раз в /usr/bin, который был удален:
mikhailnk
Ситуация — частный случай, telnet, busybox и еще пару утилит работали (проверяли методом перебора, rsync удаляет не сразу все). В основном были удалены библиотеки, что приводило к ошибке вида:
ValdikSS
Так у вас же busybox был. Наверняка в busybox был wget, даже если ваш busybox был неполноценным. Далее качаем полноценный статический busybox с сайта и делаем все в нем.
mikhailnk
да, busybox был зависимостью от kexec/kdump, что было работоспособно внутри сейчас сказать не могу, но думаю, что тоже вариант.
mikhailnk
подсказка коллеги — тоже тем же способом был передан. т.е. сконвертировали в txt, но копировали через буфер обмена и терминал. Всего-то 140кб.