reload.sh

Series: projects January 20, 2016

W dobie wirtualizacji, konteneryzacji - krótko mówiąc - w czasie kiedy mamy narzędzia do bardzo szybkiego i sprawnego tworzenia środowisk sposób taki prawdopodobnie nigdy nie będzie Nam potrzebny. Jednak z racji tego, że lubimy dłubać w systemie i badać jego mechanizmy na pewno jest wart uwagi.

Narzędzie to pozwala na instalację systemu z poziomu i w miejsce już uruchomionego innego systemu operacyjnego na tym samym dysku. Repozytorium projektu znajduje się tutaj.

Co skrypt robi i wypluwa na ekran pokazuje poniższy zrzut:

Artykuł ten opisuje co dzieje się “pod spodem” oraz jakie kroki należy wykonać aby przeprowadzić poprawnie i z sukcesem całą procedurę.

Spis treści

Wprowadzenie

Można zainstalować system z płyty, można wykorzystać zewnętrzne narzędzia a można też przywrócić system z kopii - ale w jaki sposób wrzucić cały system na dysk na którym rezyduje już inny system i co więcej, jest uruchomiony i to z tego uruchomionego chcielibyśmy zainstalować właśnie nowy?

Opis procedury

Cała procedura wygląda mniej więcej tak (bez wdawania się w szczegóły):

  1. Pobranie kopii zapasowej systemu ze zdalnego serwera lub pobranie świeżego systemu (np. za pomocą narzędzia debootstrap pozwalającego na instalację dystrybucji debianopodobnych)
  2. Utworzenie katalogu roboczego w którym umieszczony zostanie nowy “tymczasowy” system
  3. Chroot do nowego “tymczasowego” środowiska
  4. Usunięcie danych aktualnego systemu oraz przywrócenie systemu z kopii

Import systemu

Czynności wstępne

Utworzenie katalogu roboczego i pobranie systemu za pomocą narzędzia deboostrap:

_working_directory="/mnt/system"
mkdir $_working_directory
debootstrap --verbose --arch amd64 {wheezy|jessie} . http://ftp.pl.debian.org/debian

Podmontowanie podsystemów proc, sys, dev i dev/pts:

for i in proc sys dev dev/pts ; do mount -o bind /$i $_working_directory/$i ; done

Przygotowanie system bazowego (tymczasowego)

Następnie należy pobrać kopię zapasową ze zdalnego serwera. Skoro system roboczy znajduje się w /mnt/system aktualnie działającego systemu, można utworzyć w nim katalog /mnt/backup i tam umieścić kopię zapasową.

Przyszedł czas udostępnić spakowany system nowo utworzonemu systemowi roboczemu. Utworzenie symlinków nic nie da ponieważ po wejściu do chrootowanego środowiska nie będzie możliwości dotknięcia niczego “na zewnątrz” (przynajmniej w teorii). Można po prostu skopiować obraz np. do katalogu /mnt/system/mnt:

cp system_backup_22012015.tgz $_working_directory/mnt

Jednak lepiej nie marnować miejsca i wykonać to innym sposobem (przy założeniu, że kopia znajduje się w /mnt/backup):

_backup_directory="${_working_directory}/mnt/backup"
mkdir $_backup_directory && mount --bind /mnt/backup $_backup_directory

Następnie chroot na nowym systemie:

chroot $_working_directory /bin/bash

Aktualizacja informacji o podmontowanych urządzeniach:

grep -v rootfs /proc/mounts > /etc/mtab

Znajdujemy się w chrootowanym środowisku systemu bazowego. Plik z kopią systemu, który należy przywrócić znajduje się w katalogu /mnt nowego środowiska.

W tym momencie z takiego systemu możliwe jest usunięcie plików systemu znajdującego się na dysku głównym co nie byłoby możliwe w przypadku próby usunięcia plików systemowych (całego systemu) z jego poziomu. Krótko mówiąc: z systemu bazowego istnieje możliwość usunięcia systemu, który znajduje się na głównym dysku co jest kluczową czynnością potrzebną do przywrócenia/instalacji nowego systemu.

W “nowym” systemie, kolejną rzeczą jaką należy wykonać jest podmontowanie dysku na którym znajduje się “stary” system (/dev/sda1):

_working_directory="/mnt/old_system"
_backup_directory="/mnt/backup"
mkdir $_working_directory && mount /dev/sda1 $_working_directory

Teraz należy wejść do katalogu /mnt/old_system i usunąć jego zawartość za pomocą polecenia rm, shred lub jakiegokolwiek innego. Ważne jest tylko to aby usunąć pliki/katalogi a nie wymazać cały dysk, ponieważ wtedy usuniemy wszystko i stracimy dostęp do maszyny:

for i in $(ls | awk '!(/proc/ || /dev/ || /sys/ || /mnt/)') ; do rm -fr $i ; done

Przywrócenie systemu z kopii zapasowej

Następnym krokiem jest przywrócenie systemu z kopii zapasowej. W tym celu należy wypakować zawartość archiwum do katalogu głównego (tutaj: /mnt/old_system):

tar xzvfp $_backup_directory/system_backup_22012015.tgz -C $_working_directory

Podmontowanie proc, sys, dev i dev/pts w nowym katalogu roboczym:

for i in proc sys dev dev/pts ; do mount -o bind /$i $_working_directory/$i ; done

I na koniec zainstalować i zaktualizować konfigurację programu rozruchowego (już bez zmiany chrootowanego środowiska):

chroot $_working_directory /bin/bash -c "grub-install --no-floppy --root-directory=/ /dev/sda"
chroot $_working_directory /bin/bash -c "update-grub"

Pliki starego systemu zostały usunięte a na ich miejsce weszły wszystkie pliki systemu z kopii.

Należy posprawdzać czy główne pliki konfiguracyjne (tj. /etc/fstab, /etc/network/\*) zawierają odpowiednie wpisy, aby potem nie było problemów z uruchomieniem takiego systemu.

Czynności poinstalacyjne

Po wykonaniu całej procedury należy odmontować katalogi proc, sys, dev i dev/pts:

cd
grep $_working_directory /proc/mounts | cut -f2 -d " " | sort -r | xargs umount -n

Podsystemów tych zamontowanych w /mnt/system (nie /mnt/old_system, ponieważ te zamontowane w tym katalogu musimy odmontować) nie należy odmontowywać.

Teraz ostrożnie, ponieważ znajdujemy się w środowisku pierwotnego systemu a ostatnią czynnością do wykonania pozostaje restart systemu. Wychodząc z konsoli superużytkownika np. poleceniem exit, stracimy możliwość restartu czy wyłączenia maszyny jeśli użytkownik z którego logowaliśmy się na roota nie ma do tego przywilejów. Co więcej stracimy także możliwość zalogowania się ponownie na root’a.

Żadne z dostępnych poleceń tj. halt, shutdown czy reboot nie zadziała. Należy przeładować konfigurację systemu - w tym celu należy posłużyć się debuggerem jądra (bez opcji ‘b’):

echo 1 > /proc/sys/kernel/sysrq
echo reisu > /proc/sysrq-trigger

Podane opcje oznaczają:

  • r - przełącza tryb klawiatury na raw. Pozwala na wysłanie ctrl + alt + del w przypadku problemów z obsługującą ją sesją X
  • e - wysyła sygnał SIGTERM do wszystkich procesów z wyjątkiem procesu init
  • i - wysyła sygnał SIGKILL do wszystkich procesów z wyjątkiem procesu init
  • s - wymusza synchronizację buforów dyskowych dla wszystkich zamontowanych systemów plików
  • u - remount na wszystkich systemach plików w tryb tylko do odczytu
  • b - powoduje natychmiastowy restart systemu, bez odmontowania dysków i zapisania ich buforów (tej opcji nie używamy, chyba, że konieczny jest restart systemu - ryzykujemy jednak ponieważ może dojść do uszkodzenia systemu plików)

Wymusiliśmy kilka czynności pomijając restart systemu - od tej chwili możemy pracować na nowych systemie (i to bez restartu serwera). Oczywiście zalecane jest pełne zrestartowanie maszyny w celu całkowitego załadowania aktualnego systemu. W tym celu wykonać należy:

sync ; reboot -f

Wykorzystanie skryptu

Skoro poznaliśmy jak to mniej więcej działa można zautomatyzować cały proces wykorzystując narzędzie, które napisałem.

reload.sh przyjmuje trzy parametry:

  • --base - wskazuje ścieżkę do systemu bazowego (tymczasowego); jeżeli nie podamy tego parametru system zostanie pobrany automatycznie (wymagane do tego jest narzędzie debootstrap)
  • --build - wskazuje ścieżkę do kopii systemu, który chcemy przywrócić
  • --disk - określa dysk, na którym będzie rezydował nowy system

Z rzeczy, które zostały do zrobienia/poprawienia jest możliwość przekazania do narzędzia schematu partycji.

Jeżeli mamy wszystko przygotowane wykonujemy:

./bin/reload.sh --base "/mnt/minimal-base" --build "/mnt/system-backup.tgz" --disk "/dev/vda"

built with Jekyll and trimstray blog — read the fine print