Como faço para parar todos os processos em um chroot?

16

Eu tenho um número de partições LVM, cada uma contendo uma instalação do Ubuntu. Ocasionalmente, eu quero fazer um apt-get dist-upgrade , para atualizar uma instalação para os pacotes mais recentes. Eu faço isso com o chroot - o processo geralmente é algo como:

$ sudo mount /dev/local/chroot-0 /mnt/chroot-0
$ sudo chroot /mnt/chroot-0 sh -c 'apt-get update && apt-get dist-upgrade'
$ sudo umount /mnt/chroot-0

[não mostrado: eu também monto e desmonto /mnt/chroot-0/{dev,sys,proc} como montagens de ligação para o% real/dev, /sys e /proc , já que o dist-upgrade parece esperar que elas estejam presentes]

No entanto, após a atualização para precisão, esse processo não funciona mais - o umount final falhará porque ainda há arquivos abertos no sistema de arquivos /mnt/chroot-0 . lsof confirma que existem processos com arquivos abertos no chroot. Esses processos foram iniciados durante o dist-upgrade, estou assumindo que isso ocorre porque certos serviços no chroot precisam ser reiniciados (por exemplo, através de service postgresql restart ) após o upgrade do pacote.

Então, eu acho que preciso dizer ao upstart para parar todos os serviços que estão rodando dentro deste chroot. Existe uma maneira de fazer isso de forma confiável?

Eu tentei:

cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'initctl' services 
initctl list | awk '/start\/running/ {print \}' | xargs -n1 -r initctl stop
EOF

Em que initctl list parece fazer a coisa certa e listar apenas os processos que foram iniciados nessa raiz específica. Eu tentei adicionar isso também, como sugerido por Tuminoid:

cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'service' services
service --status-all 2>/dev/null |
    awk '/^ \[ \+ \]/ { print \}' |
    while read s; do service \$s stop; done
EOF

No entanto, isso não parece pegar tudo; processos que foram daemonizados e reparados no PID 1 não são interrompidos. Eu também tentei:

sudo chroot /mnt/chroot-0 telinit 0

Mas, neste caso, o init não faz distinção entre as raízes separadas e desliga a máquina inteira.

Então, existe alguma maneira de dizer ao init para parar todos os processos em um chroot em particular, para que eu possa desmontar o sistema de arquivos com segurança? O upstart tem alguma facilidade para SIGTERM / SIGKILL todos os processos filhos (como seria feito durante o desligamento normal) dentro de um chroot?

    
por Jeremy Kerr 11.07.2012 / 11:38

5 respostas

16

Eu não confio em nada além do kernel para manter um estado sadio aqui, então eu não uso (ab) o init para realizar este trabalho, nem eu mesmo conto realmente saber o que está ou não está montado (alguns pacotes podem montar sistemas de arquivos extras, como binfmt_misc). Então, para abate de processo, eu uso:

PREFIX=/mnt/chroot-0
FOUND=0

for ROOT in /proc/*/root; do
    LINK=$(readlink $ROOT)
    if [ "x$LINK" != "x" ]; then
        if [ "x${LINK:0:${#PREFIX}}" = "x$PREFIX" ]; then
            # this process is in the chroot...
            PID=$(basename $(dirname "$ROOT"))
            kill -9 "$PID"
            FOUND=1
        fi
    fi
done

if [ "x$FOUND" = "x1" ]; then
    # repeat the above, the script I'm cargo-culting this from just re-execs itself
fi

E para a contagem de chroots, eu uso:

PREFIX=/mnt/chroot-0
COUNT=0

while grep -q "$PREFIX" /proc/mounts; do
    COUNT=$(($COUNT+1))
    if [ $COUNT -ge 20 ]; then
        echo "failed to umount $PREFIX"
        if [ -x /usr/bin/lsof ]; then
            /usr/bin/lsof "$PREFIX"
        fi
        exit 1
    fi
    grep "$PREFIX" /proc/mounts | \
        cut -d\  -f2 | LANG=C sort -r | xargs -r -n 1 umount || sleep 1
done

Como um adendo, gostaria de salientar que abordar isso como um problema de inicialização é provavelmente a maneira errada de examiná-lo, a menos que você tenha um init no chroot e em um espaço de processo separado (ou seja: no caso de Recipientes LXC). Com um único init (fora do chroot) e um espaço de processo compartilhado, isso não é mais o "problema do init", mas depende apenas de você encontrar os processos que por acaso têm o caminho ofensivo, daí o procedimento anterior. / p>

Não está claro a partir do seu post inicial se estes são sistemas totalmente inicializáveis que você está apenas atualizando externamente (que é como eu o leio), ou se são chroots que você usa para coisas como compilações de pacotes. Se for o último, você também pode querer um policy-rc.d em vigor (como o que aparece no mk-sbuild) que apenas proíbe o início de jobs do init. Obviamente, essa não é uma solução sensata, se estas também forem sistemas de inicialização.

    
por infinity 23.07.2012 / 08:18
0

Você mesmo já identificou o problema: Algumas coisas executam service ... durante o dist-upgrade e service não faz parte do Upstart, mas parte do sysvinit . Adicione uma magia awk similar em torno de service --status-all para parar os serviços do sysvinit como você usava para os serviços do Upstart.

    
por Tuminoid 11.07.2012 / 14:23
0

Eu sei que essa pergunta é bem antiga, mas acho que é tão relevante hoje quanto era em 2012, e espero que alguém ache este código útil. Eu escrevi o código para algo que estava fazendo, mas pensei em compartilhá-lo.

Meu código é diferente, mas as idéias são muito semelhantes a @infinity (na verdade - a única razão pela qual agora sei sobre / proc / * / root é por causa de sua resposta - obrigado @infinity!). Eu também adicionei algumas funcionalidades adicionais legais

#Kills any PID passed to it
#At first it tries nicely with SIGTERM
#After a timeout, it uses SIGKILL
KILL_PID()
{
        PROC_TO_KILL=$1

        #Make sure we have an arg to work with
        if [[ "$PROC_TO_KILL" == "" ]]
        then
                echo "KILL_PID: \ cannot be empty"
                return 1
        fi

        #Try to kill it nicely
        kill -0 $PROC_TO_KILL &>/dev/null && kill -15 $PROC_TO_KILL

        #Check every second for 5 seconds to see if $PROC_TO_KILL is dead
        WAIT_TIME=5

        #Do a quick check to see if it's still running
        #It usually takes a second, so this often doesn't help
        kill -0 $PROC_TO_KILL &>/dev/null &&
        for SEC in $(seq 1 $WAIT_TIME)
        do
                sleep 1

                if [[ "$SEC" != $WAIT_TIME ]]
                then
                        #If it's dead, exit
                        kill -0 $PROC_TO_KILL &>/dev/null || break
                else
                        #If time's up, kill it
                        kill -0 $PROC_TO_KILL &>/dev/null && kill -9 $PROC_TO_KILL
                fi
        done
}

Agora você faria 2 coisas para ter certeza de que o chroot pode ser desmontado:

Mate todos os processos que possam estar em execução no chroot:

CHROOT=/mnt/chroot/

#Find processes who's root folder is actually the chroot
for ROOT in $(find /proc/*/root)
do
        #Check where the symlink is pointing to
        LINK=$(readlink -f $ROOT)

        #If it's pointing to the $CHROOT you set above, kill the process
        if echo $LINK | grep -q ${CHROOT%/}
        then
                PID=$(basename $(dirname "$ROOT"))
                KILL_PID $PID
        fi
done

Mate todos os processos que possam estar rodando fora do chroot, mas interferindo com ele (ex: se o seu chroot for / mnt / chroot e dd estiver gravando em / mnt / chroot / testfile, / mnt / chroot falhará ao desmontar )

CHROOT=/mnt/chroot/

#Get a list of PIDs that are using $CHROOT for anything
PID_LIST=$(sudo lsof +D $CHROOT 2>/dev/null | tail -n+2 | tr -s ' ' | cut -d ' ' -f 2 | sort -nu)

#Kill all PIDs holding up unmounting $CHROOT
for PID in $PID_LIST
do
        KILL_PID $PID
done

Nota: execute todo o código como raiz

Além disso, para uma versão menos complexa, substitua KILL_PID por kill -SIGTERM ou kill -SIGKILL

    
por Tal 21.11.2014 / 01:53
0

jchroot : um chroot com mais isolamento.

Após o seu comando ter sido executado, qualquer processo iniciado pela execução deste comando será eliminado, qualquer IPC será liberado, qualquer ponto de montagem será desmontado. Tudo limpo!

O schroot ainda não é capaz de fazer isso, mas isso está planejado

Eu testei com sucesso no OpenVZ VPS, que não pode usar o docker ou o lxc.

Por favor, leia o blog do autor para mais detalhes:

link

    
por Like 08.06.2016 / 08:08
-1

schroot: Tem o recurso de gerenciamento de sessão. Quando você pára a sessão, todos os seus processos são mortos.

link : Estes scripts eliminam todo o processo chroot e desmontam todos os dispositivos montados.

    
por sdkie 01.07.2014 / 23:21