El servidor Ubuntu 16.04 VM imagen aparentemente inicia el "apt-daily.service" cada 12 horas más o menos; este servicio realiza varias tareas relacionadas con APT, como actualizar la lista de paquetes disponibles, realizar actualizaciones desatendidas si es necesario, etc.
Al comenzar desde una VM "instantánea", el servicio se activa inmediatamente , ya que (supongo) systemd se da cuenta rápidamente que el temporizador debería haberse disparado hace mucho tiempo.
Sin embargo, una ejecución APT evita que otros procesos apt
se ejecuten ya que mantiene un bloqueo en /var/lib/dpkg
. El mensaje de error que indica esto se ve así:
E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
Necesito deshabilitar esta tarea automatizada APT) hasta que Ansible haya completado la configuración de la máquina (que generalmente implica la instalación de paquetes); vea https://github.com/gc3-uzh-ch/elasticluster/issues/304 para más información y contexto.
He probado varias opciones para deshabilitar la función "actualizaciones desatendidas" a través de un script de "datos de usuario" para cloud-init
, pero todos han fallado hasta ahora.
tarea systemd apt-daily.service
es activado por apt-daily.timer
. He intentado deshabilitar uno u otro, o ambos, con varias combinaciones de los siguientes comandos; aún así, el apt-daily.service
se inicia momentos después de que el VM se prepara para aceptar conexiones SSH ::
#!/bin/bash
systemctl stop apt-daily.timer
systemctl disable apt-daily.timer
systemctl mask apt-daily.service
systemctl daemon-reload
APT::Periodic::Enable
Guión /usr/lib/apt/apt.systemd.daily
lee algunas APT variables de configuración; la configuración APT::Periodic::Enable
desactiva la funcionalidad por completo (líneas 331--337). He intentado deshabilitarlo con el siguiente script ::
#!/bin/bash
# cannot use /etc/apt/apt.conf.d/10periodic as suggested in
# /usr/lib/apt/apt.systemd.daily, as Ubuntu distributes the
# unattended upgrades stuff with priority 20 and 50 ...
# so override everything with a 99xxx file
cat > /etc/apt/apt.conf.d/99elasticluster <<__EOF
APT::Periodic::Enable "0";
// undo what's in 20auto-upgrade
APT::Periodic::Update-Package-Lists "0";
APT::Periodic::Unattended-Upgrade "0";
__EOF
Sin embargo a pesar APT::Periodic::Enable
que tiene valor 0
desde la línea de comando (ver abajo), el unattended-upgrades
el programa aún se ejecuta ...
[email protected]:~$ apt-config Shell AutoAptEnable APT::Periodic::Enable
AutoAptEnable='0'
/usr/lib/apt/apt.systemd.daily
por completoEl seguimiento cloud-init
script elimina el script de actualizaciones desatendidas por completo ::
#!/bin/bash
mv /usr/lib/apt/apt.systemd.daily /usr/lib/apt/apt.systemd.daily.DISABLED
Aún así, la tarea se ejecuta y puedo verla en la tabla de procesos. aunque el archivo no existe si se prueba desde la línea de comando ::
[email protected]:~$ ls /usr/lib/apt/apt.systemd.daily
ls: cannot access '/usr/lib/apt/apt.systemd.daily': No such file or directory
Parece que el cloud-init
script (junto con la línea de comandos SSH) y el proceso raíz del sistema se ejecutan en sistemas de archivos y espacios de proceso separados ...
¿Hay algo obvio que me estoy perdiendo? ¿O hay alguna magia de espacio de nombres que no conozco?
Lo más importante: ¿cómo puedo desactivar el apt-daily.service
a través de un cloud-init
script?
Sí, había algo obvio que me faltaba.
Systemd tiene que ver con el inicio simultáneo de servicios, por lo que el cloud-init
el script se ejecuta al mismo tiempo the apt-daily.service
se activa. Para el momento cloud-init
consigue ejecutar la carga útil especificada por el usuario, apt-get update
ya se está ejecutando. Entonces, los intentos 2. y 3. fallaron no por alguna magia de espacio de nombres, sino porque alteraron el sistema demasiado tarde para apt.systemd.daily
para recoger los cambios.
Esto también significa que básicamente no hay forma de prevenirapt.systemd.daily
de la ejecución: solo se puede matar después de que se haya iniciado.
Este script de "datos de usuario" toma esta ruta ::
#!/bin/bash
systemctl stop apt-daily.service
systemctl kill --kill-who=all apt-daily.service
# wait until `apt-get updated` has been killed
while ! (systemctl list-units --all apt-daily.service | egrep -q '(dead|failed)')
do
sleep 1;
done
# now proceed with own APT tasks
apt install -y python
Todavía hay una ventana de tiempo durante la cual los inicios de sesión SSH son posibles todavía apt-get
no se ejecutará, pero no puedo imaginar otra solución que funcione en la imagen de la nube Ubuntu 16.04.
Nota: Desafortunadamente, parte de la solución a continuación no funciona en los sistemas Ubuntu 16.04 (como la del interrogador) porque la sugerencia systemd-run
invocación solo funciona en Ubuntu 18.04 y superior (vea comentarios para más detalles ). Dejaré la respuesta aquí porque esta pregunta sigue siendo un éxito popular, independientemente de la versión de Ubuntu que esté utilizando ...
En Ubuntu 18.04 (y superior) puede haber hasta dos servicios involucrados en el tiempo de arranque para actualizar/actualizar. El primero apt-daily.service
actualiza la lista de paquetes. Sin embargo, puede haber un segundo apt-daily-upgrade.service
que realmente instala paquetes críticos de seguridad. Un respuesta a la pregunta "Finalizar y deshabilitar/eliminar la actualización desatendida antes de que el comando regrese" ofrece un excelente ejemplo de cómo esperar a que ambos terminen (copiado aquí por conveniencia):
systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true
(tenga en cuenta que esto debe ejecutarse como root). Si está intentando deshabilitar estos servicios en futuras botas, deberá enmascarar AMBOS servicios:
systemctl mask apt-daily.service apt-daily-upgrade.service
Alternativamente, puedes systemctl disable
ambos servicios Y sus temporizadores asociados (es decir, apt-daily.timer
y apt-daily-upgrade.timer
).
Tenga en cuenta que las técnicas de enmascaramiento/desactivación en esta respuesta solo impiden la actualización/actualización en futuras botas; no las detendrán si ya se están ejecutando en el arranque actual.
Puede deshabilitar esto a través del módulo "bootcmd" cloud-init. Esto se ejecuta antes de que aparezca la red, lo cual es necesario antes de que apt update pueda tener la oportunidad de ejecutarse.
#cloud-config
bootcmd:
- echo 'APT::Periodic::Enable "0";' > /etc/apt/apt.conf.d/10cloudinit-disable
- apt-get -y purge update-notifier-common ubuntu-release-upgrader-core landscape-common unattended-upgrades
- echo "Removed APT and Ubuntu 18.04 garbage early" | systemd-cat
Una vez que ingrese a la instancia, también debe esperar a que finalicen las fases finales de cloud-init, ya que mueve las fuentes/listas aptas.
# Wait for cloud-init to finish moving apt sources.list around...
# a good source of random failures
# Note this is NOT a replacement for also disabling apt updates via bootcmd
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
echo 'Waiting for cloud-init to finish...'
sleep 3
done
Esto también es útil para ver qué tan temprano se ejecuta bootcmd:
# Show microseconds in systemd journal
journalctl -r -o short-precise
Puede verificar que esto funcionó de la siguiente manera:
apt-config dump | grep Periodic
# Verify nothing was updated until we run apt update ourselves.
cd /var/lib/apt/lists
Sudo du -sh . # small size
ls -ltr # old timestamps
¿No sería más fácil enmascarar la unidad?
systemctl mask apt-daily.service
?
Basado en la solución de Anon, creé este script, que después de ejecutarlo y luego reiniciarlo, resuelve el problema para mí:
#!/bin/sh
systemctl mask apt-daily.service apt-daily-upgrade.service
systemctl disable apt-daily.service apt-daily-upgrade.service
systemctl disable apt-daily.timer apt-daily-upgrade.timer
Si el propósito es aprovisionar la máquina sin incurrir en un error de bloqueo, la solución más simple y estable es ejecutar el comando remoto del aprovisionador (o los comandos relacionados con apt) mientras se bloquea el archivo de bloqueo apt-daily. Sin servicio de enmascaramiento/desactivación/espera, etc.etc.
En el servidor Ubuntu, los programas de actualización de paquetes (apt-daily, desatendido-actualizaciones, cloud-init), pasan por apt-daily, por lo que la solución puede centrarse en él.
Apt-daily usa los bloqueos flock(2)
, que, a diferencia de dpkg/apt (que usan fnctl
), se pueden administrar mediante una herramienta de línea de comandos, con la conveniencia de que admite esperar en el bloqueo.
Por lo tanto, si uno, por ejemplo, usa Chef, es tan simple como correr, en los nodos:
$ Sudo flock /var/lib/apt/daily_lock chef-client
y:
Si no se invoca el aprovisionador en los nodos, es posible modificar la configuración del aprovisionador (por ejemplo, Ansible Playbook) para ejecutar:
$ Sudo flock /var/lib/apt/daily_lock apt update
$ Sudo flock /var/lib/apt/daily_lock apt upgrade
(o cualquier variación, como sh -c '...'
y así)
Fuente: https://saveriomiroddi.github.io/Handling-the-apt-lock-on-ubuntu-server-installations .
Esto espera 1 segundo en un bucle while y comprueba si se libera el bloqueo.
while : ; do
sleep 1
echo $( ps aux | grep -c lock_is_held ) processes are using apt.
ps aux | grep -i apt
[[ $( ps aux | grep -c lock_is_held ) > 2 ]] || break
done
echo Apt released
Este cloud-init funciona.
#cloud-config
apt:
conf: |
APT {
Periodic {
Update-Package-Lists "0";
};
};
Unattended-Upgrade {
Package-Blacklist {
"*";
};
};
runcmd:
- [ systemctl, stop, apt-daily.timer, apt-daily-upgrade.timer ]
- [ systemctl, disable, apt-daily.timer, apt-daily-upgrade.timer ]