web-dev-qa-db-fra.com

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

Je me retrouve à devoir réorganiser les partitions d'un système pour déplacer les données précédemment sous le système de fichiers racine vers des points de montage dédiés. Les volumes sont tous dans LVM, c'est donc relativement simple: créez de nouveaux volumes, déplacez-y des données, réduisez le système de fichiers racine, puis montez les nouveaux volumes aux points appropriés.

Le problème est l'étape 3, la réduction du système de fichiers racine. Les systèmes de fichiers impliqués sont ext4, donc le redimensionnement en ligne est pris en charge; cependant, une fois montés, les systèmes de fichiers ne peuvent être agrandis. Pour réduire la partition, il faut 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 dans 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 il n'est pas possible de démarrer un disque de secours et d'effectuer des opérations à partir de la console.

Comment puis-je démonter le système de fichiers racine tout en maintenant l'accès distant à Shell?

100
Tom Hunt

Pour résoudre ce problème, les informations fournies sur http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml étaient pivot. Cependant, ce guide est pour 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 devraient être facilement transférables à toute distribution exécutant systemd. Toutes les commandes sont exécutées en tant que root.

  1. Assurez-vous que le système est dans un état stable

    Assurez-vous que personne d'autre ne l'utilise et que rien d'autre d'important ne se passe. 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 affichera un certain nombre d'avertissements "La cible est occupée", pour le volume racine lui-même et pour divers FS temporaires/système. Celles-ci peuvent être ignorées pour le moment. Ce qui est important, c'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, alors quelque chose est toujours en cours d'exécution qui ne devrait pas l'être. 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) l'affichage des pages de manuel (pas de /usr/share), personnalisations au niveau de l'utilisateur (pas de /root ou /home) et ainsi de suite. C'est intentionnel, car cela constitue un encouragement à ne pas rester dans un tel système racinaire truqué par un jury plus longtemps que nécessaire.

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

  4. Pivotez 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 fait en sorte que les montages autorisent le partage des sous-arbres par défaut (comme avec mount --make-shared), ce qui provoque pivot_root échouer. 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. C'est nécessaire pour le faire fonctionner du tout; les sockets pour la communication avec systemd, entre autres, vivent dans /run, et donc il n'y a aucun moyen de faire fermer les processus en cours.

  5. Assurez-vous 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 entrer, en ouvrant un autre terminal et en vous reconnectant à la machine via ssh. Si vous ne le pouvez pas, résolvez le problème avant de continuer.

    Une fois que vous avez vérifié que vous pouvez vous reconnecter, quittez le shell que vous utilisez actuellement et reconnectez-vous. Cela permet au sshd restant bifurqué de sortir et garantit que le nouveau ne tient pas /oldroot.

  6. Fermez tout en utilisant l'ancienne racine

    fuser -vm /oldroot
    

    Cela affichera une liste des processus conservant toujours 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 force brute est simplement kill $PID pour 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 contenant /oldroot, puis lancez systemctl restart pour chacun d'eux. Certains services refuseront de remonter 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 certains 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 via un simple systemctl restart. Pour moi, cela incluait auditd (qui n'aime pas être tué via systemctl, et donc je voulais juste un kill -15). Ceux-ci peuvent être traités individuellement.

    Le dernier processus que vous trouverez généralement est systemd lui-même. Pour cela, exécutez systemctl daemon-reexec.

    Une fois que vous avez terminé, le tableau devrait ressembler à ceci:

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

    umount /oldroot
    

    À ce stade, vous pouvez effectuer toutes les manipulations dont vous avez besoin. La question d'origine avait besoin d'un simple resize2fs invocation, mais vous pouvez faire ce que vous voulez ici; un autre cas d'utilisation est le transfert du système de fichiers racine d'une simple partition vers LVM/RAID/autre.

  8. Faites pivoter la racine vers l'arrière

    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
    

    Il s'agit d'une inversion simple de l'étape 4.

  9. Éliminer la racine temporaire

    Répétez les étapes 5 et 6, sauf en utilisant /tmp/tmproot au lieu de /oldroot. Alors:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Comme c'est un tmpfs, à ce stade, la racine temporaire se dissout dans l'éther, pour ne plus jamais être vue.

  10. Remettez les choses à leur place

    Montez à nouveau les systèmes de fichiers:

    mount -a
    

    À ce stade, vous devez également mettre à jour /etc/fstab et grub.cfg conformément aux ajustements que vous avez effectués à l'étape 7.

    Redémarrez tous les services ayant échoué:

    systemctl | grep failed
    systemctl restart <whatever>
    

    Autoriser à nouveau les sous-arborescences partagées:

    mount --make-rshared /
    

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

    systemctl isolate default.target
    

Et tu as fini.

Un grand merci à Andrew Wood, qui a élaboré cette évolution sur RHEL4, et à Steve, qui m'a fourni le lien avec le premier.

182
Tom Hunt

Si vous êtes sûr de ce que vous faites - donc sans expérimenter, vous pouvez vous connecter à initrd qui est la méthode non interactive et rapide.

Sur un système basé sur Debian, voici comment.

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

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

10
Szépe Viktor

Ce que j'ai fait sur un VPS DigitalOcean (ayant 25G/dev/vda1 monté en tant que root):

  1. à l'aide de fdisk, supprimez la première partition (25G)
  2. créer une partition 20G (le premier secteur doit être le même que celui d'origine)
  3. créer une nouvelle partition (évidemment avec la taille 5G), ce sera/dev/vda2
  4. écrire la table de partition et quitter fdisk.
  5. créer un système de fichiers ext4 sur/dev/vda2
  6. notez les UUID des deux partitions (ls -l/dev/disk/by-uuid)
  7. remplacer/dev/vda1 UUID par/dev/vda2 UUID dans /boot/grub/grub.cfg et/etc/fstab
  8. monter/dev/vda2 sur/mnt
  9. copier tout (sauf dev, proc, run, sys, mnt) de/vers/mnt
  10. courir update-grub
  11. reboot et priez

Ce qui précède a bien fonctionné quand on m'a dit que resize2fs n'est pas pris en charge.

0
Zsombor