Как сжать корневую файловую систему без загрузки livecd

94

Я чувствую, что мне нужно переставить системные разделы для перемещения данных, ранее находящихся под корневой файловой системой, в выделенные точки монтирования. Все тома находятся в LVM, так что это относительно просто: создать новые тома, перенести в них данные, сжать корневую файловую систему, а затем смонтировать новые тома в соответствующих точках.

Проблема заключается в шаге 3, уменьшающем корневую файловую систему. Используются файловые системы ext4, поэтому поддерживается онлайн изменение размера; однако при монтировании файловые системы могут только расширяться. Чтобы сжать раздел, требуется размонтировать его, что, конечно, невозможно для корневого раздела при нормальной работе.

Кажется, что ответы в Интернете вращаются вокруг загрузки LiveCD или другого аварийного носителя, выполнения операции сжатия, а затем загрузки обратно в установленную систему. Тем не менее, рассматриваемая система является удаленной, и у меня есть доступ только через SSH. Я могу перезагрузиться, но загрузка аварийного диска и выполнение операций с консоли невозможна.

Как я могу размонтировать корневую файловую систему, поддерживая удаленный доступ к оболочке?

Том Хант
источник
Любая возможность временно смонтировать корневую файловую систему на другом сервере? например, раскрутить другую виртуальную машину и представить ей этот объем диска?
Стив
Сервер физический, поэтому нет.
Том Хант
4
Скопируйте root в tmpfs и pivot_rootтуда. Вот пример: dreamlayers.blogspot.co.uk/2012/10/running-linux-from-ram.html - это сложно, но если у вас есть тестовый бокс, чтобы попробовать его, стоит подумать.
Стив
1
Другой пример, где удаленный доступ через ssh считается ivarch.com/blogs/oss/2007/01/…
Стив
2
Если корневой LVM достаточно мал, вы можете клонировать его в другой LVM и создать загрузочную забегаловку (temp new default) в grub, чтобы использовать его, а затем загрузиться с него (сделав его вашей «живой системой»)
Rabin

Ответы:

171

При решении этой проблемы информация, представленная по адресу http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml, имела ключевое значение. Однако это руководство относится к очень старой версии RHEL, и различная информация устарела.

Приведенные ниже инструкции предназначены для работы с CentOS 7, но их должно быть достаточно легко перенести в любой дистрибутив, на котором работает systemd. Все команды запускаются от имени пользователя root.

  1. Убедитесь, что система находится в стабильном состоянии

    Убедитесь, что никто не использует его, и ничего более важного не происходит. Вероятно, будет хорошей идеей прекратить предоставление сервисов, таких как httpd или ftpd, просто для того, чтобы внешние соединения не нарушали работу посередине.

    systemctl stop httpd
    systemctl stop nfs-server
    # and so on....
    
  2. Размонтировать все неиспользуемые файловые системы

    umount -a
    

    Это напечатает несколько предупреждений «Target is busy» для самого корневого тома и для различных временных / системных FS. Это может быть проигнорировано на данный момент. Важно то, что файловые системы на диске не остаются подключенными, кроме самой корневой файловой системы. Проверьте это:

    # mount alone provides the info, but column makes it possible to read
    mount | column -t
    

    Если вы видите, что файловые системы на диске все еще смонтированы, значит, что-то еще работает, чего не должно быть. Проверьте, что он использует fuser:

    # if necessary:
    yum install psmisc
    # then:
    fuser -vm <mountpoint>
    systemctl stop <whatever>
    umount -a
    # repeat as required...
    
  3. Сделать временный корень

    mkdir /tmp/tmproot
    mount -t tmpfs none /tmp/tmproot
    mkdir /tmp/tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot}
    cp -ax /{bin,etc,mnt,sbin,lib,lib64} /tmp/tmproot/
    cp -ax /usr/{bin,sbin,lib,lib64} /tmp/tmproot/usr/
    cp -ax /var/{account,empty,lib,local,lock,nis,opt,preserve,run,spool,tmp,yp} /tmp/tmproot/var/
    

    Это создает очень минимальную корневую систему, которая нарушает (среди прочего) просмотр man-страниц (нет /usr/share), пользовательские настройки (нет /rootили /home) и так далее. Это сделано намеренно, так как это поощрение не оставаться в такой фальсифицированной корневой системе больше, чем необходимо.

    На этом этапе вы также должны убедиться, что установлено все необходимое программное обеспечение, так как оно также обязательно нарушит работу менеджера пакетов. Просмотрите все шаги и убедитесь, что у вас есть необходимые исполняемые файлы.

  4. Поворот в корень

    mount --make-rprivate / # necessary for pivot_root to work
    pivot_root /tmp/tmproot /tmp/tmproot/oldroot
    for i in dev proc sys run; do mount --move /oldroot/$i /$i; done
    

    systemd заставляет монтирование разрешать совместное использование поддерева по умолчанию (как с mount --make-shared), и это приводит pivot_rootк сбою. Следовательно, мы отключаем это глобально с mount --make-rprivate /. Системные и временные файловые системы перемещаются оптом в новый корень. Это необходимо, чтобы заставить его работать вообще; сокеты для связи с systemd, между прочим, живут /run, и поэтому нет способа заставить запущенные процессы закрыть его.

  5. Убедитесь, что удаленный доступ пережил переход

    systemctl restart sshd
    systemctl status sshd
    

    После перезапуска sshd убедитесь, что вы можете войти, открыв другой терминал и снова подключившись к машине через ssh. Если вы не можете исправить проблему, прежде чем двигаться дальше.

    После того, как вы подтвердите, что вы можете подключиться снова, выйдите из оболочки, которую вы используете в данный момент, и снова подключитесь. Это позволяет оставшимся разветвленным sshdвыходам и гарантирует, что новый не держит /oldroot.

  6. Закройте все еще используя старый рут

    fuser -vm /oldroot
    

    Это напечатает список процессов, все еще удерживающих старый корневой каталог. В моей системе это выглядело так:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
                 root          1 ...e. systemd
                 root        549 ...e. systemd-journal
                 root        563 ...e. lvmetad
                 root        581 f..e. systemd-udevd
                 root        700 F..e. auditd
                 root        723 ...e. NetworkManager
                 root        727 ...e. irqbalance
                 root        730 F..e. tuned
                 root        736 ...e. smartd
                 root        737 F..e. rsyslogd
                 root        741 ...e. abrtd
                 chrony      742 ...e. chronyd
                 root        743 ...e. abrt-watch-log
                 libstoragemgmt    745 ...e. lsmd
                 root        746 ...e. systemd-logind
                 dbus        747 ...e. dbus-daemon
                 root        753 ..ce. atd
                 root        754 ...e. crond
                 root        770 ...e. agetty
                 polkitd     782 ...e. polkitd
                 root       1682 F.ce. master
                 postfix    1714 ..ce. qmgr
                 postfix   12658 ..ce. pickup
    

    Вам нужно разобраться с каждым из этих процессов, прежде чем вы сможете размонтировать /oldroot. Подход грубой силы просто kill $PIDдля каждого, но это может сломать вещи. Чтобы сделать это более мягко:

    systemctl | grep running
    

    Это создает список запущенных сервисов. Вы должны быть в состоянии сопоставить это со списком процессов /oldroot, выполняемых , а затем выполнить systemctl restartдля каждого из них. Некоторые службы отказываются входить во временный корень и переходить в состояние отказа; это на самом деле не имеет значения на данный момент.

    Если корневой диск, размер которого вы хотите изменить, является диском LVM, вам также может потребоваться перезапустить некоторые другие работающие службы, даже если они не отображаются в списке, созданном fuser -vm /oldroot. Если вы обнаружите, что не можете изменить размер диска LVM при выполнении шага 7, попробуйте systemctl restart systemd-udevd.

    Некоторые процессы не могут быть решены с помощью простых systemctl restart. Для меня они включены auditd(который не любит быть убитым через systemctl, и поэтому просто хотел kill -15). С ними можно разобраться индивидуально.

    Последний процесс, который вы найдете, как правило, systemdсам по себе. Для этого беги systemctl daemon-reexec.

    Как только вы закончите, таблица должна выглядеть так:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
    
  7. Размонтировать старый рут

    umount /oldroot
    

    На этом этапе вы можете выполнять любые необходимые вам манипуляции. Первоначальный вопрос требовал простого resize2fsвызова, но вы можете сделать все, что захотите; Еще один вариант использования - перенос корневой файловой системы из простого раздела в LVM / RAID / любой другой.

  8. Поверните корень назад

    mount <blockdev> /oldroot
    mount --make-rprivate / # again
    pivot_root /oldroot /oldroot/tmp/tmproot
    for i in dev proc sys run; do mount --move /tmp/tmproot/$i /$i; done
    

    Это прямое изменение шага 4.

  9. Утилизировать временный корень

    Повторите шаги 5 и 6, за исключением использования /tmp/tmprootвместо /oldroot. Затем:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Поскольку это tmpfs, в этот момент временный корень растворяется в эфире, и его больше никогда не увидеть.

  10. Положите вещи на свои места

    Снова смонтируйте файловые системы:

    mount -a
    

    На этом этапе вы также должны обновить /etc/fstabи grub.cfgв соответствии с любыми изменениями, которые вы сделали на шаге 7.

    Перезапустите все неисправные службы:

    systemctl | grep failed
    systemctl restart <whatever>
    

    Разрешить общие поддеревья снова:

    mount --make-rshared /
    

    Запустите остановленные сервисные единицы - вы можете использовать эту единственную команду:

    systemctl isolate default.target
    

И вы сделали.

Большое спасибо Эндрю Вуду, который разработал эту эволюцию на RHEL4, и Стиву, который предоставил мне ссылку на первое.

Том Хант
источник
11
Потрясающий ответ. Почти волшебный, очень ясный и понятный. Использовал его с Debian VPS без каких-либо проблем (просто пришлось, umount /oldroot/bootконечно, на этапе 6). Я связываю ваш ответ с другими вопросами SE, на которые не было ответа или отрицательного ответа.
Вааб
3
И проблема была решена, как указано @vaab; Вы должны быть umount /oldroot/bootперед вамиumount /oldroot
ToBeReplaced
3
Суть в том, чтобы размонтировать и управлять корневой файловой системой без необходимости использования физической консоли. Насколько я знаю, нет способа держать открытым сервис, который читает из раздела при размонтировании этого раздела. Если ваша служба не затрагивает корневую FS, возможно, вы можете оставить ее открытой, используя mount --movetmpfs, но это не поддерживается.
Том Хант
2
Вам необходимо использовать возможности ОС для перезапуска демона init. Я никогда не использовал выскочки, но wiki.ubuntu.com/FoundationsTeam/Specs/… предполагает, что telinit uможет делать то, что вы хотите.
Том Хант
3
Дополнительная морщина, с которой я столкнулся: / tmp - это ram-диск в моей системе, поэтому в итоге я установил ram-диск, на /oldroot/tmpкотором я /oldrootне мог размонтироваться , но не показывался fuserи не lsofвыводился.
Крис Китчинг
7

Если вы уверены, что делаете, то есть не экспериментируете, вы можете подключиться к initrd, который является неинтерактивным и быстрым способом.

В системе на основе Debian вот как.

Смотрите код: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-resizefs.sh

Есть еще один пример: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-convert-ext3-ext4.sh

Сепе Виктор
источник
Когда вы даете ответ, предпочтительно дать какое-то объяснение, ПОЧЕМУ ваш ответ тот.
Стивен Раух
1
Это разумный подход. Мне нравится, что я позволяю мне делать необходимые манипуляции в интерактивном режиме; однако, этот, вероятно, быстрее. Возможно, было бы неплохо отредактировать некоторые подробности в самом ответе или рассмотреть другие платформы (кажется, что этот общий подход все еще будет работать с dracut или mkinitcpio или любым другим неопределенно современным генератором initramfs).
Том Хант
Извините, @ stephen-rauch, я просто указал на идею, а не на казнь.
Сепе Виктор