Como reduzir o sistema de arquivos raiz sem inicializar um livecd

93

Acho que preciso reorganizar as partições de um sistema para mover dados anteriormente no sistema de arquivos raiz para pontos de montagem dedicados. Os volumes estão todos no LVM, então isso é relativamente fácil: crie novos volumes, mova dados para eles, reduza o sistema de arquivos raiz e monte os novos volumes nos pontos apropriados.

O problema é a etapa 3, diminuindo o sistema de arquivos raiz. Os sistemas de arquivos envolvidos são ext4, então o redimensionamento online é suportado; no entanto, enquanto montado, os sistemas de arquivos podem ser cultivados apenas. Para reduzir a partição, é necessário desmontá-la, o que obviamente não é possível para a partição raiz em operação normal.

As respostas na Web parecem girar em torno da inicialização de um LiveCD ou outra mídia de resgate, da operação de redução e, em seguida, da inicialização do sistema instalado. No entanto, o sistema em questão é remoto e eu tenho acesso apenas via SSH. Posso reiniciar, mas não é possível inicializar um disco de recuperação e executar operações no console.

Como desmontar o sistema de arquivos raiz, mantendo o acesso remoto ao shell?

Tom Hunt
fonte
Alguma oportunidade de montar temporariamente o sistema de arquivos raiz em um servidor diferente? por exemplo, gire outra VM e apresente esse volume de disco?
steve
O servidor é físico, então não.
Tom Hunt
4
Copie a raiz para tmpfs e pivot_rootpara lá. Um exemplo aqui: dreamlayers.blogspot.co.uk/2012/10/running-linux-from-ram.html - é complicado, mas se você tiver uma caixa de teste para experimentá-lo, vale a pena considerar.
steve
1
Outro exemplo aqui, onde o acesso remoto via ssh é considerado ivarch.com/blogs/oss/2007/01/…
steve
2
Se o LVM raiz é pequeno o suficiente, você pode cloná-lo para outro LVM e criar um restaurante de inicialização (temp novo padrão) no grub para usá-lo, e depois inicializar a partir dele (tornando-o seu "sistema
ativo

Respostas:

170

Para resolver esse problema, as informações fornecidas em http://www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml foram essenciais. No entanto, esse guia é para uma versão muito antiga do RHEL, e várias informações estavam obsoletas.

As instruções abaixo foram criadas para funcionar com o CentOS 7, mas devem ser facilmente transferíveis para qualquer distribuição que execute o systemd. Todos os comandos são executados como raiz.

  1. Verifique se o sistema está em um estado estável

    Certifique-se de que ninguém mais está usando e nada mais importante está acontecendo. Provavelmente, é uma boa idéia interromper as unidades de fornecimento de serviços como httpd ou ftpd, apenas para garantir que as conexões externas não atrapalhem as coisas.

    systemctl stop httpd
    systemctl stop nfs-server
    # and so on....
    
  2. Desmonte todos os sistemas de arquivos não utilizados

    umount -a
    

    Isso imprimirá vários avisos de 'O destino está ocupado', para o próprio volume raiz e para vários FSs temporários / do sistema. Estes podem ser ignorados no momento. O importante é que nenhum sistema de arquivos em disco permaneça montado, exceto o próprio sistema de arquivos raiz. Verifique isto:

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

    Se você vir algum sistema de arquivos em disco ainda montado, algo ainda está em execução que não deveria estar. Verifique o que está usando fuser:

    # if necessary:
    yum install psmisc
    # then:
    fuser -vm <mountpoint>
    systemctl stop <whatever>
    umount -a
    # repeat as required...
    
  3. Faça a raiz temporária

    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/
    

    Isso cria um sistema raiz muito mínimo, que interrompe (entre outras coisas) a visualização da página de manual (não /usr/share), personalizações no nível do usuário (não /rootou /home) e assim por diante. Isso é intencional, uma vez que constitui um incentivo para não permanecer em um sistema radicular equipado com júri por mais tempo do que o necessário.

    Nesse ponto, você também deve garantir que todo o software necessário esteja instalado, pois também quebrará o gerenciador de pacotes. Veja todas as etapas e verifique se você tem os executáveis ​​necessários.

  4. Gire na raiz

    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 faz com que as montagens permitam o compartilhamento de subárvore por padrão (como em mount --make-shared), e isso causa pivot_rootfalha. Portanto, desativamos isso globalmente com mount --make-rprivate /. Os sistemas e sistemas de arquivos temporários são movidos por atacado para a nova raiz. Isso é necessário para fazê-lo funcionar; os soquetes para comunicação com o systemd, entre outras coisas, estão disponíveis /rune, portanto, não há como fazer com que os processos em execução fiquem fechados.

  5. Garantir que o acesso remoto tenha sobrevivido à transição

    systemctl restart sshd
    systemctl status sshd
    

    Após reiniciar o sshd, assegure-se de poder entrar, abrindo outro terminal e conectando-o novamente à máquina via ssh. Se não conseguir, corrija o problema antes de prosseguir.

    Depois de verificar, você pode se conectar novamente, saia do shell que está usando no momento e reconecte-se. Isso permite que o garfo restante sshdsaia e garante que o novo não esteja segurando /oldroot.

  6. Feche tudo ainda usando a raiz antiga

    fuser -vm /oldroot
    

    Isso imprimirá uma lista de processos ainda mantendo o diretório raiz antigo. No meu sistema, ficou assim:

                 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
    

    Você precisa lidar com cada um desses processos antes de poder desmontar /oldroot. A abordagem da força bruta é simplesmente kill $PIDpara cada um, mas isso pode quebrar as coisas. Para fazer isso mais suavemente:

    systemctl | grep running
    

    Isso cria uma lista de serviços em execução. Você deve poder correlacionar isso com a lista de processos em espera /oldroote emitir systemctl restartpara cada um deles. Alguns serviços se recusam a aparecer na raiz temporária e entrar em um estado com falha; estes realmente não importam no momento.

    Se a unidade raiz que você deseja redimensionar for uma unidade LVM, também será necessário reiniciar alguns outros serviços em execução, mesmo que eles não apareçam na lista criada por fuser -vm /oldroot. Se você não conseguir redimensionar uma unidade LVM na Etapa 7, tente systemctl restart systemd-udevd.

    Alguns processos não podem ser tratados de maneira simples systemctl restart. Para mim, estes incluídos auditd(o que não gosta de ser morto via systemctl, e só queria um kill -15). Estes podem ser tratados individualmente.

    O último processo que você encontrará, geralmente, é systemdele próprio. Para isso, corra systemctl daemon-reexec.

    Quando terminar, a tabela deve ficar assim:

                 USER        PID ACCESS COMMAND
    /oldroot:    root     kernel mount /oldroot
    
  7. Desmonte a raiz antiga

    umount /oldroot
    

    Nesse ponto, você pode executar as manipulações necessárias. A pergunta original precisava de uma resize2fschamada simples , mas você pode fazer o que quiser aqui; outro caso de uso é transferir o sistema de arquivos raiz de uma partição simples para LVM / RAID / qualquer que seja.

  8. Gire a raiz de volta

    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
    

    Essa é uma reversão direta da etapa 4.

  9. Descarte a raiz temporária

    Repita as etapas 5 e 6, exceto usando /tmp/tmprootno lugar de /oldroot. Então:

    umount /tmp/tmproot
    rmdir /tmp/tmproot
    

    Como é um tmpfs, nesse ponto a raiz temporária se dissolve no éter, para nunca mais ser vista.

  10. Coloque as coisas de volta em seus lugares

    Monte os sistemas de arquivos novamente:

    mount -a
    

    Nesse ponto, você também deve atualizar /etc/fstabe grub.cfgde acordo com os ajustes feitos durante a etapa 7.

    Reinicie quaisquer serviços com falha:

    systemctl | grep failed
    systemctl restart <whatever>
    

    Permitir subárvores compartilhadas novamente:

    mount --make-rshared /
    

    Inicie as unidades de serviço paradas - você pode usar este único comando:

    systemctl isolate default.target
    

E você terminou.

Muito obrigado a Andrew Wood, que trabalhou nessa evolução no RHEL4, e a Steve, que me forneceu o link para o primeiro.

Tom Hunt
fonte
11
Resposta incrível. Quase mágico, e muito claro e direto. Usou-o com o VPS debian sem problemas (é umount /oldroot/bootclaro, no estágio 6). Estou vinculando sua resposta a outras perguntas de SE que não tiveram resposta ou resposta negativa.
vaab
3
E resolvido, o problema era como o @vaab indicado; você deve umount /oldroot/bootantes de vocêumount /oldroot
ToBeReplaced
3
O objetivo é desmontar e manipular o sistema de arquivos raiz sem precisar de um console físico. Até onde eu sei, não há como manter aberto um serviço que lê de uma partição enquanto desmonta a partição. Se o seu serviço não tocar no FS raiz, é possível mantê-lo aberto usando mount --moveo tmpfs, mas isso não é suportado.
Tom Hunt
2
Você precisa usar os recursos do sistema operacional para reiniciar o daemon init. Eu nunca usei o iniciante, mas o wiki.ubuntu.com/FoundationsTeam/Specs/… sugere que telinit upode fazer o que você deseja.
Tom Hunt
3
Uma ruga adicional Corri para: / tmp é um disco RAM no meu sistema, então eu acabei com um ramdisk montado na /oldroot/tmp, o que me impediu de desmontar /oldroot, mas não aparecem em fuserou lsofsaída. Tomou um pouco de ficar olhando para systemd de trabalho que um ...
Chris Kitching
7

Se você tem certeza do que está fazendo - portanto, não está experimentando, pode se conectar ao initrd, que é a maneira mais interativa e rápida.

Em um sistema baseado no Debian, aqui está como.

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

Há outro exemplo: https://github.com/szepeviktor/debian-server-tools/blob/master/debian-convert-ext3-ext4.sh

Szépe Viktor
fonte
Ao dar uma resposta, é preferível dar uma explicação sobre POR QUE sua resposta é essa.
Stephen Rauch
1
Esta é uma abordagem sólida. Gosto da minha por me deixar fazer as manipulações necessárias interativamente; no entanto, este é provavelmente mais rápido. Pode ser bom editar mais alguns detalhes na resposta em si, ou considerar outras plataformas (parece que essa abordagem geral ainda funcionaria com dracut ou mkinitcpio ou qualquer outro gerador vagamente moderno de initramfs).
21717 Tom Hunt
Desculpe @ stephen-rauch, eu estava apenas apontando a idéia, não a execução.
Szépe Viktor 15/02