Comment réduire le système de fichiers racine sans démarrer un livecd

94

Je me trouve dans l'obligation de réorganiser les partitions d'un système pour déplacer des données précédemment situées sous le système de fichiers racine dans des points de montage dédiés. Les volumes sont tous au format LVM. Il est donc relativement facile de créer de nouveaux volumes, d'y déplacer des données, de réduire le système de fichiers racine, puis de monter les nouveaux volumes aux points appropriés.

Le problème est l'étape 3, réduisant le système de fichiers racine. Les systèmes de fichiers impliqués sont ext4, le redimensionnement en ligne est donc pris en charge. cependant, lorsqu'ils sont montés, les systèmes de fichiers peuvent uniquement être développés. Pour réduire la partition, vous devez la démonter, ce qui n'est bien sûr pas possible pour la partition racine en fonctionnement normal.

Les réponses sur le Web semblent tourner autour du démarrage d'un LiveCD ou d'un autre support de secours, de l'opération de réduction, puis du redémarrage sur le système installé. Cependant, le système en question est distant et je n’y ai accès que via SSH. Je peux redémarrer mais l'initialisation d'un disque de secours et l'exécution d'opérations à partir de la console sont impossibles.

Comment démonter le système de fichiers racine tout en conservant un accès distant au shell?

Tom Hunt
la source
Toute opportunité de monter temporairement le système de fichiers racine sur un autre serveur? par exemple, faire tourner une autre VM et lui présenter ce volume de disque?
Steve
Le serveur est physique, alors non.
Tom Hunt
4
Copier la racine dans tmpfs et pivot_rootlà-bas. Un exemple ici dreamlayers.blogspot.co.uk/2012/10/running-linux-from-ram.html - c'est difficile, mais si vous avez une boîte de test pour l'essayer, cela vaut la peine d'être examiné.
Steve
1
Un autre exemple ici, où l’accès à distance via ssh est considéré comme ivarch.com/blogs/oss/2007/01/…
steve
2
Si le LVM racine est suffisamment petit, vous pouvez le cloner sur un autre LVM et créer un restaurant de démarrage (temp new default) dans grub pour l'utiliser, puis démarrer à partir de celui-ci (en faisant de cela votre "système actif")
Rabin

Réponses:

171

Pour résoudre ce problème, les informations fournies à l' adresse http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml étaient essentielles. Cependant, ce guide s’applique à une très ancienne version de RHEL et diverses informations étaient obsolètes.

Les instructions ci-dessous sont conçues pour fonctionner avec CentOS 7, mais elles doivent être facilement transférables à toute distribution exécutant systemd. Toutes les commandes sont exécutées en tant que root.

  1. S'assurer que le système est dans un état stable

    Assurez-vous que personne ne l'utilise et que rien d'autre n'est important. C'est probablement une bonne idée d'arrêter les unités fournissant des services comme httpd ou ftpd, juste pour s'assurer que les connexions externes ne perturbent pas les choses au milieu.

    systemctl stop httpd
    systemctl stop nfs-server
    # and so on....
    
  2. Démontez tous les systèmes de fichiers inutilisés

    umount -a
    

    Cela imprimera un certain nombre d'avertissements «La cible est occupée», pour le volume racine lui-même et pour différents systèmes de sécurité temporaires / système. Ceux-ci peuvent être ignorés pour le moment. L'important est qu'aucun système de fichiers sur disque ne reste monté, à l'exception du système de fichiers racine lui-même. Vérifiez ceci:

    # mount alone provides the info, but column makes it possible to read
    mount | column -t
    

    Si vous voyez des systèmes de fichiers sur disque toujours montés, quelque chose ne fonctionne toujours pas. Vérifiez ce qu'il utilise fuser:

    # if necessary:
    yum install psmisc
    # then:
    fuser -vm <mountpoint>
    systemctl stop <whatever>
    umount -a
    # repeat as required...
    
  3. Faire la racine temporaire

    mkdir /tmp/tmproot
    mount -t tmpfs none /tmp/tmproot
    mkdir /tmp/tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot}
    cp -ax /{bin,etc,mnt,sbin,lib,lib64} /tmp/tmproot/
    cp -ax /usr/{bin,sbin,lib,lib64} /tmp/tmproot/usr/
    cp -ax /var/{account,empty,lib,local,lock,nis,opt,preserve,run,spool,tmp,yp} /tmp/tmproot/var/
    

    Cela crée un système racine très minimal, qui interrompt (entre autres choses) l'affichage de la page de manuel (non /usr/share), les personnalisations au niveau de l'utilisateur (non /rootou /home) et ainsi de suite. Cela est intentionnel, car cela constitue un encouragement à ne pas rester plus longtemps que nécessaire dans un système racinaire truqué par un jury.

    À ce stade, vous devez également vous assurer que tous les logiciels nécessaires sont installés, car cela endommagera également le gestionnaire de paquets. Parcourez toutes les étapes et assurez-vous de disposer des exécutables nécessaires.

  4. Pivoter dans la racine

    mount --make-rprivate / # necessary for pivot_root to work
    pivot_root /tmp/tmproot /tmp/tmproot/oldroot
    for i in dev proc sys run; do mount --move /oldroot/$i /$i; done
    

    systemd force les montages à autoriser le partage des sous-arbres par défaut (comme avec mount --make-shared), et cela entraîne l' pivot_rootéchec. Par conséquent, nous désactivons cela globalement avec mount --make-rprivate /. Les systèmes de fichiers système et temporaires sont déplacés en gros vers la nouvelle racine. Ceci est nécessaire pour que cela fonctionne du tout; les sockets pour la communication avec systemd, entre autres choses, résident dans /run, et il n’ya donc aucun moyen de faire en sorte que les processus en cours la ferment.

  5. S'assurer que l'accès à distance a survécu au basculement

    systemctl restart sshd
    systemctl status sshd
    

    Après avoir redémarré sshd, assurez-vous que vous pouvez y entrer en ouvrant un autre terminal et en vous reconnectant à la machine via ssh. Si vous ne pouvez pas, résolvez le problème avant de continuer.

    Une fois que vous avez vérifié, vous pouvez vous reconnecter, quittez le shell que vous utilisez actuellement et reconnectez-vous. Cela permet aux fourchettes restantes sshdde sortir et garantit que la nouvelle ne tient pas /oldroot.

  6. Fermez tout en utilisant l'ancienne racine

    fuser -vm /oldroot
    

    Ceci imprimera une liste des processus restant dans l'ancien répertoire racine. Sur mon système, cela ressemblait à ceci:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
                 root          1 ...e. systemd
                 root        549 ...e. systemd-journal
                 root        563 ...e. lvmetad
                 root        581 f..e. systemd-udevd
                 root        700 F..e. auditd
                 root        723 ...e. NetworkManager
                 root        727 ...e. irqbalance
                 root        730 F..e. tuned
                 root        736 ...e. smartd
                 root        737 F..e. rsyslogd
                 root        741 ...e. abrtd
                 chrony      742 ...e. chronyd
                 root        743 ...e. abrt-watch-log
                 libstoragemgmt    745 ...e. lsmd
                 root        746 ...e. systemd-logind
                 dbus        747 ...e. dbus-daemon
                 root        753 ..ce. atd
                 root        754 ...e. crond
                 root        770 ...e. agetty
                 polkitd     782 ...e. polkitd
                 root       1682 F.ce. master
                 postfix    1714 ..ce. qmgr
                 postfix   12658 ..ce. pickup
    

    Vous devez gérer chacun de ces processus avant de pouvoir démonter /oldroot. L'approche par la force brute est simplement kill $PIDpour chacun, mais cela peut casser des choses. Pour le faire plus doucement:

    systemctl | grep running
    

    Cela crée une liste de services en cours d'exécution. Vous devriez pouvoir corréler cela avec la liste des processus en cours /oldroot, puis émettre systemctl restartpour chacun d'eux. Certains services refuseront de se placer dans la racine temporaire et entreront dans un état d'échec. cela n'a pas vraiment d'importance pour le moment.

    Si le lecteur racine que vous souhaitez redimensionner est un lecteur LVM, vous devrez peut-être également redémarrer d'autres services en cours d'exécution, même s'ils n'apparaissent pas dans la liste créée par fuser -vm /oldroot. Si vous ne parvenez pas à redimensionner un lecteur LVM à l’étape 7, essayez systemctl restart systemd-udevd.

    Certains processus ne peuvent pas être traités simplement systemctl restart. Pour moi, ceux-ci sont inclus auditd(qui n'aime pas être tués via systemctl, et je voulais juste en avoir un kill -15). Ceux-ci peuvent être traités individuellement.

    Le dernier processus que vous trouverez, généralement, est systemdlui - même. Pour cela, lancez systemctl daemon-reexec.

    Une fois que vous avez terminé, la table devrait ressembler à ceci:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
    
  7. Démonter l'ancienne racine

    umount /oldroot
    

    À ce stade, vous pouvez effectuer toutes les manipulations dont vous avez besoin. La question initiale nécessitait une simple resize2fsinvocation, mais vous pouvez faire ce que vous voulez ici; un autre cas d’utilisation consiste à transférer le système de fichiers racine d’une simple partition vers LVM / RAID / peu importe.

  8. Faire pivoter la racine

    mount <blockdev> /oldroot
    mount --make-rprivate / # again
    pivot_root /oldroot /oldroot/tmp/tmproot
    for i in dev proc sys run; do mount --move /tmp/tmproot/$i /$i; done
    

    C’est un renversement simple de l’étape 4.

  9. Éliminer la racine temporaire

    Répétez les étapes 5 et 6, sauf /tmp/tmprooten lieu et place de /oldroot. Ensuite:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Comme il s’agit d’un tmpfs, la racine temporaire se dissout dans l’éther pour ne plus jamais être vue.

  10. Remets les choses à leur place

    Montez à nouveau les systèmes de fichiers:

    mount -a
    

    À ce stade, vous devez également mettre à jour /etc/fstabet grub.cfgen fonction des ajustements que vous avez effectués à l'étape 7.

    Redémarrez tous les services en échec:

    systemctl | grep failed
    systemctl restart <whatever>
    

    Autoriser à nouveau les sous-arbres partagés:

    mount --make-rshared /
    

    Démarrez les unités de service arrêtées - vous pouvez utiliser cette commande unique:

    systemctl isolate default.target
    

Et tu as fini.

Un grand merci à Andrew Wood, qui a élaboré cette évolution sur RHEL4, et à steve, qui m’ont fourni le lien avec l’ancien.

Tom Hunt
la source
11
Réponse géniale. Presque magique, et très clair et simple. Utilisé avec debian VPS sans aucun problème (je devais umount /oldroot/bootbien sûr passer à l'étape 6). Je relie votre réponse à d'autres questions SE qui n'ont pas eu de réponse ou de réponse négative.
vaab
3
Et résolu, le problème était comme @vaab a indiqué; vous devez umount /oldroot/bootavant vousumount /oldroot
ToBeReplaced
3
Le but est de démonter et de manipuler le système de fichiers racine sans avoir besoin d'une console physique. Autant que je sache, il n’ya aucun moyen de garder ouvert un service qui lit une partition tout en démontant cette partition. Si votre service ne touche pas le système de fichiers racine, vous pouvez le garder ouvert à l'aide mount --movedes fichiers tmpfs, mais cela n'est pas pris en charge.
Tom Hunt
2
Vous devez utiliser les fonctions du système d'exploitation pour redémarrer le démon init. Je n'ai jamais utilisé upstart, mais wiki.ubuntu.com/FoundationsTeam/Specs/… suggère que cela telinit upourrait faire ce que vous voulez.
Tom Hunt
3
Une erreur supplémentaire que j'ai rencontrée: / tmp est un disque mémoire sur mon système. Je me suis donc retrouvé avec un disque mémoire monté sur /oldroot/tmp, ce qui m’a empêché de démonter /oldroot, mais ne s’affiche fuserni dans, ni dans la lsofsortie. Il a fallu un peu regarder fixement systemd pour que ça marche ...
Chris Kitching
7

Si vous êtes sûr de ce que vous faites - et donc de ne pas expérimenter, vous pouvez vous connecter à initrd, qui est un moyen rapide et non interactif.

Voici comment procéder sur un système basé sur Debian.

Voir le code: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-resizefs.sh

Il existe un autre exemple: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-convert-ext3-ext4.sh

Szépe Viktor
la source
Lorsque vous répondez, il est préférable d' expliquer POURQUOI votre réponse est la bonne.
Stephen Rauch
1
C'est une bonne approche. J'aime le mien pour me permettre de faire les manipulations nécessaires de manière interactive; Cependant, celui-ci est probablement plus rapide. Il serait peut-être bon d’éditer plus de détails dans la réponse elle-même ou d’envisager d’autres plateformes (il semble que cette approche générale fonctionnerait toujours avec dracut ou mkinitcpio ou tout autre générateur d’initramfs vaguement moderne).
Tom Hunt
Désolé @ stephen-rauch Je voulais juste souligner l'idée pas l'exécution.
Szépe Viktor