¿Cómo puedo instalar paquetes sin iniciar sus servicios asociados?

13

Como probablemente ya sepa, de manera predeterminada cuando instala un paquete en un sistema basado en Debian o Ubuntu, si el paquete contiene un servicio, ese servicio generalmente se habilitará y se iniciará automáticamente cuando instale el paquete.

Esto es un problema para mi.

Me encontré necesitando administrar plantillas para construir contenedores LXC. Hay varios contenedores, cada uno correspondiente a una versión de Debian o Ubuntu. (También hay contenedores basados ​​en Red Hat, pero no son relevantes aquí).

/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, encontraré que las plantillas tienen un paquete faltante o que necesitan algún otro cambio, por lo que las utilizaré para instalar el paquete. ¡Desafortunadamente cuando hago eso, termino con varias copias del servicio del paquete ejecutándose!

A modo de ejemplo, descubrí que las plantillas no tenían un demonio syslog, así que instalé uno:

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

Y rápidamente terminó con cuatro copias de rsyslog ejecutándose. Sin mencionar dos copias de exim4. ¡Uy!


Leí en alguna parte (aunque no puedo encontrarlo de nuevo ahora) que no se supone que inicie los servicios cuando se ejecuta en un chroot, pero eso claramente no está sucediendo aquí.

Un truco desagradable potencialmente viable requiere reemplazar temporalmente los diversos comandos que realmente inician servicios, como start-stop-daemony initctl, aunque esto es mucho más trabajo de lo que realmente quería hacer. Si no tengo otra opción, sin embargo ...

La solución ideal aquí sería que los sistemas basados ​​en Debian dejen de hacer esta basura, pero en su defecto, ¿tal vez una opción de línea de comando oscura o indocumentada apt-get?

En caso de que no estuviera claro, realmente quiero mantener todo lo relacionado con la administración de las plantillas fuera de las plantillas, si es posible.

Michael Hampton
fuente

Respuestas:

23

Para debian puede hacer esto con policy-rc.d . Aquí hay una explicación :

Se supone que las secuencias de comandos del mantenedor de un paquete solo interactúan con el sistema init mediante invoke-rc.d, update-rc.d y los encabezados de secuencia de comandos LSB init ... invoke-rc.d, antes de realizar su acción, comprobará si /usr/sbin/policy-rc.d es ejecutable, lo llamará con el nombre del servicio respectivo y el número de nivel de ejecución actual en su línea de comando y actuará de acuerdo con su código de salida. Por ejemplo, un valor de retorno de 101 evitará que se tomen las acciones planificadas. Esto incluye el inicio automático del servicio después de la instalación del paquete, así como la detención del servicio en la eliminación del paquete y reduce el ritual de detención-actualización-reinicio durante las actualizaciones del paquete a solo realizar la actualización, lo que podría dejar la versión anterior del servicio en funcionamiento

Como no desea que se inicie ningún servicio, su script policy-rc.d puede ser simplemente

#!/bin/sh
exit 101

Esta es la técnica utilizada por herramientas como pbuilder y mkimage-debootstrap de Docker .

Desafortunadamente, esta técnica no funciona con los chroots de Ubuntu . Los paquetes que se integran con el sistema de arranque inicial llaman / usr / sbin / initctl en lugar de invoke-rc.d durante la instalación, y initctl no consulta la política-rc.d. Según el autor de upstart, la solución consiste en reemplazar / sbin / initctl con un enlace simbólico a / bin / true en un chroot. Puedes ver esto en mkimage-debootstrap también, lo hacen

dpkg-divert --local --rename --add /sbin/initctl
ln -sf /bin/true sbin/initctl
Sciurus
fuente
Esto parece bastante limpio, aunque también deberá eliminarse antes de crear un contenedor a partir de la plantilla.
Michael Hampton
1
Gracias por esto. Puede que termine teniendo que estafar el script mkimage-debootstrap de Docker, ya que parecen haber resuelto principalmente este problema.
Michael Hampton
4

Tu puedes hacer:

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

No lo he probado con chroot, pero debería funcionar. Al principio, establece la variable de entorno RUNLEVEL, por lo que los procesos iniciados por apt-get no iniciarán ningún servicio, ya que "pensarán" que el sistema se está ejecutando en modo único. A medida que el entorno se modifica de la manera en que puede afectar los comandos futuros, es necesario salir del shell cuando el entorno modificado ya no es necesario, esto se logra mediante el comando de salida al final. No puede haber algunos paquetes (raro?) Que no se instalará correctamente en el modo sencillo (pero que yo sepa esto no debería ser un problema en la mayoría de los casos).

DavisNT
fuente
¿Es export RUNLEVEL=1la parte importante aquí? ¿Qué hace que suceda exactamente?
Michael Hampton
@MichaelHampton Creo que la variable ambiental RUNLEVEL proporcionará el nivel de ejecución actual. En este caso, lo está sobrescribiendo para que cualquier aplicación piense que se está ejecutando en 1. Es una especie de "kludge" pero debería ser suficiente.
WinkyWolly
Se agregó una explicación a la respuesta original. Básicamente esto es lo que dijo @WinkyWolly.
DavisNT
Desafortunadamente, rsyslogresultó ser uno de los paquetes "raros" que explotó por completo al intentar instalar de esta manera. Sin embargo, esto puede ser útil, por lo que puede mantener el voto a favor :)
Michael Hampton