Перенос корневой системы с SW RAID1 на LVM

На сервере кончается свободное место на дисках, а купить новый в этом месяце в бюджет не заложено? Ищем не самые полезные с точки зрения отказоустойчивости методы решения вопроса и вспоминаем, что все сервера у нас собраны на программных зеркалах mdadm raid1. Пришло время избавиться от дублирования данных в угоду увеличению объема тех самых данных. Это увеличит риски потерять все в случае выхода из строя любого из дисков, но иногда можно этим пренебречь (как говорил классик, все люди делятся на три категории: 1) те кто еще не делают бэкапы, 2) те кто уже делает, 3) кто проверяет что он там набэкапил).

Итак, суть: возьмем RAID1 из двух дисков, выбросим из него один диск, накатим туда пустой LVM, переложим данные, загрузимся с этого диска, грохнем raid и расширим LVM за счет освободившегося второго диска.

Идея не претендует на новаторство, однако пошагового how-to при беглом гуглении найти не удалось. Были найдены варианты с переделкой в RAID5 в статусе degraded без одного диска, что явно не является решением нашей проблемы. А также вполне логичный вопрос (на мой взгляд) как переделать зеркало в страйп (raid1 в raid0) от Пумы несколько лет назад. Так вот, Ромка, нельзя. Из-за структуры хранения данных в страйпе, которая напоминает сцепленные в замок руки. Данные поочередно кладутся на оба диска.

Перед началом всех операций имеем следующую картину: 2 диска по 3 раздела в каждом (swap, /boot и /) объединены в md-зеркала:

# fdisk -l
Disk /dev/sda: 477 GiB, 512110190592 bytes, 1000215216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x865165a5

Device     Boot    Start        End   Sectors   Size Id Type
/dev/sda1           2048   33556479  33554432    16G fd Linux raid autodetect
/dev/sda2       33556480   34605055   1048576   512M fd Linux raid autodetect
/dev/sda3       34605056 1000213167 965608112 460.4G fd Linux raid autodetect


Disk /dev/sdb: 477 GiB, 512110190592 bytes, 1000215216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x96457804

Device     Boot    Start        End   Sectors   Size Id Type
/dev/sdb1           2048   33556479  33554432    16G fd Linux raid autodetect
/dev/sdb2       33556480   34605055   1048576   512M fd Linux raid autodetect
/dev/sdb3       34605056 1000213167 965608112 460.4G fd Linux raid autodetect


Disk /dev/md1: 511.4 MiB, 536281088 bytes, 1047424 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/md0: 16 GiB, 17163091968 bytes, 33521664 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/md2: 460.3 GiB, 494257111040 bytes, 965345920 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes



# cat /proc/mdstat 
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10] 
md2 : active raid1 sdb3[1] sda3[0]
      482672960 blocks super 1.2 [2/2] [UU]
      bitmap: 1/4 pages [4KB], 65536KB chunk

md0 : active raid1 sda1[0] sdb1[1]
      16760832 blocks super 1.2 [2/2] [UU]
      
md1 : active raid1 sdb2[1] sda2[0]
      523712 blocks super 1.2 [2/2] [UU]
      
unused devices: 

Выбрасываем первый диск

# mdadm --fail /dev/md2 /dev/sda3
mdadm: set /dev/sda3 faulty in /dev/md2
# mdadm -fr /dev/md2 /dev/sda3
mdadm: hot removed /dev/sda3 from /dev/md2
# mdadm --fail /dev/md1 /dev/sda2
mdadm: set /dev/sda2 faulty in /dev/md1
# mdadm -fr /dev/md1 /dev/sda2
mdadm: hot removed /dev/sda2 from /dev/md1
# mdadm --fail /dev/md0 /dev/sda1
mdadm: set /dev/sda1 faulty in /dev/md0
# mdadm -fr /dev/md0 /dev/sda1
mdadm: hot removed /dev/sda1 from /dev/md0


# cat /proc/mdstat 
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10] 
md2 : active raid1 sdb3[1]
      482672960 blocks super 1.2 [2/1] [_U]
      bitmap: 2/4 pages [8KB], 65536KB chunk

md0 : active raid1 sdb1[1]
      16760832 blocks super 1.2 [2/1] [_U]
      
md1 : active raid1 sdb2[1]
      523712 blocks super 1.2 [2/1] [_U]
      
unused devices: 

Стираем с этого диска информацию о принадлежности к RAID-массиву, чтобы он в будущем не решил вернуться в эти ряды.

# mdadm --zero-superblock /dev/sda1
# mdadm --zero-superblock /dev/sda2
# mdadm --zero-superblock /dev/sda3

Поменяем информацию по типу разделов на этом диске

# fdisk /dev/sda
Command (m for help): t
Partition number (1-3, default 3): 3
Partition type (type L to list all types): 82

Changed type of partition 'Linux raid autodetect' to 'Linux swap / Solaris'.

Command (m for help): t
Partition number (1-3, default 3): 2
Partition type (type L to list all types): 83

Changed type of partition 'Linux raid autodetect' to 'Linux'.

Command (m for help): t   
Partition number (1-3, default 3): 
Partition type (type L to list all types): 83

Changed type of partition 'Linux raid autodetect' to 'Linux'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Device or resource busy

The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).

Если выдало в конце ошибку как у меня — делаем (после установки kpartx при отсутствии):

# kpartx -f -v /dev/sda
sda1 : 0 33554432 /dev/sda 2048
sda2 : 0 1048576 /dev/sda 33556480
sda3 : 0 965608112 /dev/sda 34605056

Раздел /boot класть на LVM не будем (с LVM уверенно грузится GRUB2+, а в случае отсутствия KVM-доступа к серверу вернуть в работоспособное состояние его будет весьма проблематично). Поэтому создаем в маленьком разделе файловую систему и перекладываем туда данные с еще живого куска зеркала

# mkfs.ext3 /dev/sda2
mke2fs 1.42.13 (17-May-2015)
Discarding device blocks: done                            
Creating filesystem with 131072 4k blocks and 32768 inodes
Filesystem UUID: f4215b7b-1793-49f0-96ed-f3fb8fc50786
Superblock backups stored on blocks: 
	32768, 98304

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

# mount /dev/sda2 /mnt/
           
# rsync -av /boot/ /mnt/

Делаем раздел подкачки активным:

# mkswap /dev/sda1
Setting up swapspace version 1, size = 16 GiB (17179865088 bytes)
no label, UUID=0b90f5ac-810e-40e2-a026-18823dedbd50
# swapon /dev/sda1

Выключаем прежний раздел

# swapoff /dev/md0

На оставшемся разделе под систему и данные создаем lvm том, группу и непосредственно логическое устройство необходимых размеров (я задействую всё пространство, кому требуются другие варианты — есть неплохие мануалы тут и там, переносить их сюда слово в слово не вижу надобности)

# pvcreate /dev/sda3
  Physical volume "/dev/sda3" successfully created
# vgcreate vg0 /dev/sda3
  Volume group "vg0" successfully created
# lvcreate -n bigroot vg0
  Please specify either size or extents.
  Run `lvcreate --help' for more information.
# lvcreate -n bigroot -l100%FREE vg0
  Logical volume "bigroot" created.
# mkfs.ext4 /dev/vg0/bigroot 
mke2fs 1.42.13 (17-May-2015)
Discarding device blocks: done                            
Creating filesystem with 120699904 4k blocks and 30179328 inodes
Filesystem UUID: 38c8869a-516b-4149-8db8-ce74831f8a6f
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
	4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
	102400000

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done  

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

Теперь самое рутинное — переносим своим любимым способом ПОЧТИ всю информацию со старого диска на новый раздел (то, что не требуется — пропускаем)

# mount /dev/vg0/bigroot /mnt/
# rsync -av / /mnt/ --exclude sys --exclude proc --exclude dev --exclude tmp --exclude media --exclude mnt --exclude run --exclude boot
# cd /mnt && mkdir sys proc dev tmp media mnt run boot

Заходим в окружение новой системы и правим конфиги для успешной загрузки в дальнейшем

# mount -t proc none /mnt/proc/
# mount -t sysfs sysfs /mnt/sys
# mount -o bind /dev/ /mnt/dev
# mount -o bind /run /mnt/run

# mount /dev/sda2 /mnt/boot

# chroot /mnt/

# mcedit /etc/fstab 
proc /proc proc defaults 0 0
/dev/sda1 none swap sw 0 0
/dev/sda2 /boot ext3 defaults 0 0
/dev/vg0/bigroot / ext4 defaults 0 0

# update-grub
# grub-install /dev/sda
# exit
# umount /mnt/proc /mnt/sys /mnt/dev /mnt/run /mnt/boot
# umount /mnt

Ну и, скрестив пальцы, пробуем загрузиться с этого диска

# reboot

В случае успешной загрузки проверяем с помощью df, что мы добились желаемого (у / будет не /dev/md0 а наш /dev/vg0/bigroot), останавливаем RAID и форматируем диск.

# mdadm --zero-superblock /dev/sdb1
# mdadm --zero-superblock /dev/sdb2
# mdadm --zero-superblock /dev/sdb3
# fdisk /dev/sdb

Command (m for help): d
Partition number (1-3, default 3): 

Partition 3 has been deleted.

Command (m for help): d
Partition number (1,2, default 2): 

Partition 2 has been deleted.

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): p
Disk /dev/sdb: 477 GiB, 512110190592 bytes, 1000215216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x96457804

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Теперь добавляем диск к нашим lvm-партициям и увеличиваем место

# vgextend vg0 /dev/sdb
WARNING: dos signature detected on /dev/sdb at offset 510. Wipe it? [y/n]: y
  Wiping dos signature on /dev/sdb.
  Physical volume "/dev/sdb" successfully created
  Volume group "vg0" successfully extended


# lvextend -l +100%FREE /dev/vg0/bigroot
  Size of logical volume vg0/bigroot changed from 460.43 GiB (117871 extents) to 937.37 GiB (239967 extents).
  Logical volume bigroot successfully resized.



# resize2fs /dev/vg0/bigroot 
resize2fs 1.42.13 (17-May-2015)
Filesystem at /dev/vg0/bigroot is mounted on /; on-line resizing required
old_desc_blocks = 29, new_desc_blocks = 59
The filesystem on /dev/vg0/bigroot is now 245726208 (4k) blocks long.

Радуемся, что всё получилось!

# df -h|grep bigroot
/dev/mapper/vg0-bigroot  923G  174G  707G  20% /