Cómo reducir el sistema de archivos raíz sin iniciar un livecd

94

Me encuentro necesitando reorganizar las particiones de un sistema para mover datos previamente bajo el sistema de archivos raíz a puntos de montaje dedicados. Todos los volúmenes están en LVM, por lo que esto es relativamente fácil: cree nuevos volúmenes, mueva datos a ellos, reduzca el sistema de archivos raíz y luego monte los nuevos volúmenes en los puntos apropiados.

El problema es el paso 3, reducir el sistema de archivos raíz. Los sistemas de archivos involucrados son ext4, por lo que se admite el cambio de tamaño en línea; sin embargo, mientras están montados, los sistemas de archivos solo pueden crecer. Reducir la partición requiere desmontarla, lo que, por supuesto, no es posible para la partición raíz en funcionamiento normal.

Las respuestas en la Web parecen girar alrededor del arranque de un LiveCD u otro medio de rescate, realizar la operación de reducción y luego reiniciar el sistema instalado. Sin embargo, el sistema en cuestión es remoto y solo tengo acceso a través de SSH. Puedo reiniciar, pero no es posible iniciar un disco de rescate y realizar operaciones desde la consola.

¿Cómo puedo desmontar el sistema de archivos raíz mientras mantengo el acceso remoto al shell?

Tom Hunt
fuente
¿Alguna oportunidad de montar temporalmente el sistema de archivos raíz en un servidor diferente? por ejemplo, girar otra máquina virtual y presentarle este volumen de disco?
Steve
El servidor es físico, así que no.
Tom Hunt
44
Copie la raíz a tmpfs y pivot_rootallí. Un ejemplo aquí dreamlayers.blogspot.co.uk/2012/10/running-linux-from-ram.html : es complicado, pero si tiene una caja de prueba para probarlo, vale la pena considerarlo.
Steve
1
Otro ejemplo aquí, donde el acceso remoto a través de ssh se considera ivarch.com/blogs/oss/2007/01/…
steve
2
Si el LVM raíz es lo suficientemente pequeño, puede clonarlo a otro LVM y crear un restaurante de arranque (temp nuevo predeterminado) en grub para usarlo, y luego arrancar desde él (convirtiéndolo en su "sistema en vivo")
Rabin

Respuestas:

171

Al resolver este problema, la información proporcionada en http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml fue fundamental. Sin embargo, esa guía es para una versión muy antigua de RHEL, y varias informaciones eran obsoletas.

Las instrucciones a continuación están diseñadas para funcionar con CentOS 7, pero deberían ser fácilmente transferibles a cualquier distribución que ejecute systemd. Todos los comandos se ejecutan como root.

  1. Asegúrese de que el sistema esté en un estado estable

    Asegúrese de que nadie más lo esté usando y que nada más importante esté sucediendo. Probablemente sea una buena idea detener las unidades que brindan servicios como httpd o ftpd, solo para asegurarse de que las conexiones externas no interrumpan las cosas en el medio.

    systemctl stop httpd
    systemctl stop nfs-server
    # and so on....
    
  2. Desmontar todos los sistemas de archivos no utilizados

    umount -a
    

    Esto imprimirá una serie de advertencias de 'El destino está ocupado', para el volumen raíz en sí y para varios FS temporales / del sistema. Estos pueden ser ignorados por el momento. Lo importante es que no quedan montados los sistemas de archivos en el disco, excepto el sistema de archivos raíz en sí. Verifica esto:

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

    Si ve algún sistema de archivos en el disco todavía montado, entonces todavía se está ejecutando algo que no debería. Comprueba lo que está usando fuser:

    # if necessary:
    yum install psmisc
    # then:
    fuser -vm <mountpoint>
    systemctl stop <whatever>
    umount -a
    # repeat as required...
    
  3. Haz la raíz temporal

    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/
    

    Esto crea un sistema raíz muy mínimo, que interrumpe (entre otras cosas) la visualización de la página de manual (no /usr/share), las personalizaciones a nivel de usuario (no /rooto /home), etc. Esto es intencional, ya que constituye un estímulo para no permanecer en un sistema raíz tan manipulado por el jurado más de lo necesario.

    En este punto, también debe asegurarse de que esté instalado todo el software necesario, ya que seguramente romperá el administrador de paquetes. Eche un vistazo a todos los pasos y asegúrese de tener los ejecutables necesarios.

  4. Pivotar en la raíz

    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 hace que los montajes permitan compartir subárbol de manera predeterminada (como con mount --make-shared), y esto hace pivot_rootque falle. Por lo tanto, desactivamos esto globalmente con mount --make-rprivate /. El sistema y los sistemas de archivos temporales se trasladan al por mayor a la nueva raíz. Esto es necesario para que funcione; los sockets para la comunicación con systemd, entre otras cosas, viven /run, por lo que no hay forma de hacer que los procesos en ejecución lo cierren.

  5. Asegúrese de que el acceso remoto haya sobrevivido al cambio

    systemctl restart sshd
    systemctl status sshd
    

    Después de reiniciar sshd, asegúrese de poder ingresar abriendo otro terminal y conectándose nuevamente a la máquina a través de ssh. Si no puede, solucione el problema antes de continuar.

    Una vez que haya verificado que puede conectarse nuevamente, salga del shell que está utilizando actualmente y vuelva a conectarse. Esto permite que la bifurcación restante sshdsalga y garantiza que la nueva no se mantenga /oldroot.

  6. Cierra todo lo que sigue usando la raíz antigua

    fuser -vm /oldroot
    

    Esto imprimirá una lista de procesos que aún se mantienen en el antiguo directorio raíz. En mi sistema, se veía así:

                 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
    

    Debe lidiar con cada uno de estos procesos antes de poder desmontar /oldroot. El enfoque de fuerza bruta es simplemente kill $PIDpara cada uno, pero esto puede romper las cosas. Para hacerlo más suavemente:

    systemctl | grep running
    

    Esto crea una lista de servicios en ejecución. Debería poder correlacionar esto con la lista de procesos en espera /oldroot, luego emitir systemctl restartpara cada uno de ellos. Algunos servicios se negarán a aparecer en la raíz temporal y entrarán en un estado fallido; estos realmente no importan por el momento.

    Si la unidad raíz que desea cambiar de tamaño es una unidad LVM, es posible que también deba reiniciar algunos otros servicios en ejecución, incluso si no aparecen en la lista creada por fuser -vm /oldroot. Si encuentra que no puede cambiar el tamaño de una unidad LVM en el Paso 7, intente systemctl restart systemd-udevd.

    Algunos procesos no pueden tratarse de manera simple systemctl restart. Para mí estos incluidos auditd(que no le gusta que lo maten a través de systemctl, por lo que solo quería un kill -15). Estos pueden ser tratados individualmente.

    El último proceso que encontrarás, por lo general, es en systemdsí mismo. Para esto, corre systemctl daemon-reexec.

    Una vez que haya terminado, la tabla debería verse así:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
    
  7. Desmontar la antigua raíz

    umount /oldroot
    

    En este punto, puede realizar cualquier manipulación que requiera. La pregunta original necesitaba una resize2fsinvocación simple , pero puede hacer lo que quiera aquí; otro caso de uso es transferir el sistema de archivos raíz de una partición simple a LVM / RAID / lo que sea.

  8. Gire la raíz hacia atrás

    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
    

    Esta es una inversión directa del paso 4.

  9. Deseche la raíz temporal

    Repita los pasos 5 y 6, excepto usar /tmp/tmprooten lugar de /oldroot. Entonces:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Como se trata de un tmpfs, en este punto, la raíz temporal se disuelve en el éter, para nunca volver a verse.

  10. Poner las cosas nuevamente en sus lugares.

    Montar sistemas de archivos nuevamente:

    mount -a
    

    En este punto, también debe actualizar /etc/fstaby grub.cfgde acuerdo con los ajustes que realizó durante el paso 7.

    Reinicie los servicios fallidos:

    systemctl | grep failed
    systemctl restart <whatever>
    

    Permitir subárboles compartidos nuevamente:

    mount --make-rshared /
    

    Inicie las unidades de servicio detenidas; puede usar este comando único:

    systemctl isolate default.target
    

Y tu estas listo.

Muchas gracias a Andrew Wood, quien resolvió esta evolución en RHEL4, y Steve, que me proporcionó el enlace a la primera.

Tom Hunt
fuente
11
Impresionante respuesta. Casi mágico, y muy claro y directo. Lo usé con Debian VPS sin ningún problema (solo tenía que hacerlo, umount /oldroot/bootpor supuesto, en la etapa 6). Estoy vinculando su respuesta a otras preguntas SE que no tuvieron respuesta o respuesta negativa.
vaab 01 de
3
Y resuelto, el problema fue como indicó @vaab; debe umount /oldroot/bootante ustedumount /oldroot
ToBeSustituido
3
El punto es desmontar y manipular el sistema de archivos raíz sin necesidad de una consola física. Hasta donde sé, no hay forma de mantener abierto un servicio que lee desde una partición mientras se desmonta esa partición. Si su servicio no toca el FS raíz, es posible que pueda mantenerlo abierto usando mount --movetmpfs, pero eso no es compatible.
Tom Hunt
2
Debe utilizar las funciones del sistema operativo para reiniciar el demonio init. Nunca he usado advenedizo, pero wiki.ubuntu.com/FoundationsTeam/Specs/… sugiere que telinit upodría hacer lo que quieres.
Tom Hunt
3
Una arruga adicional con la que me encontré: / tmp es un ramdisk en mi sistema, así que terminé con un ramdisk montado en /oldroot/tmp, lo que me impidió desmontar /oldroot, pero no aparece fuserni lsofsale. Tomó un poco de mirar a systemd para resolverlo ...
Chris Kitching
7

Si está seguro de lo que está haciendo, por lo que no está experimentando, puede conectarse a initrd, que es la forma no interactiva y rápida.

En un sistema basado en Debian, aquí es cómo.

Vea el código: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-resizefs.sh

Hay otro ejemplo: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-convert-ext3-ext4.sh

Szépe Viktor
fuente
Al dar una respuesta, es preferible dar una explicación de POR QUÉ su respuesta es la correcta.
Stephen Rauch
1
Este es un enfoque sólido. Me gusta el mío por dejarme hacer las manipulaciones necesarias de forma interactiva; Sin embargo, este es probablemente más rápido. Puede ser bueno editar algunos detalles más en la respuesta en sí misma, o considerar otras plataformas (parece que este enfoque general aún funcionaría con dracut o mkinitcpio o cualquier otro generador initramfs vagamente moderno).
Tom Hunt
Lo siento @ stephen-rauch, solo estaba señalando la idea, no la ejecución.
Szépe Viktor