Віддалена переустановка Linux за ssh без доступу до консолі

Знадобилося мені перевстановити сервер, який як би хостился у знайомих знайомих. Там був сильно застарілий Debian, а, найголовніше, система стояла на звичайних розділах без lvm і простір було розподілено дуже не оптимально. Фізичний доступ до нього було практично нереально, місцевого адміна попросити щось зробити можна, але це могло зайняти тиждень. Віртуальний KVM у сервера, але ззовні на нього потрапити було не можна; як би хостера не було зайвих IP-адрес, а всередину його мережі потрапити було неможливо. Треба було перевстановити сервер з-під працюючої системи по ssh. Ага, давайте поміняємо ротор у турбіни не вимикаючи, потім її перезапустим і буде вона з новим ротором працювати!

Першою ідеєю було створити chroot оточення на ram-диску і з нього створити lvm і залити систему. Але не тут-то було, не дає система змінити таблицю розділів.

Другою ідеєю було взяти исходники дистрибутиву Debian, зашити у них IP-адресу сервера, перезібрати initrd з інсталятор Debian, ssh-сервером і моїми IP, підставити цей initrd в конфіг grub блоком за замовчуванням і перевантажитися. Після цього я повинен був отримати ssh консоль з мережевим установником. На стенді у мене вийшло! Але на бою все закінчилося невдачею, сервер не піднявся. Господарям сервер виявився не дуже потрібен, і справа затихла, але в мене залишилося відчуття невирішеною завдання.

Як-то з колегами обговорювали всякі деструктивні дії з системою (типу rm -rf /) і один з колег сказав, що можна відключити scsi диск, на якому знаходиться кореневий розділ і система не пискне. Це дало мені ідею номер три, взяти ідею один, відірвати диск, повернути диск і повернутий диск буде вже іншим, не тим що система не віддавала. Саме так і виявилося. А тепер по пунктах, як же все-таки перевстановити систему без доступу до фізичної консолі.

Попередження! Треба розуміти, що все, що ми будемо робити — дорога в один кінець, при помилці ми втрачаємо доступ до системи! Цілком можливо, що доведеться їхати 1500 кілометрів і лізти в шахту, щоб реанімувати сервер.

Будемо вважати, що IP нашої системи 192.168.56.102. Саме так було у мене на стенді. Плюс доступ до інтернету через проксі:

http://proxy:8080

Починаємо роботу на вихідній системі.

# System #0
Заходимо по ssh на сервер:

ssh 192.168.56.102

Створюємо каталог і файлову систему для «Системи вбивці», монтуємо її:

mkdir /target
mount none -t tmpfs -o size=1G /target/

Ставимо відмінну утиліту debootstrap, яка розгортає мінімальну встановлення Debian, за допомогою неї ми створимо chroot оточення:

export http_proxy='http://proxy:8080'
apt-get -y install debootstrap

Існують анологичные утиліти для Федори і Centos, відповідно febootstrap і yumbootstrap, але я з ними не працював.

Розгортаємо chroot:

debootstrap jessie /target/ http://mirror.mephi.ru/debian/

Перший аргумент — версія, другий — каталог установки, третій — репозиторій.

Бекапим найнеобхідніше:

mkdir /target/backup
cp /etc/network/interfaces /target/backup

Найважливіше — налаштування мережевих інтерфейсів, без них не вийде потрапити в переустановленную систему.

Даємо ім'я chroot-оточенню:

echo "Killer_system" > /target/etc/debian_chroot

Слово «Killer_system» буде показуватися в запрошенні bash. Це важлива річ, без неї не буде зрозуміло, де ми зараз знаходимося.

Переходимо в нове оточення.

# System #1
chroot /target

Монтуємо корисні fs:

mount none -t proc /proc/
mount none -t sysfs /sys/
mount none -t devtmpfs /dev/
mount none -t devpts /dev/pts/

Ще раз ставимо debootstrap:

apt-get -y install lvm2 debootstrap

Далі мої заморочки: у дебиановского пакету openssh-server в рекомендованих пакетах є пакет xauth, а у нього в залежностях всякі иксовые бібліотеки. Я, як прихильник мінімалізму, не хочу, щоб на сервері, де не було і не буде графіки, ставилися огризки іксів. Тому ставимо з ключиком --no-install-recommends:

apt-get -y install openssh-server openssh-client openssh-blacklist openssh-blacklist-extra --no-install-recommends

Правимо конфіги. Ставимо альтернативний порт для ssh демона, щоб ми могли зайти на chroot систему по ssh:

sed -i 's/^Port .*$/Port 11122/' /etc/ssh/sshd_config

І дозволяємо доступ для root:

sed -i 's/^PermitRootLogin .*$/PermitRootLogin yes/' /etc/ssh/sshd_config
/etc/init.d/ssh restart

Можна не давати доступ root, а створити користувача і дати йому sudo права, але тут я свідомо спрощую.

Далі треба ввести пароль root, так як за замовчуванням debootstrap не встановлює ніякі паролі:

passwd root

Заходимо в chroot оточення по ssh:

ssh 192.168.56.102 -l root -p 11122

Це ми робимо для того, щоб повністю позбутися старої системи, у якій ми відірвемо диски. А так у нас буде повністю автономна система оперативної пам'яті, ніяк не пов'язана зі старою.

Такий трюк дуже добре підходить, якщо ми йдемо від хостера, а залишати йому наші файли дуже не хочеться (я знаю, параноя). На цьому етапі просто забиваємо диски нулями, якщо хочемо швидко:

dd if=/dev/zero of=/dev/sda bs=1M

Або випадковими даними в кілька проходів, якщо хочемо добре. Перевага методу в тому, що ми можемо дочекатися закінчення роботи dd і, за потреби, повторити. Якщо ж затирати диски безпосередньо з бойової системи, то подивитися на результати роботи dd ми вже не зможемо.

Спробуємо простий шлях, видалимо тома і розділи:

# lvremove /dev/mapper/vg_old-root
Logical volume vg_root/lv_root contains a filesystem in use.

# fdisk /dev/sda
Command (m for help): d
Selected partition 1
Partition 1 has been deleted.
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).

Але невдача. При цьому розділ віддалиться, і система зламається, але скористатися простим шляхом без перезавантаження не вийде. А перевантажуватися буде нікуди.

Ми підемо іншим шляхом. Перевіряємо, де у нас знаходиться:

pvs
lsblk

Будемо вважати, що кореневий розділ у нас на диску sda.

Затираємо диск, щоб ні в якому разі його не підчепив lvm.

Попередження! Після цього моменту повернення немає, навіть наступний крок не такий шкідливий. Замислимось на хвильку, перевіримо консоль, за якої сидимо і виправдаємо ім'я нашого chroot'а:

dd if=/dev/zero of=/dev/sda bs=1M count=100

Відриваємо диски:

echo 1 > /sys/block/sda/device/delete

Перевіряємо, диск відірвався:

lsblk

Підключаємо диск назад:

for i in /sys/class/scsi_host/host?/scan ; do echo "- - -" > $i ; done

Перевіряємо, що повернулося:

lsblk

Був sda, став sdb, відмінно.

Важливий момент: на згрузочном диску необхідно створити первинний розділ розміром на весь диск і цей розділ віддати lvm'для того щоб на нього зміг встати grub. Всі інші диски можна віддавати lvm'у цілком не створюючи систему розділів (pvcreate /dev/sdc). Створюємо таблицю розділів і один первинний розділ типу 8e, Linux LVM:

fdisk /dev/sdb
n<CR> <CR> <CR> <CR>
t<RC> 8e<CR>
w<CR>
# create new primary partition from start to end; 8e type

У початковій версії сценарію було створення одного логічного томи під всю систему, але коли мій колега перевстановлював систему по цій системі, виявилося, що створення декількох розділів створює труднощі, особливо окремий розділ під логи. Увагу треба звернути на порядок створення точок монтування та власне монтування розділів.

pvcreate /dev/sdb1
vgcreate vg_root /dev/sdb1
lvcreate -Zn -L500M -n lv_swap0 vg_root
lvcreate -Zn -L1G -n lv_root vg_root
lvcreate -Zn -L2G -n lv_usr vg_root
lvcreate -Zn -L2G -n lv_var vg_root
lvcreate -Zn -L1G -n lv_var_log vg_root
lvcreate -Zn -L1G -n lv_home vg_root

mkswap /dev/vg_root/lv_swap0
mkfs.ext4 /dev/mapper/vg_root-lv_root
mkfs.ext4 /dev/mapper/vg_root-lv_usr
mkfs.ext4 /dev/mapper/vg_root-lv_var
mkfs.ext4 /dev/mapper/vg_root-lv_var_log
mkfs.ext4 /dev/mapper/vg_root-lv_home

mkdir /target
mount /dev/mapper/vg_root-lv_root /target/
mkdir /target/usr /target/var /target/home
mount /dev/mapper/vg_root-lv_usr /target/usr
mount /dev/mapper/vg_root-lv_var /target/var
mkdir /target/var/log
mount /dev/mapper/vg_root-lv_var_log /target/var/log
mount /dev/mapper/vg_root-lv_home /target/home

Розгортаємо вже бойову систему на нове місце на жорсткому диску:

export http_proxy='http://proxy:8080'
debootstrap jessie /target/ http://mirror.mephi.ru/debian/
echo "NEW_system" > /target/etc/debian_chroot

Повертаємо на місце резервні копії конфіги:

cp /backup/interfaces /target/etc/network

Тепер нас чекає нова система:

# System #2
chroot /target

Зверніть увагу, що в запрошенні командного рядка тепер ім'я нового chroot оточення.

Монтуємо файлові системи:

mount none -t proc /proc/
mount none -t sysfs /sys/
mount none -t devtmpfs /dev/
mount none -t devpts /dev/pts/

Ще можна примонтровать ці файлові системи з батьківського chroot'а:

mount -o bind /proc/ /target/proc
mount -o bind /sys/ /target/sys
mount -o bind /dev/ /target/dev
mount -o bind /dev/pts /target/dev/pts

Встановлюємо і конфігуруємо openssh:

apt-get -y install openssh-server openssh-client openssh-blacklist openssh-blacklist-extra --no-install-recommends

sed -i 's/^PermitRootLogin .*$/PermitRootLogin yes/' /etc/ssh/sshd_config
passwd root

Встановлюємо пакети, без яких не обійтися:

apt-get -y install vim sudo linux-image-3.16.0-4-amd64 grub2 lvm2 psmisc vlan 

Так, я не можу жити без vim і ненавиджу nano:

update-alternatives --set editor /usr/bin/vim.basic

В принципі grub прописується куди треба ще при установці, але, все ж, для підтримки штанів і морального духу повторимо:

update-grub
grub-install /dev/sdb

Тепер правимо конфіги, спочатку найважливіший, без якого система не підніметься:

cat > /etc/fstab <<EOF
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks and are added removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>

/dev/mapper/vg_root-lv_root / ext4 errors=remount-ro 0 1
/dev/mapper/vg_root-lv_usr /usr ext4 defaults 0 2
/dev/mapper/vg_root-lv_var /var ext4 defaults 0 2
/dev/mapper/vg_root-lv_var_log /var/log ext4 defaults 0 2
/dev/mapper/vg_root-lv_home /home ext4 defaults 0 2

EOF

У файлі interfaces все повинно бути в порядку, адже як-то мережа у нас працювала?

vim /etc/network/interfaces

В конфіг арт'а додаємо інформацію про проксі:

echo 'Acquire::http::Proxy "http://proxy:8080";' > /etc/apt/apt.conf

Міняємо hostname:

echo new-system > /etc/hostname

Додаємо рядок в /etc/hosts:

echo "192.168.56.102 new-system.corp new-system" >> /etc/hosts

Додаємо адміна:

adduser admin
usermod -a -G sudo admin
visudo

Размонтируем файлові системи:

umount /dev/pts
umount /dev/
umount /proc/
umount /sys/

І виходимо з chroot'а:

exit

Размонтируем файлові системи:

umount /target/usr/ /target/var/log/ /target/var/ /target/home/

Якщо розмонтувати /dev не вдалося, то не вдасться розмонтувати та /target, але це не страшно.

Якщо вдалося, то робимо так:

umount /target/

Якщо ні, то так:

sync ; sync ; sync ; mount -o remount,ro /target/

Ці команди скинуть дискові кеші і перемонтируют кореневу файлову систему в read only. Після цього можна перевантажуватися.

Тут нас чекає сюрприз від улюбленого systemd! Він знає, що ми в chroot і не дає перевантажитися! Google дає поради вийти з chroot, але нам-то виходити нікуди. Але на допомогу приходить Magic SysRq!

Активуємо SysRq (він, швидше за все, активований, але нам же треба переконатися?).

echo 1 > /proc/sys/kernel/sysrq

І перевантажуємося:

echo b > /proc/sysrq-trigger

Барабанний дріб, тривожне очікування, невже ми щось забули, і сервер не піднявся?

ssh 192.168.56.102

Ура! Ми в новій системі!

Пересоздадим initrd. Це не обов'язково, але в подальшому позбавить від деяких помилок при перезавантаженні:

update-initramfs -u

Видаляємо файлик з ім'ям chroot оточення:

rm /etc/debian_chroot

От і все.

## The end

Посилання:
Цікава стаття про перевантаження сервера
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.