web-dev-qa-db-fra.com

Comment désactiver `apt-daily.service` sur le cloud Ubuntu VM?

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.

1. Désactivez la tâche systemd

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

2. Désactivez l'option de configuration 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'

3. Supprimer /usr/lib/apt/apt.systemd.daily tout à fait

Le 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 ...

Des questions

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?

70
Riccardo Murri

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.

43
Riccardo Murri

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.

17
Anon

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
5
Karl Pickett

Ne serait-il pas plus facile de masquer l'unité

systemctl mask apt-daily.service

?

2
user192526

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
1
nemesisfixx

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:

  • l'un ou l'autre chef-client saisira la serrure en premier, et tout service basé sur apt-daily attendra;
  • ou tout service basé sur apt-daily le verrouillera en premier, puis chef-clien attendra et enfin fonctionnera une fois apt-daily terminé.

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 .

1
Marcus

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
1
Navidzj

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 ]

0
Alexander