Удаленная замена корневой ФС в 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
Задачи
- Переместить корневую ФС с раздела /dev/sda2 в LVM в логический том «root» группы «sys» (/dev/mapper/sys-root)
- Увеличить размер корневой ФС с 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.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
Замечания
После переезда на новую корневую ФС сервер может спокойно продолжать работать без перезагрузки.