Удаленная замена корневой ФС в GNU/linux

Иногда мне приходится сталкиваться с заменой корневой файловой системы. Имея загрузочный диск и доступ к серверу, это не сложно. Однако, я хочу поделиться опытом замены корневой ФС удаленно, через ssh, без перезагрузки.

Причины для замены коневой ФС бывают разные:

  • перевод / в LVM
  • перевод / в mdraid
  • замена типа файловой системы (ext3 => btrfs)
  • уменьшение размера ФС (resize2fs)


В качестве примера, я буду перемещать корневую ФС из /dev/sda2 в LVM
Описание буду проводить на примере gentoo GNU/linux.
Данный способ был проверен мной также и на debian GNU/linux.

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

Дано

Есть удаленный сервер, размещенный в датацентре.
В моем случае, это будет хост система, с запущенными виртуальными машинами KVM.

Жесткий диск /dev/sda, где находится корневая ФС, разбит на три msdos раздела:

  • sda1 200Мб /boot
  • sda2 2Гб /
  • sda3 197Гб LVM

 

Задачи

 

  1. Переместить корневую ФС с раздела /dev/sda2 в LVM в логический том «root» группы «sys» (/dev/mapper/sys-root)
  2. Увеличить размер корневой ФС с 2 Гб до 3Гб

 

Прежде чем начать

— Мне понадобится утилита lsof. Необходимо установить ее до начала работ.
— Нужно понимать, что в процессе решения задачи нам потребуется перезапустить все процессы на сервере.
— Важно! Я пишу эту статью для тех, кто уже знаком с LVM и понимает, что при загрузке ядро не сможет самостоятельно замонтировать / без помощи initramfs!

Решение

Решение буду описывать по шагам.
План такой:
1. Создаем новый логический том в LVM
2. Создаем папки для монтирования
3. Готовимся к перемонтированию старой корневой ФС / в режиме readonly
4. Перемонтируем корневую ФС / в режим readonly
5. Резервное копирование (опционально)
6. Копируем корневую ФС с устройства sda2 в LVM том root
7. Изменяем размер ФС
8. Монтируем копию
9. Подменяем корневую ФС
10. Возвращаем точки монтирования всех остальных ФС
11. Перезапускаем приложения с новой корневой ФС
12. Операции после подмены корневой ФС

1. Создаем новый логический том в LVM
Том будет размером 3Гб и называться root
lvcreate -L 3g -n root sys

  Logical volume "root" created

2. Создаем папки для монтирования
mkdir /mnt/oldroot /mnt/newroot

3. Готовимся к перемонтированию старой корневой ФС / в режиме readonly
Это нужно для того, чтобы скопировать старую корневую ФС в новое место в консистентном состоянии.
Но сама ФС, скорее всего, сейчас используется процессами для записи данных.

3.1. Проверяем удаленные файлы
lsof / | grep ‘ DEL \|delete’

dmeventd   3397   root  txt    REG  8,2    31816  71851 /sbin/dmeventd (deleted)
dmeventd   3397   root  DEL    REG  8,2           87761 /lib64/libdevmapper.so.1.02|paludis-midmerge
dmeventd   3397   root  DEL    REG  8,2           87769 /lib64/libdevmapper-event.so.1.02|paludis-midmerge
sshd       5601   root  txt    REG  8,2   482592  14452 /usr/sbin/sshd (deleted)

Если такие файлы нашлись, то процессы нужно перезапустить или остановить.
У меня такие файлы есть. Они возникли из-за того, что недавно были обновлены пакеты net-misc/openssh и sys-fs/lvm2

3.2. Перезапускаем и/или останавливаем процессы с удаленными файлами
В моем случае я перезапускаю sshd и завершаю dmeventd
/etc/init.d/sshd restart

 * Stopping sshd ...  [ ok ]
 * Starting sshd ...  [ ok ]

/etc/init.d/dmeventd stop

 * WARNING: you are stopping a boot service
 * Stopping dmeventd ...  [ ok ]

3.3. Убеждаемся, что нет больше удаленных файлов
lsof / | grep ‘ DEL \|delete’
Убедились.

3.4. Проверяем открытые на запись файлы

lsof / | grep -v ‘ \(mem\|txt\|rtd\|cwd\) ‘

COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
cron      29035   root    3u   REG   8,2        6 11427 /var/run/cron.pid
snmpd     29530   root    3w   REG   8,2  1035580 84179 /var/log/net-snmpd.log
snmpd     29530   root    8r   REG   8,2     1316 28549 /etc/mtab
rsyslogd  29678   root    1w   REG   8,2   642199 11587 /var/log/messages
rsyslogd  29678   root    2w   REG   8,2    62061 12377 /var/log/cron
rsyslogd  29678   root    4w   REG   8,2     2155 12375 /var/log/secure
rsyslogd  29678   root    5w   REG   8,2      259 12376 /var/log/maillog

Смотрим на файлы, у которых режим открытия (колонка FD) содержит одну из букв: uUwW
В моем случае я не вижу проблем остановить все эти сервисы на время перемещения.
В вашем случае, решайте сами.

3.5. Останавливаем процессы, которые держат открытые файлы
/etc/init.d/rsyslog stop

 * Stopping rsyslogd ... [ ok ]

/etc/init.d/snmpd stop

 * Stopping snmpd ...  [ ok ]

/etc/init.d/vixie-cron stop

 * Stopping vixie-cron ... [ ok ]

3.6. Убеждаемся, что нет больше открытых на запись файлов
lsof / | grep -v ‘ \(mem\|txt\|rtd\|cwd\) ‘

COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME

3.7. Размонтируем все loop устройства
В моем случае я размонтирую squashfs файловую систему в /usr/portage
umount /usr/portage

3.8. Размонтируем ФС типа nfs, cifs, fuse и aufs
В моем случае таких нет.

3.9. Смотрим файловые (unix) сокеты
netstat –unix -a |grep ‘/\|Path$’

Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     3682265  /var/run/kvm/kvm204.sock
unix  2      [ ACC ]     STREAM     LISTENING     3279538  /var/run/kvm/kvm209.sock
unix  2      [ ACC ]     STREAM     LISTENING     3389038  /var/run/kvm/kvm207.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3603323  /var/run/kvm/kvm208.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3279539  /var/run/kvm/kvm209.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3607000  /var/run/kvm/kvm210.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3612458  /var/run/kvm/kvm211.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3682266  /var/run/kvm/kvm204.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3612457  /var/run/kvm/kvm211.sock
unix  2      [ ACC ]     STREAM     LISTENING     3279518  /var/run/kvm/kvm205.sock
unix  2      [ ACC ]     STREAM     LISTENING     3603322  /var/run/kvm/kvm208.sock
unix  2      [ ACC ]     SEQPACKET  LISTENING     3605138  @/org/kernel/udev/udevd
unix  2      [ ACC ]     STREAM     LISTENING     3608717  /var/run/kvm/kvm206.sock
unix  2      [ ACC ]     STREAM     LISTENING     3280746  /var/run/kvm/kvm205.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3608718  /var/run/kvm/kvm206.monitor.sock
unix  2      [ ACC ]     STREAM     LISTENING     3606999  /var/run/kvm/kvm210.sock
unix  2      [ ACC ]     STREAM     LISTENING     3389037  /var/run/kvm/kvm207.sock

При переносе корневой ФС эти сокеты перестанут быть связанными со своими приложениями.
Это решается:
— предварительной остановкой этих приложений (рекомендуется)
— перезапуском этих приложений после подмены корневой ФС
Меня не пугает потеря связи с приложениями через эти сокеты.

4. Перемонтируем корневую ФС / в режим readonly
mount -n -o remount,ro /
Если все успешно, то команда завершится тихо.
Если же появится строка «mount: / is busy», то корневая ФС все еще занята. Возвращайтесь к пункту 3 и проверяйте. Возможно вы что-то забыли.

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

Если же у вас все прошло успешно, то движемся дальше.

5. Резервное копирование (опционально)
Сейчас для этого самое время.
Для себя я не вижу в этом необходимости, т.к. после всей операции в качестве резервной копии останется старый раздел sda2.
Кроме того, у меня настроено ежедневное резервное копирование всех разделов хост системы и всех виртуальных машин.

6. Копируем корневую ФС с устройства sda2 в LVM том root
dd if=/dev/sda2 of=/dev/sys/root bs=8M

239+1 records in
239+1 records out
2006843392 bytes (2.0 GB) copied, 58.1021 s, 34.5 MB/s

7. Изменяем размер ФС

7.1. Первоначально проверяем ФС на ошибки
fsck -fC /dev/sys/root
fsck from util-linux 2.20.1

e2fsck 1.42 (29-Nov-2011)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/sys-root: 46848/122640 files (2.0% non-contiguous), 216129/489952 blocks

7.2. Производим изменение размера ФС
В нашем случае, мы увеличиваем ФС до размеров LVM тома.
resize2fs -p /dev/sys/root

resize2fs 1.42 (29-Nov-2011)
Resizing the filesystem on /dev/sys/root to 786432 (4k) blocks.
Begin pass 1 (max = 9)
Extending the inode table     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/sys/root is now 786432 blocks long.

8. Монтируем копию
mount -n /dev/sys/root /mnt/newroot

9. Подменяем корневую ФС
Это то, ради чего я все это затеял.
С этого момента наступает опасное время.
Важно: После подмены корневой ФС, если произойдет обрыв SSH сессии, то система не сможет установить новое соединение!
Подменяем ФС:
cd /mnt/newroot

pivot_root . mnt/oldroot

Важно выполнить именно эти две команды в том виде, в котором они написаны, чтобы избежать блокировок из-за текущей рабочей папки (cwd).
После этой команды, том /dev/sys/root встанет на место /, а раздел sda2 сменит точку монтирования в /mnt/oldroot. При этом все другие замонтированные ФС тоже сменят точку монтирования. Например, файловая система /dev переместится в /mnt/oldroot/dev.

10. Возврщаем точки монтирования всех остальных ФС (кроме старой корневой ФС)
Переносим стандартные ФС, которые есть у большинства:
mount -n –move /mnt/oldroot/proc /proc
mount -n –move /mnt/oldroot/dev /dev
mount -n –move /mnt/oldroot/sys /sys

Теперь можно смотреть в /proc/mounts, что еще нужно вернуть на место
cat /proc/mounts |grep oldroot

rc-svcdir /mnt/oldroot/lib64/rc/init.d tmpfs rw,nosuid,nodev,noexec,relatime,size=1024k,mode=755 0 0
/dev/root /mnt/oldroot ext3 ro,noatime,errors=continue,barrier=1,data=writeback 0 0
/dev/mapper/sys-distfiles /mnt/oldroot/var/distfiles ext2 rw,noatime,errors=continue 0 0
/dev/mapper/sys-vardb /mnt/oldroot/var/db reiserfs rw,noatime 0 0

В моем примере, я переношу
mount -n –move /mnt/oldroot/lib64/rc/init.d /lib64/rc/init.d
mount -n –move /mnt/oldroot/var/distfiles /var/distfiles
mount -n –move /mnt/oldroot/var/db /var/db

С этого момента вы вне опасности. Новые SSH сессии должны успешно открываться.

11. Перезапускаем приложения с новой корневой ФС

11.1. Смотрим, файлы процессов
lsof /mnt/oldroot

...
agetty    28783   root mem    REG   8,2    52884 99214 /mnt/oldroot/lib64/libnss_nis-2.13.so
agetty    28783   root mem    REG   8,2   109446 98354 /mnt/oldroot/lib64/libnsl-2.13.so
agetty    28783   root mem    REG   8,2    38724 99216 /mnt/oldroot/lib64/libnss_compat-2.13.so
agetty    28783   root mem    REG   8,2  1898114 99218 /mnt/oldroot/lib64/libc-2.13.so
agetty    28783   root mem    REG   8,2   156052 99219 /mnt/oldroot/lib64/ld-2.13.so
udevd     29118   root txt    REG   8,2   130216 49072 /mnt/oldroot/sbin/udevd
udevd     29118   root mem    REG   8,2    62227 99210 /mnt/oldroot/lib64/libnss_files-2.13.so
udevd     29118   root mem    REG   8,2    52884 99214 /mnt/oldroot/lib64/libnss_nis-2.13.so
udevd     29118   root mem    REG   8,2   109446 98354 /mnt/oldroot/lib64/libnsl-2.13.so
udevd     29118   root mem    REG   8,2    38724 99216 /mnt/oldroot/lib64/libnss_compat-2.13.so
udevd     29118   root mem    REG   8,2   135986 99220 /mnt/oldroot/lib64/libpthread-2.13.so
udevd     29118   root mem    REG   8,2  1898114 99218 /mnt/oldroot/lib64/libc-2.13.so
udevd     29118   root mem    REG   8,2    48545 99211 /mnt/oldroot/lib64/librt-2.13.so
udevd     29118   root mem    REG   8,2   156052 99219 /mnt/oldroot/lib64/ld-2.13.so
sshd      29455   root txt    REG   8,2   482592 74222 /mnt/oldroot/usr/sbin/sshd
sshd      29455   root mem    REG   8,2    62227 99210 /mnt/oldroot/lib64/libnss_files-2.13.so
sshd      29455   root mem    REG   8,2    52884 99214 /mnt/oldroot/lib64/libnss_nis-2.13.so
sshd      29455   root mem    REG   8,2    38724 99216 /mnt/oldroot/lib64/libnss_compat-2.13.so
sshd      29455   root mem    REG   8,2   440512 75579 /mnt/oldroot/usr/lib64/libgmp.so.10.0.2
sshd      29455   root mem    REG   8,2  1898114 99218 /mnt/oldroot/lib64/libc-2.13.so
sshd      29455   root mem    REG   8,2   135986 99220 /mnt/oldroot/lib64/libpthread-2.13.so
sshd      29455   root mem    REG   8,2    98598 99206 /mnt/oldroot/lib64/libresolv-2.13.so
sshd      29455   root mem    REG   8,2    40981 99205 /mnt/oldroot/lib64/libcrypt-2.13.so
sshd      29455   root mem    REG   8,2   109446 98354 /mnt/oldroot/lib64/libnsl-2.13.so
sshd      29455   root mem    REG   8,2    92624 98190 /mnt/oldroot/lib64/libz.so.1.2.5
sshd      29455   root mem    REG   8,2    14367 99217 /mnt/oldroot/lib64/libutil-2.13.so
sshd      29455   root mem    REG   8,2    19321 99203 /mnt/oldroot/lib64/libdl-2.13.so
sshd      29455   root mem    REG   8,2  1699456 74274 /mnt/oldroot/usr/lib64/libcrypto.so.1.0.0
sshd      29455   root mem    REG   8,2   373376 76226 /mnt/oldroot/usr/lib64/libssl.so.1.0.0
sshd      29455   root mem    REG   8,2    51760 98532 /mnt/oldroot/lib64/libpam.so.0.83.1
sshd      29455   root mem    REG   8,2   156052 99219 /mnt/oldroot/lib64/ld-2.13.so
smartd    29484   root txt    REG   8,2   374520 75866 /mnt/oldroot/usr/sbin/smartd
smartd    29484   root mem    REG   8,2  1898114 99218 /mnt/oldroot/lib64/libc-2.13.so
smartd    29484   root mem    REG   8,2   533499 82722 /mnt/oldroot/usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/libgcc_s.so.1
smartd    29484   root mem    REG   8,2   614022 99202 /mnt/oldroot/lib64/libm-2.13.so
...

Видим, что все процессы запущены со старой корневой ФС.

11.2. Начинаем перезапускать системные процессы
Я рекомендую в первую очередь:
/etc/init.d/udev restart
/etc/init.d/sshd restart

11.3. Открываем вторую ssh сессию на сервер
Если вход успешен, то первую сессию нужно завершить, для того чтобы закрыть старую оболочку bash и форк старой sshd.
смотрим lsof /mnt/oldroot
все sshd процессы, запущенные со старой корневой ФС должны исчезнуть.

11.4. Необычные процессы.
Перезапускаем agetty и init

С agetty (или другими *tty) все просто:
killall agetty
Не стоит бояться, init их перезапустит

Cам init перезапускаем командой
telinit u

11.5. Монтируем файловые системы, отключенные ранее
Я монтирую squashfs в /usr/portage
mount /usr/portage

11.6. Запускаем остановленные ранее сервисы
В моем случае я запускаю:
/etc/init.d/rsyslog start

 * Starting rsyslog ...  [ ok ]

/etc/init.d/snmpd start

 * Starting snmpd ...  [ ok ]

/etc/init.d/vixie-cron start

 * Starting vixie-cron ...  [ ok ]

11.7. Продолжаем перезапускать сервисы

смотрим lsof /mnt/oldroot, и перезапускаем, что осталось

/etc/init.d/ntpd restart
/etc/init.d/radvd restart
/etc/init.d/smartd restart
/etc/init.d/dnsmasq restart

В том числе, я перезапускаю виртуальные машины, которые все это время спокойно работали.
Более того, теперь уже нет особой надобности торопиться.
Мы перезапускаем сервисы, только чтобы размонтировать старую корневую ФС.
/etc/init.d/kvm.204 restart
/etc/init.d/kvm.205 restart
/etc/init.d/kvm.206 restart

12. Операции после подмены корневой ФС

12.1. Не забываем изменить fstab
Я пользуюсь метками LABEL=, поэтому ничего не меняю

LABEL=root              /                       ext3  noatime           0 1

12.2. Размонтируем старую корневую ФС
umount /mnt/oldroot
rmdir /mnt/oldroot /mnt/newroot
Она больше никем не используется
Для тех, кто хочет сохранить старую корневую ФС, я рекомендую поменять у нее LABEL и UUID, чтобы она не путала загрузчик.
tune2fs -L oldroot -U $(uuidgen) /dev/sda2
Для себя, я больше не вижу необходимости в старой ФС. Удаляю.
wipefs /dev/sda2 -o 0x438

12.3. Не забываем добавить/изменить initramfs, при переходе на LVM

12.4. Не забываем переконфигурировать загрузчик
В моем случае это grub2
Устанавливаем загрузчик на sda
grub2-install –no-floppy /dev/sda

Installation finished. No error reported.

Обновляем конфигурацию:
grub2-mkconfig -o /boot/grub2/grub.cfg

Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.2.12-gentoo-64-beaver-b
Found initrd image: /boot/initrd-3.2.12-gentoo-64-beaver-b
done

 

Замечания

После переезда на новую корневую ФС сервер может спокойно продолжать работать без перезагрузки.

Залишити відповідь