Le serveur Ubuntu 16.04 VM démarre apparemment le "apt-daily.service" toutes les 12 heures environ; ce service exécute diverses tâches liées à APT comme l'actualisation de la liste des packages disponibles, la mise à niveau sans assistance si besoin, etc.
Lors du démarrage à partir d'un VM "instantané", le service est déclenché immédiatement , comme (je présume) que systemd se rend compte rapidement que la minuterie aurait dû sonner depuis longtemps.
Cependant, un APT empêche l'exécution d'autres processus apt
car il détient un verrou sur /var/lib/dpkg
. Le message d'erreur indiquant ceci ressemble à ceci:
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?
Je dois désactiver cette tâche automatisée APT jusqu'à ce qu'Ansible ait terminé la configuration de la machine (ce qui implique généralement l'installation de packages); voir https://github.com/gc3-uzh-ch/elasticluster/issues/304 pour plus d'informations et de contexte.
J'ai essayé diverses options pour désactiver la fonction "mises à niveau sans assistance" via un script "données utilisateur" pour cloud-init
, mais tous ont échoué jusqu'à présent.
tâche systemd apt-daily.service
est déclenché par apt-daily.timer
. J'ai essayé de désactiver l'un ou l'autre, ou les deux, avec diverses cobinations des commandes suivantes; encore, le apt-daily.service
est démarré quelques instants après que le VM est prêt à accepter les connexions SSH ::
#!/bin/bash
systemctl stop apt-daily.timer
systemctl disable apt-daily.timer
systemctl mask apt-daily.service
systemctl daemon-reload
APT::Periodic::Enable
Script /usr/lib/apt/apt.systemd.daily
lit quelques APT variables de configuration; le paramètre APT::Periodic::Enable
désactive complètement la fonctionnalité (lignes 331 à 337). J'ai essayé de le désactiver avec le script suivant ::
#!/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
Cependant, malgré APT::Periodic::Enable
ayant une valeur 0
depuis la ligne de commande (voir ci-dessous), le unattended-upgrades
le programme est toujours en cours d'exécution ...
ubuntu@test:~$ apt-config Shell AutoAptEnable APT::Periodic::Enable
AutoAptEnable='0'
/usr/lib/apt/apt.systemd.daily
tout à faitLe suivant cloud-init
le script supprime complètement le script des mises à niveau sans assistance ::
#!/bin/bash
mv /usr/lib/apt/apt.systemd.daily /usr/lib/apt/apt.systemd.daily.DISABLED
Pourtant, la tâche s'exécute et je peux la voir dans la table de processus! bien que le fichier n'existe pas s'il est sondé à partir de la ligne de commande ::
ubuntu@test:~$ ls /usr/lib/apt/apt.systemd.daily
ls: cannot access '/usr/lib/apt/apt.systemd.daily': No such file or directory
Il semble que le cloud-init
le script (avec la ligne de commande SSH) et le processus root systemd s'exécutent dans des systèmes de fichiers et des espaces de processus séparés ...
Y a-t-il quelque chose d'évident qui me manque? Ou y a-t-il une magie d'espace de noms en cours dont je ne suis pas au courant?
Plus important encore: comment désactiver le apt-daily.service
par un cloud-init
script?
Oui, il y avait quelque chose d'évident que je manquais.
Systemd concerne le démarrage simultané des services, donc le cloud-init
le script est exécuté en même temps le apt-daily.service
est déclenché. Par le temps cloud-init
obtient d'exécuter la charge utile spécifiée par l'utilisateur, apt-get update
est déjà en cours d'exécution. Les tentatives 2. et 3. ont donc échoué non pas à cause de la magie de l'espace de noms, mais parce qu'elles ont modifié le système trop tard pour apt.systemd.daily
pour reprendre les modifications.
Cela signifie également qu'il n'y a fondamentalement aucun moyen de empêcherapt.systemd.daily
de courir - on ne peut le tuer qu'après son démarrage.
Ce script "données utilisateur" emprunte cette route ::
#!/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
Il y a encore une fenêtre de temps pendant laquelle les connexions SSH sont encore possibles apt-get
ne fonctionnera pas, mais je ne peux pas imaginer une autre solution qui puisse fonctionner sur l'image cloud Ubuntu 16.04.
Remarque: Malheureusement, une partie de la solution ci-dessous ne fonctionne pas sur les systèmes Ubuntu 16.04 (comme celle du questionneur) car le systemd-run
l'invocation ne fonctionne que sur Ubuntu 18.04 et supérieur (voir commentaires pour plus de détails ). Je vais laisser la réponse ici parce que cette question est toujours populaire, quelle que soit la version d'Ubuntu que vous utilisez ...
Sur Ubuntu 18.04 (et versions ultérieures), il peut y avoir jusqu'à deux services impliqués dans la mise à jour/mise à niveau de l'aptitude au démarrage. Le premier apt-daily.service
Rafraîchit la liste des packages. Cependant, il peut y avoir un second apt-daily-upgrade.service
Qui installe en fait des packages critiques pour la sécurité. Une réponse à la question "Terminer et désactiver/supprimer la mise à niveau sans assistance avant le retour de la commande" donne un excellent exemple de la façon d'attendre la fin de ces deux opérations (copiées ici pour plus de commodité):
systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true
(notez que cela doit être exécuté en tant que root). Si vous essayez de désactiver ces services lors de futurs démarrages, vous devrez masquer LES DEUX services:
systemctl mask apt-daily.service apt-daily-upgrade.service
Vous pouvez également systemctl disable
Les deux services ET leurs minuteries associées (c'est-à-dire apt-daily.timer
Et apt-daily-upgrade.timer
).
Notez que les techniques de masquage/désactivation dans cette réponse empêchent uniquement la mise à jour/mise à niveau sur les futurs démarrages - ils ne les arrêteront pas s'ils sont déjà en cours d'exécution dans le démarrage actuel.
Vous pouvez le désactiver via le module cloud-init "bootcmd". Cela s'exécute avant que le réseau ne soit activé, ce qui est nécessaire avant que la mise à jour apt puisse avoir une chance de s'exécuter.
#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
Une fois que vous avez accédé à l'instance, vous devez également attendre la fin des phases finales de cloud-init, car il déplace les sources/listes apt.
# 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
Cela est également utile pour voir à quel point le bootcmd s'exécute:
# Show microseconds in systemd journal
journalctl -r -o short-precise
Vous pouvez vérifier que cela a fonctionné comme suit:
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
Ne serait-il pas plus facile de masquer l'unité
systemctl mask apt-daily.service
?
Basé sur la solution d'Anon, j'ai créé ce script qui, après avoir été exécuté puis redémarré, résout le problème pour moi:
#!/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 le but est de provisionner la machine sans encourir d'erreur de verrouillage, la solution la plus simple et la plus stable consiste à exécuter la commande à distance du provisionneur (ou les commandes liées à apt) tout en verrouillant le fichier de verrouillage apt-daily. Aucun service de masquage/désactivation/attente, etc., etc.
Dans le serveur Ubuntu, les programmes de mise à jour des packages (apt-daily, mises à jour sans assistance, cloud-init) passent par apt-daily, afin que la solution puisse être centrée sur elle.
Apt-daily utilise des verrous flock(2)
, qui, contrairement à dpkg/apt (qui utilisent fnctl
), peuvent être gérés via un outil en ligne de commande, avec la commodité qu'il prend en charge d'attendre le verrou.
Par conséquent, si l'on utilise, par exemple, Chef, c'est aussi simple que d'exécuter, sur les nœuds:
$ Sudo flock /var/lib/apt/daily_lock chef-client
et:
Si le provisionneur n'est pas appelé sur les nœuds, il est possible de modifier la configuration du provisionneur (par exemple. Playbook Ansible) pour exécuter:
$ Sudo flock /var/lib/apt/daily_lock apt update
$ Sudo flock /var/lib/apt/daily_lock apt upgrade
(ou toute variation, comme sh -c '...'
etc)
Source: https://saveriomiroddi.github.io/Handling-the-apt-lock-on-ubuntu-server-installations .
Cela attend 1 seconde dans une boucle while et vérifie si le verrou est libéré.
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
Ce cloud-init fonctionne.
#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 ]