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?
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.
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....
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...
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.
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.
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
.
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
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.
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.
É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.
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.
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
Ce que j'ai fait sur un VPS DigitalOcean (ayant 25G/dev/vda1 monté en tant que root):
update-grub
reboot
et priezCe qui précède a bien fonctionné quand on m'a dit que resize2fs n'est pas pris en charge.