Como posso instalar pacotes sem iniciar os serviços associados?

13

Como você provavelmente sabe, por padrão, quando você instala um pacote em um sistema baseado no Debian ou Ubuntu, se o pacote contiver um serviço, esse serviço geralmente será ativado e iniciado automaticamente quando você instala o pacote.

Isso é um problema para mim.

Percebi que precisava gerenciar modelos para a construção de contêineres LXC. Existem vários contêineres, cada um correspondente a uma versão do Debian ou Ubuntu. (Também existem contêineres baseados na Red Hat, mas eles não são relevantes aqui.)

/var/lib/libvirt/filesystems/debian6_template
/var/lib/libvirt/filesystems/debian7_template
/var/lib/libvirt/filesystems/ubuntu1004_template
/var/lib/libvirt/filesystems/ubuntu1204_template

Ocasionalmente, descobrirei que os modelos estão com um pacote ausente ou precisam de alguma outra alteração, por isso vou fazer um chroot neles para instalar o pacote. Infelizmente, quando faço isso, acabo com várias cópias do serviço do pacote em execução!

A título de exemplo, eu achei que os modelos não tinham um daemon syslog, então instalei um:

for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    chroot $template apt-get install rsyslog
done

E prontamente terminei com quatro cópias do rsyslog em execução. Sem mencionar duas cópias do exim4. Opa!


Eu li em algum lugar (embora não possa encontrá-lo novamente agora) que não deveria iniciar serviços ao executar um chroot, mas isso claramente não está acontecendo aqui.

Um hack desagradável potencialmente viável exige a substituição temporária dos vários comandos que realmente iniciam os serviços, como start-stop-daemone initctl, embora isso seja muito mais trabalho do que eu realmente queria. Se eu não tenho outra escolha, no entanto ...

A solução ideal aqui seria que os sistemas baseados no Debian parassem de fazer essa porcaria, mas na falta disso, talvez uma opção de linha de comando obscura ou não documentada para apt-get?

Caso não esteja claro, eu realmente quero manter qualquer coisa relacionada ao gerenciamento de modelos fora dos modelos, se possível.

Michael Hampton
fonte

Respostas:

23

Para o debian, você pode fazer isso com policy-rc.d . Aqui está uma explicação :

Os scripts de mantenedor de um pacote devem interagir apenas com o sistema init por meio de invoke-rc.d, update-rc.d e os cabeçalhos de script init LSB ... invoke-rc.d, antes de executar sua ação, verificará se /usr/sbin/policy-rc.d é executável, irá chamá-lo com o respectivo nome do serviço e o número do nível de execução atual em sua linha de comando e agir de acordo com seu código de saída. Por exemplo, um valor de retorno 101 impedirá que a ação planejada seja executada. Isso inclui o início automatizado do serviço após a instalação do pacote, bem como a interrupção do serviço na remoção do pacote e reduz o ritual de interrupção, atualização e reinício durante as atualizações do pacote para apenas executar a atualização que pode deixar a versão antiga do serviço em execução

Como você não deseja que nenhum serviço seja iniciado, seu script policy-rc.d pode ser simplesmente

#!/bin/sh
exit 101

Essa é a técnica usada por ferramentas como pbuilder e mkimage-debootstrap do Docker .

Infelizmente, essa técnica não funciona com chroots do Ubuntu . Os pacotes que se integram ao sistema init iniciam a chamada / usr / sbin / initctl, em vez de invoke-rc.d durante a instalação, e o initctl não consulta policy-rc.d. De acordo com o autor do iniciante, a solução alternativa é substituir / sbin / initctl por um link simbólico para / bin / true em um chroot. Você pode ver isso no mkimage-debootstrap também, eles

dpkg-divert --local --rename --add /sbin/initctl
ln -sf /bin/true sbin/initctl
sciurus
fonte
Isso parece bastante limpo, embora também precise ser removido antes de criar um contêiner a partir do modelo.
Michael Hampton
1
Obrigado por isso. Eu posso acabar tendo que copiar o script mkimage-debootstrap do Docker, pois eles parecem ter resolvido esse problema.
Michael Hampton
4

Você pode fazer:

export RUNLEVEL=1
for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    chroot $template apt-get install rsyslog
done
exit

Não testei com chroot, mas deve funcionar. Inicialmente, define a variável de ambiente RUNLEVEL, para que os processos iniciados pelo apt-get não iniciem nenhum serviço, porque eles "pensam" que o sistema está sendo executado no modo único. Como o ambiente é modificado da maneira que pode afetar os comandos futuros, é necessário sair do shell quando o ambiente modificado não é mais necessário, isso é realizado pelo comando exit no final. Não pode ser alguns pacotes (raro?) Que não irá instalar corretamente no modo single (mas AFAIK isso não deve ser problema na maioria dos casos).

DavisNT
fonte
A export RUNLEVEL=1parte importante está aqui? O que exatamente isso causa?
Michael Hampton
@MichaelHampton Acredito que a variável ambiental RUNLEVEL fornecerá o nível de execução atual. Nesse caso, ele está sobrescrevendo, para que qualquer aplicativo pense que está sendo executado no 1. É uma espécie de "kludge", mas deve ser suficiente.
WinkyWolly
Adicionado explicação para a resposta original. Basicamente, foi o que o @WinkyWolly disse.
21414 DavisNT
Infelizmente, rsyslogfoi um dos pacotes "raros" que explodiu completamente ao tentar instalar dessa maneira. Isso ainda pode ser útil, embora, assim você pode manter o upvote :)
Michael Hampton