В последнее время на Хабре было пару интересных статей (например, раз, два и в ряде корп. блогов коллег), после прочтения которых возникла мысль, а не поделиться ли с сообществом опытом по выходу из интересных ситуаций, с которыми сталкивался работая в аутсорсе.

Сегодня про восстановление доступа к виртуальной машине с linux после удаления части операционной системы.

Если содержание будет интересно аудитории, то попробую написать ряд подобных статей.


Постановка задачи


В начале 2012 года потребовалось сделать v2v миграцию нескольких linux виртуальных машин между разными ЦОД-ами. Не помню по какой причине, но выбрали способ через rsync всех разделов (естественно, потом колдовство с настройками ядра/модулями/initrd/grub и пр. стандартные процедуры).

Поскольку сервера были «объемные», данные важные, репликация не возможна, каналы узкие, жёсткие требования downtime, сроки — вчера и т.д. и т.п., то расписали подробный план работ в несколько этапов синхронизаций с последующей досинхронизацией изменений. Важным моментом было отсутствие доступа к консоле виртуальной машины (целевая, откуда мигрировали) ибо она была в приватном облаке. Жёсткие условия диктовал Заказчик (классическое желание все сделать быстро, дешево и качественно), поэтому мы максимально себя обезопасили: о рисках предупредили, бекапы сделали сами и попросили сделать бекап приклада, пользователи сервиса о работах оповещены, весь процесс операции был проработан до мельчайших деталей, «окна» в ночное время оговорены — ничто не предвещало беды.

Начало работ


Далее как по закону Мерфи: если может что-то произойти, то это произойдет.

У нас вмешался человеческий фактор: на этапе досинхронизации администратор перепутал аргументы rsync и случайно поменял местами адреса источника и назначения. От потери данных нас спасло то, что синхронизация была от точки монтирования /usr, а администратор успел заметить и быстро прервал выполнение команды. В итоге под удар попали каталоги /usr/{bin,lib*,sbin} — часть файлов из них были удалены. Основная проблема была в том, что из-за отсутствия многих библиотек нельзя было ни открыть новую сессию, ни запустить rsync, ни восстановить все через пакетный менеджер, в общем осталось только то, что запущено + базовые утилиты без особенных зависимостей. Вечер перестал быть томным…

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

Описание восстановления


Сразу оговорюсь, данный алгоритм не является панацеей и не обязательно оптимальным решением, но у него большой плюс — он быстро и успешно сработал.

Идея в следующем: найти донора, скопировать недостающие данные для запуска rsync, запустить rsync, восстановить все библиотеки/команды, пройтись по системе контролем целостности пакетов/diff-ом с бекапа, затем снять нужные данные.

Тут же были подняты сканы «битого» сервера до работ, найден рабочий сервер с аналогичной ОС, который решили использовать как донора для копирования библиотек и программ с него.

Вопрос с транспортом был открытым — на «битом» сервере ничего не работает. Разве что telnet. Тогда вспомнили что через него можно легко посылать GET запросы. Если можно, значит нужно! Поскольку все в *nix хранится в виде файлов, то можно взять, преобразовать архив с нужными данными в unicode текстовый файл и передать как обычный текст (лучше рабочего способа передать данные относительно консистентными через телнет быстро не нашли).

На проблемном сервере стояла обратная задача, принять данные, сконвертировать в архив, распаковать, привести rsync в рабочее состояние, далее все как по маслу.

На рабочем сервере выполнили ряд действий (условно):

  1. Собираем в архив то, что потребуется:

    tar zcf /tmp/usr.tgz /usr...

  2. Конвертируем из бинарного формата в текстовый:

    cat /tmp/usr.tgz | busybox uuencode -m - > usr.txt

  3. Перемещаем на веб сервер, куда есть доступ с битого сервера:

    mv usr.txt /var/www/html

На сломанном сервере (условно):

  1. Пытаемся скачать файл:

    telnet workserver 80 > usr.txt
        GET /usr.txt

  2. Смотрим сколько строк занимают служебные заголовки 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

  3. Удаляем первые http строки командой (удалить строки с 1 по 12 включительно, до строки begin-base64):

    sed -e '1,12d' usr.txt

  4. Конвертируем обратно из текстового формата в бинарный:

    busybox uudecode -o /root/usr.tgz usr.txt

  5. Распаковываем /root/usr.tgz и руками переносим файлы, что удалены;
  6. Проверяем заработал ли rsync, если нет — смотрим чего не хватает, если да — запускаем rsync, синхронизируем с рабочей копией служебные папки;
  7. Ищем что изменилось (условно):

    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)

  8. В зависимости от затронутых пакетов может потребоваться ребут (после снятия бекапа изменений, проработки вариантов отката на другой сервер и 3-х кратных проверок, что все загрузится, желательно после переустановки ядра).

Итоги


Мы смогли уложиться в выделенное время. Бизнес проблемы не почувствовал. Тем не менее нами был проведен тщательный анализ ситуации и в будущем подобные ошибки уже не повторялись.
С технической стороны были отмечены следующие моменты:

  • Теперь во всех ситуациях, где хранятся исходные данные, файловые системы перед работами перемонтируются в read only режим;
  • Работы выполняются в screen-е;
  • Все команды администраторы, проводящие работы, копируют только из текстового редактора (vi, notepad, etc) для исключения каких-либо ошибок (в этом случае администратор использовал историю для ввода команд и слегка модифицировал). Штатно никаких уходов от плана. Перед этим все проверяется на тестовых стендах, проверяются опытными администраторами;
  • На особо важных операциях всегда дежурит второй более опытный администратор для анализа происходящего и при необходимости перехватывающий управление;
  • Составлен ряд пакетов/ПО, которые устанавливаются на задействованные машины (после выполнения работ на некоторых удаляются по соображениям безопасности) и используются в случае не штатных ситуаций;
  • Теперь данная задача добавлена в список тренировочных задач при обучении сотрудников восстановлению *nix-подобных систем, т.е. каждый администратор помимо сертификации RHCE должен уметь её решать + интересно давать её на собеседовании linux-админам :)
Поделиться с друзьями
-->

Комментарии (22)


  1. PinGniX
    05.04.2017 18:26

    Не совсем понятно как Вы запустили telnet если он хранится как раз в /usr/bin, который был удален:

    $ whereis telnet
    telnet: /usr/bin/telnet
    


    1. mikhailnk
      05.04.2017 21:13

      Ситуация — частный случай, telnet, busybox и еще пару утилит работали (проверяли методом перебора, rsync удаляет не сразу все). В основном были удалены библиотеки, что приводило к ошибке вида:

      XXX: error while loading shared libraries: libXXXX.so: cannot open shared object file: No such file or directory
      


      1. ValdikSS
        08.04.2017 13:56

        Так у вас же busybox был. Наверняка в busybox был wget, даже если ваш busybox был неполноценным. Далее качаем полноценный статический busybox с сайта и делаем все в нем.


        1. mikhailnk
          08.04.2017 18:14

          да, busybox был зависимостью от kexec/kdump, что было работоспособно внутри сейчас сказать не могу, но думаю, что тоже вариант.


    1. mikhailnk
      05.04.2017 21:58

      подсказка коллеги — тоже тем же способом был передан. т.е. сконвертировали в txt, но копировали через буфер обмена и терминал. Всего-то 140кб.


  1. izzholtik
    05.04.2017 18:31
    +1

    netcat позволяет пересылать файлы гораздо удобнее. *морщится*
    https://superuser.com/questions/98089/sending-file-via-netcat

    $ whereis nc
    nc: /bin/nc.openbsd


    1. Evengard
      05.04.2017 19:46

      netcat мог быть не установлен. Например, в debian это отдельный пакет, по умолчанию не устанавливаемый.


      1. mikhailnk
        05.04.2017 21:17

        совершенно верно, nc в rhel-подобных ОС пакет есть, но в минимальную установку не входит.


  1. Tallanvor
    05.04.2017 21:59

    Возможно, побуду К.О., но если всё так трепетно 100500 раз проверялось перед запуском, то почему не использовался ключ --dry-run для rsync перед реальным выполнением?

    Но за метод — отдельное «спасибо», отправил в копилку.
    Мало ли как оно в будущем сложится ;)


  1. mikhailnk
    05.04.2017 22:04

    Прогон rsync -n не всегда уместен с т.з. результата ибо данные могут меняться во время синхронизации рабочей систему, а могут и нет.
    Человеческий фактор не всегда предугадаешь. После того случая — только копипаст уже отработанного.


  1. Merkat0r
    05.04.2017 22:56
    +1

    бекапы сделали сами

    дак и достали бы весь */*/bin (ну или ldd rsync и тока их), НО

    Проверяем заработал ли rsync, если нет — смотрим чего не хватает, если да — запускаем rsync,


    Почему было просто не взять static-linked rsync ?:)

    т.е. каждый администратор помимо сертификации RHCE должен уметь её решать + интересно давать её на собеседовании linux-админам

    А зачем сертификация? Чтобы еще раз доказать, что она бесполезна? :)


    1. mikhailnk
      05.04.2017 23:28

      Бекапы приклада. ОС можно восстановить в любом случае и довольно быстро.

      Да, думали на эту тему, решили, что быстрее и надёжнее будет восстановить все как было + на static-linked пришлось потратить время на поиск/закачку и пр. Но как вариант это сработает.

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


  1. AlexeySaff
    06.04.2017 10:21

    dry-run в rsync для проверки никто не отменял.

    влезли в жопу, а потом героически ее победили


    1. mikhailnk
      06.04.2017 10:27

      Про dry-run — см. выше, он не всегда уместен. Попробуйте проанализировать результат на часто меняющихся данных с множеством файлов (например, кеш с много млрд файлов или огромный массив изменяемых данных (бд)).

      Про геройство — кто бы спорил :) Но факт остаётся фактом, ни кто не застрахован от ошибок. Главное из любой ситуации важно выйти и сделать выводы, чтобы в будущем подобные ситуации не повторялись.


      1. darken99
        06.04.2017 14:13

        А вы, простите, БД файлами копируете? :)


        1. mikhailnk
          06.04.2017 14:29
          +1

          Зависит от задачи. Частенько бывало и такое (например, когда репликация не возможна, а объём десятки-сотни Гб). Естественно, финальный прогон когда база остановлена.

          Сейчас есть другие средства миграции/конвертеры и пр., которые позволяют более-менее мигрировать без головной боли.


  1. BcTpe4HbIu
    06.04.2017 12:40

    При живом баше можно было обойтись без nc на принимающем сервере.


    На доноре:


    nc -l -p 8080 < test.tgz

    На принимающем:


    cat - > test.tgz < /dev/tcp/donor.server/8080


    1. mikhailnk
      06.04.2017 12:47

      да, верно, это еще один из вариантов транспорта, но все же конверт в UUE лучше проделать ибо могут быть коллизии при передачи непечатаемых символов.


  1. 4144
    06.04.2017 19:24

    Можно попробовать запустить на сервере, на котором происходят работы:
    1. sshfs смонтировать директорию с другого сервера.
    2. открыть ssh соединение на тот сервер, откуда смонтирована директория.
    3. запустить mc.

    Если на текущем сервере что-то повреждается, то по ssh можно сразу сделать исправление на удаленном сервере. потом при помощи mc и sshfs скопировать на сервер с повреждением.

    Можно заменить mc на busybox или еще что-то. но с mc сложнее еще раз ошибиться.


    1. mikhailnk
      06.04.2017 21:56

      В данному случае даже новую сессию открыть не получалось (дубликат текущей, из-за отсутствие библиотек) + для sshfs требуется fuse, который не входит в минимальную установку. Если же работает запуск отдельных сессий, то проще scp/rsync использовать.

      Вариантов решения много, но главная проблема — транспорт.


  1. 4144
    07.04.2017 00:22

    это не инструкция как исправить уже случившуюся проблему, а инструкция для предварительных действий.
    В такой конфигурации я удалил libc, но все нормально восстановилось. скопировал через sshfs и mc распакованный пакет.


    1. mikhailnk
      07.04.2017 01:15

      «Правильное решение» в данном случае должно было быть на административном уровне, а не техническом ибо все мы люди и человеки, но любой косяк технаря должен быть предусмотрен заранее.
      На техническом можно было развернуть резервную систему в ОЗУ и при необходимости переключиться на нее. Вот только там могли быть другие косяки и другие ветви развития событий…