[Перевод] Как использовать systemd-nspawn для восстановления Linux-системы
Перевод статьи подготовлен специально для студентов курса «Администратор Linux».
Разбираемся со способностью systemd запускать контейнеры для восстановления корневой файловой системы поврежденной системы.
До тех пор пока будут существовать системы GNU/Linux, системным администраторам будет необходимо восстанавливаться после повреждения корневой файловой системы, случайных изменений конфигурации или других ситуаций, которые не дают системе загрузиться в «нормальное» состояние.
Обычно дистрибутивы Linux предлагают одну или несколько опций меню во время загрузки (например, в меню GRUB), которые можно использовать для восстановления поврежденной системы; зачастую они загружают систему в однопользовательском режиме с отключением большинства системных служб. В худшем случае пользователь может изменить командную строку ядра в загрузчике, чтобы использовать стандартную оболочку в качестве процесса init (PID 1). Этот метод является наиболее сложным и чреват затруднениями, которые могут привести к потере времени и фрустрации, в то время как система нуждается в восстановлении.
Самое главное, что все эти методы предполагают, что у поврежденной системы есть какая-либо физическая консоль, но в эпоху облачных вычислений на это уже нельзя полагаться. Без физической консоли есть всего несколько вариантов (если они еще окажутся доступными), чтобы повлиять на процесс загрузки таким образом. Даже физические машины могут оказаться небольшими встроенными устройствами, которые не имеют простой в использовании консоли, а поиск подходящих кабелей и адаптеров последовательного порта и настройка эмулятора терминала, все для использования консоли на последовательном порту в условиях работы с чрезвычайной ситуацией, зачастую достаточно сложны.
Когда доступна другая система (той же архитектуры и в целом аналогичной конфигурации), общий способ упростить процесс восстановления заключается в извлечении запоминающих устройств из поврежденной системы и подключении их к рабочей системе в качестве вторичных устройств. В физических системах это обычно не вызывает затруднений, и большинство платформ облачных вычислений также могут это поддерживать, поскольку они позволяют смонтировать корневой том хранилища поврежденного инстанса в другом инстансе.
После того, как корневая файловая система подключена к другой системе, решение проблемы повреждения файловой системы осуществляется с помощью fsck и других инструментов. Устранение ошибок конфигурации, поврежденных пакетов или других проблем может быть более сложным, поскольку для них требуется монтировать файловую систему и находить и изменять правильные файлы конфигурации или базы данных.
Использование systemd
До появления systemd способом исправления конфигурации на практике было редактирование файлов конфигурации с помощью текстового редактора. Поиск необходимых файлов и понимание их содержимого является отдельной задачей, которая выходит за рамки данной статьи.
Когда система GNU/Linux использует systemd, многие изменения конфигурации лучше всего выполнять с помощью инструментов, которые она предоставляет — например, для включения и отключения служб требуется создание или удаление символических ссылок в различных местах. Инструмент systemctl используется для внесения этих изменений, но для его использования требуется, чтобы экземпляр systemd работал и прослушивал запросы (по шине D-Bus). Когда корневая файловая система смонтирована как дополнительная файловая система на другом компьютере, работающий экземпляр systemd не может быть использован для внесения этих изменений.
Ручной запуск systemd целевой системы также нецелесообразен, поскольку он спроектирован как PID 1 процесс для управления всеми другими процессами, который может конфликтовать с уже запущенным экземпляром в системе, используемой для исправления.
К счастью, systemd имеет возможность запускать контейнеры — полностью инкапсулированные системы GNU/Linux с собственным PID 1 и средой, в которой используется различный функционал пространства имен, предлагаемый ядром Linux. В отличие от таких инструментов, как Docker и Rocket, systemd не требуется образ контейнера для запуска контейнера; он может запустить его с root-правами в любой точке существующей файловой системы. Это делается с помощью инструмента systemd-nspawn, который создаст необходимые пространства имен системы и запустит начальный процесс в контейнере, а затем предоставит консоль. В отличие от chroot, который изменяет только видимый корень файловой системы, этот тип контейнера будет иметь отдельное пространство имен файловой системы, подходящие файловые системы, смонтированные в /dev, /run и /proc, а также отдельное пространство имен процессов и IPC. Посетите основной ресурс systemd-nspawn, чтобы узнать больше о его возможностях.
Пример для демонстрации того, как это работает
В этом примере запоминающее устройство, содержащее корневую файловую систему поврежденной системы, подключено к работающей системе, где оно отображается как /dev/vdc. Имя устройства будет различаться в зависимости от количества существующих запоминающих устройств, типа устройства и метода, используемого для подключения его к системе. Корневая файловая система может использовать все устройство хранения или находиться в разделе внутри устройства; поскольку наиболее распространенная (простая) конфигурация помещает корневую файловую систему в первый раздел устройства, в этом примере будет использоваться /dev/vdc1. Обязательно замените имя устройства в приведенных ниже командах на правильное имя устройства вашей системы.
Поврежденная корневая файловая система также может быть более сложной, чем отдельная файловая система на устройстве; это может быть том в LVM или на наборе устройств, объединенных в RAID-массив. В этих случаях нужно выполнить необходимые шаги для создания и активации логического устройства, содержащего файловую систему, прежде чем оно будет доступно для монтирования. Опять же, эти шаги выходят за рамки этой статьи.
Необходимые приготовления
Во-первых, убедитесь, что установлен инструмент systemd-nspawn — большинство дистрибутивов GNU/Linux не устанавливают его по умолчанию. Он предоставляется пакетом systemd-container в большинстве дистрибутивов, поэтому используйте менеджер пакетов вашего дистрибутива для его установки. Инструкции в этом примере были протестированы с использованием Debian 9, но должны работать аналогично в любом современном дистрибутиве GNU/Linux.
Для использования приведенных ниже команд почти наверняка потребуются root-права, поэтому вам нужно будет либо войти в систему как root, использовать sudo для получения оболочки с root-правами или добавить к каждой команде префикс sudo.
Проверьте и смонтируйте файловую систему
Сначала используйте fsck для проверки структур и содержимого целевой файловой системы:
$ fsck /dev/vdc1
Если он обнаружит какие-либо проблемы с файловой системой, ответьте на вопросы соответствующим образом, чтобы исправить их. Если файловая система серьезно повреждена, она не подлежит восстановлению, и в этом случае вам придется искать другие способы извлечения ее содержимого.
Теперь создайте временный каталог и смонтируйте в него целевую файловую систему:
$ mkdir /tmp/target-rescue
$ mount /dev/vdc1 /tmp/target-rescue
Когда файловая система смонтирована, запустите контейнер с ней в качестве корневой файловой системы:
$ systemd-nspawn --directory /tmp/target-rescue --boot -- --unit rescue.target
Аргументы командной строки для запуска контейнера:
- --directory /tmp/target-rescue предоставляет путь к корневой файловой системе контейнера.
- --boot ищет подходящую программу инициализации в корневой файловой системе контейнера и запускает ее, передавая ей параметры из командной строки. В этом примере целевая система также использует systemd в качестве PID 1 процесса, поэтому остальные параметры предназначены для него. Если целевая система, которую вы восстанавливаете, использует какой-либо другой инструмент в качестве PID 1 процесса, вам необходимо соответствующим образом настроить параметры.
- — отделяет параметры для systemd-nspawn от тех, которые предназначены для PID 1 процесса контейнера.
- --unit rescue.target сообщает systemd в контейнере имя цели, которую он должен попытаться достичь в процессе загрузки. Чтобы упростить операции восстановления в целевой системе, загрузите ее в режиме «восстановления», а не в обычном многопользовательском режиме.
Если все пойдет хорошо, вы должны увидеть вывод, который выглядит примерно так:
Spawning container target-rescue on /tmp/target-rescue.
Press ^] three times within 1s to kill container.
systemd 232 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
Detected virtualization systemd-nspawn.
Detected architecture arm.
Welcome to Debian GNU/Linux 9 (Stretch)!
Set hostname to .
Failed to install release agent, ignoring: No such file or directory
[ OK ] Reached target Swap.
[ OK ] Listening on Journal Socket (/dev/log).
[ OK ] Started Dispatch Password Requests to Console Directory Watch.
[ OK ] Reached target Encrypted Volumes.
[ OK ] Created slice System Slice.
Mounting POSIX Message Queue File System...
[ OK ] Listening on Journal Socket.
Starting Set the console keyboard layout...
Starting Restore / save the current clock...
Starting Journal Service...
Starting Remount Root and Kernel File Systems...
[ OK ] Mounted POSIX Message Queue File System.
[ OK ] Started Journal Service.
[ OK ] Started Remount Root and Kernel File Systems.
Starting Flush Journal to Persistent Storage...
[ OK ] Started Restore / save the current clock.
[ OK ] Started Flush Journal to Persistent Storage.
[ OK ] Started Set the console keyboard layout.
[ OK ] Reached target Local File Systems (Pre).
[ OK ] Reached target Local File Systems.
Starting Create Volatile Files and Directories...
[ OK ] Started Create Volatile Files and Directories.
[ OK ] Reached target System Time Synchronized.
Starting Update UTMP about System Boot/Shutdown...
[ OK ] Started Update UTMP about System Boot/Shutdown.
[ OK ] Reached target System Initialization.
[ OK ] Started Rescue Shell.
[ OK ] Reached target Rescue Mode.
Starting Update UTMP about System Runlevel Changes...
[ OK ] Started Update UTMP about System Runlevel Changes.
You are in rescue mode. After logging in, type "journalctl -xb" to view
system logs, "systemctl reboot" to reboot, "systemctl default" or ^D to
boot into default mode.
Give root password for maintenance
(or press Control-D to continue):
В этом выводе вы можете увидеть запуск systemd в качестве процесса init в контейнере и определение того, что он выполняется внутри контейнера, чтобы он мог соответствующим образом настроить свое поведение. Для приведения контейнера в рабочее состояние запускаются различные юнит-файлы, затем запрашивается root-пароль целевой системы. Вы можете ввести root-пароль здесь, если вы хотите запросить оболочку с root-правами, или вы можете нажать Ctrl + D, чтобы продолжить процесс запуска, который будет отображать обычное приглашение входа в консоль.
Когда вы выполните необходимые изменения в целевой системе, нажмите Ctrl +] три раза подряд; это завершит работу контейнера и вернет вас в исходную оболочку. Оттуда вы можете выполнить очистку, размонтировав файловую систему целевой системы и удалив временный каталог:
$ umount /tmp/target-rescue
$ rmdir /tmp/target-rescue
Вот и все! Теперь вы можете извлечь запоминающие устройства целевой системы и вернуть их обратно.
Идея использовать systemd-nspawn таким образом, особенно параметр --boot, возникла из вопроса, опубликованного на StackExchange. Спасибо Shibumi и kirbyfan64sos за полезные ответы на этот вопрос!