Как отключить `apt-daily.service` на образе облачной виртуальной машины Ubuntu?

60

Образ виртуальной машины сервера Ubuntu 16.04, по-видимому, запускает «apt-daily.service» каждые 12 часов или около того; эта служба выполняет различные задачи, связанные с APT, такие как обновление списка доступных пакетов, автоматическое обновление, если это необходимо, и т. д.

При запуске с «моментального снимка» виртуальной машины служба запускается немедленно , так как (я полагаю) systemd быстро понимает, что таймер должен был давно отключиться.

Однако работающий APT предотвращает запуск других aptпроцессов, поскольку он удерживает блокировку /var/lib/dpkg. Сообщение об ошибке, указывающее это выглядит так:

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?

Мне нужно отключить эту автоматическую задачу APT, пока Ansible не завершит настройку машины (которая обычно включает установку пакетов); см. https://github.com/gc3-uzh-ch/elasticluster/issues/304 для получения дополнительной информации и контекста.

Я пробовал различные варианты отключения функции «автоматических обновлений» с помощью сценария «пользовательские данные» cloud-init, но все они до сих пор не сработали.

1. Отключите задачу systemd

Systemd задача apt-daily.serviceзапускается apt-daily.timer. Я попытался отключить одну или другую, или обе, с различными сочетаниями следующих команд; Тем не менее, apt-daily.serviceон запускается через несколько секунд после того, как виртуальная машина готова принять соединения SSH:

    #!/bin/bash

    systemctl stop apt-daily.timer
    systemctl disable apt-daily.timer
    systemctl mask apt-daily.service
    systemctl daemon-reload

2. Отключить опцию конфигурации APT::Periodic::Enable

Скрипт /usr/lib/apt/apt.systemd.dailyчитает несколько переменных конфигурации APT; настройка полностью APT::Periodic::Enableотключает функциональность (строки 331--337). Я попытался отключить его с помощью следующего скрипта:

    #!/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

Однако, несмотря на APT::Periodic::Enableналичие значения 0из командной строки (см. Ниже), unattended-upgradesпрограмма все еще выполняется ...

    ubuntu@test:~$ apt-config shell AutoAptEnable APT::Periodic::Enable
    AutoAptEnable='0'

3. Удалить /usr/lib/apt/apt.systemd.dailyвообще

Следующий cloud-initскрипт полностью удаляет скрипт автоматического обновления:

    #!/bin/bash

    mv /usr/lib/apt/apt.systemd.daily /usr/lib/apt/apt.systemd.daily.DISABLED

Тем не менее, задача выполняется, и я вижу это в таблице процессов! хотя файл не существует, если проверено из командной строки ::

ubuntu@test:~$ ls /usr/lib/apt/apt.systemd.daily
ls: cannot access '/usr/lib/apt/apt.systemd.daily': No such file or directory

Похоже, что cloud-initскрипт (вместе с командной строкой SSH) и корневой процесс systemd выполняются в отдельных файловых системах и пространствах процессов ...

Вопросов

Есть что-то очевидное, чего мне не хватает? Или происходит какое-то волшебство пространства имен, о котором я не знаю?

Самое главное: как я могу отключить apt-daily.serviceсквозной cloud-initскрипт?

Риккардо Мурри
источник
2
Это не поможет вам, пока не будет добавлено официальное обновление пакета, но, пожалуйста, посмотрите патч, который я только что опубликовал для ошибки Debian # 844453 .
Звол
Возможно, вы пропустили --nowфлаг в systemctl disableкоманде, чтобы изменения вступили в силу немедленно. Это была моя проблема.
Даниэль Ф
@DanielF нет, потому что disable --nowэквивалентно stopпоследующему disable.
sourcejedi
1
По-видимому, это было окончательно исправлено в systemd в 2019 г. Фев: github.com/systemd/systemd/issues/5659 . Надеюсь, это будет в Ubuntu 20.04.
оснастка

Ответы:

38

Да, было нечто очевидное, чего мне не хватало.

Systemd все о параллельном запуске услуг, поэтому cloud-initскрипт запускается одновременноapt-daily.service срабатывает. К тому моменту, когда cloud-initисполняется заданная пользователем полезная нагрузка, apt-get updateона уже запущена. Таким образом, попытки 2. и 3. потерпели неудачу не из-за некоторой магии пространства имен, а потому, что они изменили систему слишком поздно, чтобы apt.systemd.dailyпринять изменения.

Это также означает, что в принципе нет способа предотвратить apt.systemd.daily запуск - его можно убить только после его запуска.

Этот сценарий «пользовательских данных» использует этот маршрут:

#!/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

Еще есть временное окно, в течение которого вход по SSH возможен, но не apt-get будет работать, но я не могу представить другого решения, которое может работать на стандартном облачном образе Ubuntu 16.04.

Риккардо Мурри
источник
у меня это работало на aws ubuntu 16.04, спасибо за решение
krisdigitx
Да, я иду по пути создания собственного AMI. Это также ускоряет установку общих служб.
Георгиосирони
Этого, кажется, недостаточно, я нахожу, что все еще встречаются редкие случаиapt-get -o Acquire::http::AllowRedirect=false update
Эдвард З. Ян
12

Примечание. К сожалению, часть решения, приведенного ниже , не работает в системах Ubuntu 16.04 (например, в вопроснике), поскольку предлагаемый systemd-runвызов работает только в Ubuntu 18.04 и выше (подробности см. В комментариях ). Я оставлю здесь ответ, потому что этот вопрос по-прежнему популярен, независимо от того, какую версию Ubuntu вы используете ...

В Ubuntu 18.04 (и выше) может быть до двух служб, участвующих в обновлении / обновлении времени загрузки. Первый apt-daily.serviceобновляет список пакетов. Однако может быть второй, apt-daily-upgrade.serviceкоторый фактически устанавливает критические пакеты безопасности. Ответ на «Terminate и отключить / удалить без присмотра обновления , прежде чем команда возвращает» вопрос дает отличный пример того , как ждать , пока оба они до конца (скопированного здесь для удобства):

systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true

(обратите внимание, это должно быть запущено от имени пользователя root). Если вы пытаетесь отключить эти службы в будущих загрузках, вам нужно замаскировать ОБА службы:

systemctl mask apt-daily.service apt-daily-upgrade.service

В качестве альтернативы вы можете использовать systemctl disableкак службы, так и связанные с ними таймеры (т.е. apt-daily.timerи apt-daily-upgrade.timer).

Обратите внимание, что методы маскирования / отключения в этом ответе только предотвращают обновление / обновление в будущих загрузках - они не остановят их, если они уже запущены в текущей загрузке.

скоро
источник
2
Отличный ответ, спасибо! Обратите внимание, что systemd-runв Ubuntu 16.04 он слишком стар, чтобы поддерживать этот --waitпараметр, но в действительности он не должен быть необходим для этой цели. (Согласно справочной странице, --waitожидает завершения подразделения, но достаточно дождаться его запуска, что является поведением по умолчанию systemd-run.)
Риккардо Мурри
Я исправлен: данное systemd-runзаклинание не работает на Ubuntu 16.04 вообще; он умирает с сообщением об ошибке Неизвестное назначение После = apt-daily.service apt-daily-upgrade.service . Похоже, что некоторые свойства объекта не были доступны systemd-run, см., Например, здесь
Риккардо Мурри
@ Риккардо-Мурри ты меня понял :-)! Я на самом деле задавался вопросом о различиях 16.04 / 18.04 (отсюда и ласка «до двух»), а потом забыл вставить оговорку. Какие изменения вы бы предложили?
Anon
@ riccardo-murri ах, это очень плохо, я добавлю большое предупреждение в начало ответа о том, что его нельзя использовать в Ubuntu 16.04
Anon
Отключил службы и перезапустил и все работает!
digz6666
4

Вы можете отключить это через модуль «bootcmd» cloud-init. Он запускается до запуска сети, что необходимо, прежде чем apt update сможет запустить.

#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

Как только вы войдете в экземпляр, вы также должны дождаться завершения финальных фаз cloud-init, поскольку он перемещает подходящие источники / списки.

# 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

Это также полезно, чтобы увидеть, как рано запускается bootcmd:

# Show microseconds in systemd journal
journalctl -r -o short-precise

Вы можете убедиться, что это работает следующим образом:

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
Карл Пикетт
источник
2

Не будет легче замаскировать устройство

systemctl mask apt-daily.service

?


источник
Не работает - см. Раздел 1. Отключите задачу systemd в тексте вопроса. Но все равно спасибо за предложение! :-)
Риккардо Мурри
2
отключить и замаскировать службу не то же самое. маска создает ссылку на / dev / null. ls -al /etc/systemd/system/ | grep alsa lrwxrwxrwx 1 root root 9 Sep 1 13:17 alsa-init.service -> /dev/nullДанные пусты.
2
я избавляюсь от автоматического обновления sudo dpkg-reconfigure -plow unattended-upgradesи запрещаю его. Так что статус модуля apt-daily.service мертв.
Привет @Bahamut спасибо за ваши усилия! Однако вопрос заключается в том, как отключить apt-daily.serviceиз cloud-initсценария и до его запуска после перезагрузки виртуальной машины: это означает: (1) это должно быть сделано не в интерактивном режиме, (2) это должно быть сделано до apt-daily.serviceпервого запуска. (Если мое понимание Systemd правильно, (2) не может фактически быть выполнена , как cloud-initи apt-dailyработать одновременно - видеть мой собственный ответ для больше.)
Риккардо Murri
1
Я пробовал это на нормальной физической машине (т.е. не на виртуальной машине) и могу подтвердить, что она не работает. Вам также необходимо остановить таймер: systemctl stop apt-daily.timer; systemctl отключить apt-daily.timer
happyskeptic
1

Это ждет 1сек в цикле и проверяет, снята ли блокировка.

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
Navidzj
источник