Почему unattended-upgrades не работает в Debian
Пакет unattended-upgrades в Debian по умолчанию отключен. Узнайте, как активировать службу через dpkg-reconfigure, настроить Origins-Pattern и проверить таймеры systemd.
Почему unattended-upgrades не работает на свежей установке Debian
В Debian пакет unattended-upgrades может быть установлен, но при этом не выполнить ни одного обновления. Установка пакета и его активация — это два разных действия. Пакет задает вопрос через debconf перед завершением настройки, и установщик Debian сохраняет ответ false для этого вопроса. В Ubuntu на этот же вопрос дается противоположный ответ, поэтому один и тот же пакет там работает «из коробки», а здесь кажется неисправным.
В системе нет никаких указаний на эту проблему. При загрузке не возникает ошибок, при входе в систему не выводится предупреждений, а лог-файлы отсутствуют, так как код, отвечающий за их запись, просто не вызывается. Для включения автоматических обновлений достаточно одной команды. В остальной части этого руководства рассматриваются четыре фактора, которые могут блокировать работу даже после активации: список разрешенных репозиториев, фактическое время срабатывания таймеров systemd, способы уведомления о сбоях и разрешение системе выполнять автоматическую перезагрузку.
Выведите текущие настройки системы перед внесением изменений
dpkg -l unattended-upgrades | tail -n 1
sudo apt install -y debconf-utils
sudo debconf-show unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades
apt-config dump APT::Periodicdebconf-show выводит сохраненный ответ на unattended-upgrades/enable_auto_updates. Символ * в начале строки означает, что значение было задано принудительно, а не оставлено по умолчанию для пакета. На машине, установленной с помощью Debian installer, этим «кем-то» является сам установщик.
cat может вывести cat: /etc/apt/apt.conf.d/20auto-upgrades: No such file or directory. Это само по себе объясняет отсутствие активности: при отсутствии файла нет периодических ключей, поэтому ничего не запланировано.
apt-config dump — это важная команда. APT считывает каждый файл в /etc/apt/apt.conf.d/ в алфавитном порядке имен и объединяет их, поэтому значение, заданное в 99local, переопределяет такое же значение в 20auto-upgrades. Чтение одного файла показывает, что указано именно в нем. apt-config dump показывает, что APT будет делать на самом деле.
Два ключа определяют, будет ли вообще что-либо происходить:
APT::Periodic::Update-Package-Listsобновляет списки пакетов, что соответствует задаче, которуюapt updateвыполняет вручную.APT::Periodic::Unattended-Upgradeзапускает само обновление.
Их значения — это не true или false. Это интервалы в днях. "1" означает «выполнить, если это не делалось в течение последнего дня», "7" означает еженедельное выполнение, а "0" означает «никогда». APT::Periodic::Unattended-Upgrade "0"; — это корректная конфигурация, которая не выполняет ничего и никогда, не выдавая при этом ошибок. Если в вашем выводе для этого ключа указано 0 или такой ключ вообще отсутствует, вы нашли причину.
Включение: dpkg-reconfigure или ручная запись ключей
sudo apt update
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades--priority=low здесь обязателен. Вопрос имеет низкий приоритет, поэтому при стандартном приоритете dpkg-reconfigure ничего не выводит, ничего не меняет и завершается с кодом 0, что выглядит как успешно выполненная команда. Ответьте утвердительно в диалоговом окне. После этого скрипт postinst пакета запишет /etc/apt/apt.conf.d/20auto-upgrades на основе вашего ответа.
На машине, которую вы разворачиваете с помощью скрипта, диалогового окна нет, поэтому сначала задайте ответ:
echo 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean true' \
| sudo debconf-set-selections
sudo dpkg-reconfigure -f noninteractive unattended-upgrades
apt-config dump APT::PeriodicВы также можете записать два ключа напрямую:
printf 'APT::Periodic::Update-Package-Lists "1";\nAPT::Periodic::Unattended-Upgrade "1";\n' \
| sudo tee /etc/apt/apt.conf.d/20auto-upgrades
apt-config dump APT::PeriodicЭто сработает немедленно, но оставит скрытую проблему. Ответ в debconf останется прежним, поэтому при следующем вызове dpkg-reconfigure или переустановке пакета файл будет перезаписан на основе данных debconf, что отменит ваши правки без какого-либо вывода в консоль. Устанавливайте оба значения или настройте debconf, позволив postinst управлять файлом.
Это единственное существенное отличие от другой ветки семейства дистрибутивов. Там установщик включает этот пакет автоматически, поэтому настройка unattended-upgrades в Ubuntu начинается с системы, которая уже обновляет себя сама, и всё внимание уделяется только тонкой настройке. Всё, что описано ниже, применимо к обоим вариантам.
Какие именно обновления устанавливает Debian?
Включение таймера не означает автоматическое согласие на установку всего подряд. Каждый источник пакетов содержит метаданные релиза: origin (источник), label (метку), suite (набор), codename (кодовое имя) и site (сайт). unattended-upgrades анализирует версию-кандидат каждого пакета, доступного для обновления, считывает метаданные источника и устанавливает пакет только в том случае, если этот источник соответствует записи в Unattended-Upgrade::Origins-Pattern. Отсутствие совпадения означает отказ от обновления; это происходит без вывода сообщений, согласно логике работы программы.
Выведите свои шаблоны, а затем метаданные, с которыми они сопоставляются:
apt-config dump Unattended-Upgrade::Origins-Pattern
grep -H -E '^(Origin|Label|Suite|Codename|Components):' /var/lib/apt/lists/*Release
apt-cache policygrep -H сохраняет имя файла в каждой строке, чтобы вы видели, к какому источнику относится каждый блок метаданных. Значения этих полей — это правые части ваших шаблонов. ${distro_codename} внутри шаблона во время выполнения заменяется на кодовое имя текущего релиза, поэтому один файл конфигурации продолжает работать даже после обновления дистрибутива.
Изучите свои шаблоны вместе с этими метаданными, так как ответ на вопрос «получаю ли я только исправления безопасности или также обновления точечных релизов» написан именно там, и нигде больше:
- Шаблон, указывающий на
label=Debian-Security, соответствует архиву безопасности. Именно туда поступают бюллетени безопасности Debian. - Шаблон, указывающий на набор
-updates, соответствует stable-updates, где содержатся изменения, которые Debian выпускает между точечными релизами, например, данные о часовых поясах. - Шаблон, указывающий на обычный набор релиза, подтягивает изменения точечных релизов по мере их публикации, что влечет за собой больше изменений и требует больше усилий по тестированию с вашей стороны.
- Репозиторий, который вы добавили самостоятельно, не будет соответствовать ничему, пока вы не напишете для него шаблон.
Последний пункт часто становится неожиданностью. У стороннего репозитория есть свой origin и своя label, поэтому unattended-upgrades видит кандидата, понимает, что источник ничему не соответствует, и пропускает его. Добавление шаблона для такого репозитория — решение, которое стоит принимать взвешенно, так как поставщик может выпустить новую мажорную версию в рамках того же набора, и вы тем самым согласитесь на автоматическое мажорное обновление этого ПО посреди ночи.
unattended-upgrades также никогда не переводит систему между релизами Debian. Программа обновляет пакеты только внутри того релиза, который установлен. Переход с одного стабильного релиза на следующий остается ручной задачей, которую вы планируете самостоятельно.
При изменении списка помните, что списки APT дополняются. Второй блок Origins-Pattern в другом файле добавляется к уже существующему списку, а не заменяет его. Если ваша цель — полная замена, сначала очистите список:
#clear Unattended-Upgrade::Origins-Pattern;
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};Размещайте локальные изменения в новом файле, который сортируется после стандартного, например /etc/apt/apt.conf.d/52unattended-upgrades-local. 50unattended-upgrades является conffile, поэтому его редактирование приведет к тому, что при каждом будущем обновлении пакета система будет останавливаться и спрашивать, что делать с вашей версией. Отдельный файл никогда не вызывает конфликтов.
Стоит вывести еще два параметра, пока вы здесь. Unattended-Upgrade::Allowed-Origins — это старая форма той же идеи, записанная в виде пар origin:archive; она до сих пор считывается, поэтому конфигурация, скопированная из руководств, часто содержит оба списка, что не дает четкого ответа, какой из них сработал. Unattended-Upgrade::Package-Blacklist содержит регулярные выражения для имен пакетов, и слишком общее выражение может заблокировать гораздо больше, чем вы планировали. Пробный запуск (dry run), приведенный ниже, покажет, что именно было применено.
Почему ничего не запустилось в ожидаемое время?
За это отвечают два таймера systemd, выполняющие разные задачи. apt-daily.timer запускает apt-daily.service, который обновляет списки пакетов и загружает их. apt-daily-upgrade.timer запускает apt-daily-upgrade.service, который вызывает unattended-upgrade. Оба запускают /usr/lib/apt/apt.systemd.daily с разными аргументами. Если второй таймер отключен или замаскирован, оба периодических ключа могут считывать 1, но установка так и не произойдет.
systemctl list-timers 'apt-daily*' --all
systemctl is-enabled apt-daily.timer apt-daily-upgrade.timer
systemctl cat apt-daily-upgrade.timerlist-timers выводит NEXT, LEFT, LAST и PASSED для каждого юнита. Таймер без NEXT не будет запущен. Если is-enabled выводит masked, это означает, что кто-то принудительно отключил его, и никакие изменения в apt.conf.d не исправят ситуацию.
Теперь изучите раздел [Timer], который вывел systemctl cat. OnCalendar — это самое раннее время, когда таймер может сработать. RandomizedDelaySec добавляет случайную задержку после этого момента, чтобы парк машин на Debian не обращался к зеркалам в одну и ту же секунду. Именно поэтому столбец NEXT показывает время, которое не совпадает с OnCalendar, и именно поэтому вчерашний запуск произошел в другую минуту. Это штатное поведение. Persistent=true означает, что машина, которая была выключена в запланированное время, выполнит задачу вскоре после следующей загрузки, а не пропустит день.
Чтобы изменить временное окно, используйте переопределение юнита вместо его редактирования:
sudo systemctl edit apt-daily-upgrade.timer[Timer]
OnCalendar=
OnCalendar=03:30
RandomizedDelaySec=30mПустая строка OnCalendar= обязательна, так как настройки юнитов, являющиеся списками, суммируются: если её пропустить, вы сохраните стандартное расписание и добавите к нему второе. systemctl edit автоматически перезагружает systemd, поэтому проверьте результат с помощью systemctl list-timers 'apt-daily*' и посмотрите на новое значение NEXT.
Вам не нужно ждать срабатывания таймера, чтобы протестировать это:
sudo systemctl start apt-daily-upgrade.service
journalctl -u apt-daily-upgrade.service --since -1hОдна вещь сбивает с толку тех, кто ищет информацию в /etc/cron.daily: APT по-прежнему поставляет /etc/cron.daily/apt-compat для систем без systemd. Прочитайте его с помощью cat. На машине с systemd он завершается досрочно, поэтому работа не выполняется дважды.
Проверка работы: unattended-upgrade --dry-run --debug
sudo unattended-upgrade --dry-run --debugИсполняемый файл называется в единственном числе, а пакет — во множественном. Ввод unattended-upgrades здесь выдает command not found, что многие ошибочно принимают за признак отсутствия пакета.
Эта команда отвечает почти на любой вопрос «почему пропущен этот пакет», так как выводит логику своих действий. В начале вывода отображаются источники, вычисленные на основе ваших шаблонов:
Allowed origins are: ...Затем для каждого пакета-кандидата выводится строка с записью об источнике версии, которую система собирается установить:
Checking: curl ([<Origin component:'main' archive:'stable' origin:'Debian' label:'Debian' site:'deb.debian.org' isTrusted:True>])Далее следует список пакетов, с которыми будут произведены действия, или, если обновлений нет:
No packages found that can be upgraded unattended and no pending auto-removalsСопоставьте первую и вторую части вывода для прямой диагностики. Найдите строку Checking: для пакета, который должен был обновиться. Сравните запись об источнике по каждому полю с разрешенными источниками, выведенными выше. Одно несовпадающее поле, чаще всего label или archive, и является причиной пропуска.
--dry-run помечает пакеты в памяти и ничего не устанавливает, поэтому запускайте его сколько угодно раз. Он всё равно делает запись в /var/log/unattended-upgrades/unattended-upgrades.log.
Если источники совпадают, а пакет всё равно не обновляется, проверьте следующее:
apt-mark showholdсодержит список пакетов, зафиксированных вами или сторонней утилитой. unattended-upgrades не будет обновлять зафиксированный (held) пакет.- Обновление требует удаления или добавления другого пакета. unattended-upgrades избегает этого, если соответствующие ключи не разрешают такие действия. Сравните результат с
sudo apt-get -s upgrade, где показано то же решение без учета этих правил безопасности. - dpkg находится в состоянии частичной настройки после прерванного выполнения. Исправьте это с помощью
sudo dpkg --configure -a, затем проверьте снова. /varпереполнен, поэтому загрузка и распаковка невозможны. Проверьте свободное место командойdf -h /var./bootзаполнен старыми ядрами, что препятствует установке нового ядра. Проверьте это черезdf -h /bootи выведитеapt-config dump Unattended-Upgrade::Remove-Unused-Kernel-Packages, чтобы узнать, включена ли очистка.
Если вы запустите apt вручную во время работы таймера, вы получите Could not get lock /var/lib/dpkg/lock-frontend. Это сообщение означает, что unattended-upgrades уже выполняет свою задачу. Дождитесь завершения процесса.
Как узнать, что выполнение завершилось с ошибкой?
Начните с логов, так как они существуют независимо от того, настроили ли вы что-то еще:
sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades.log
sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
journalctl -u apt-daily-upgrade.service --since -7dПервый файл — это лог решений: что проверялось, что было выбрано, что установлено. Второй содержит необработанный вывод dpkg, именно там отображается ошибка, если скрипт postinst пакета завершился неудачно. Отдельный лог завершения работы появляется, если обновления выполняются во время выключения машины.
Почта — стандартный способ оповещения:
Unattended-Upgrade::Mail "you@example.com";
Unattended-Upgrade::MailReport "on-change";MailReport принимает значения always, on-change и only-on-error. only-on-error кажется дисциплинированным выбором, но на сервере, куда никто не заходит, это обычно плохой вариант, так как машина, которая полностью перестала обновляться, также перестает отправлять ошибки. В этом случае тишина одинаково скрывает как исправный сервер, так и неработающий. on-change отправляет письмо каждый раз, когда что-то было установлено, поэтому почта служит подтверждением того, что таймер все еще работает.
Почта покидает машину только в том случае, если машина может ее отправить. unattended-upgrades передает сообщение локальной почтовой системе, поэтому вам нужен MTA (агент передачи почты), например postfix, или релей-клиент, совместимый с sendmail, например msmtp. Проверьте это с помощью command -v sendmail и command -v mail. Если ни один из них не установлен, отчет никуда не уйдет, обновление все равно выполнится, а сам факт сбоя останется незамеченным. Помните также, что у нового IP-адреса VPS нет репутации отправителя, поэтому почта, отправленная напрямую на публичный почтовый ящик, часто попадает в спам. Релей через почтового провайдера, которым вы уже пользуетесь, надежнее, чем запуск собственного сервера для этих целей.
Если вы не хотите использовать почту вовсе, следите за меткой времени лога с помощью любой имеющейся у вас системы мониторинга:
stat -c '%y %n' /var/log/unattended-upgrades/unattended-upgrades.logМетка времени, которая не менялась в течение недели, означает, что таймер остановился, независимо от того, что указано в конфигурации. Эту проверку стоит добавить к остальным регулярным проверкам обслуживания Linux-сервера.
Должен ли сервер перезагружаться автоматически?
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";Если параметр Automatic-Reboot установлен в true, unattended-upgrades выполняет перезагрузку без подтверждения, но только при условии, что после завершения работы существует файл /var/run/reboot-required. Этот маркер создается не самим unattended-upgrades. Его должен создавать другой пакет, и в Debian это обычно needrestart. Не стоит полагаться на то, что он там есть. Проверьте его наличие после следующего обновления ядра:
ls -l /var/run/reboot-required /var/run/reboot-required.pkgs
uname -r
dpkg -l 'linux-image-*' | grep '^ii'Если этот файл никогда не появляется в вашей системе, Automatic-Reboot "true" не сработает, и вы можете месяцами думать, что перезагружаетесь для обновления ядра, продолжая работать на старой версии. Команда uname -r в сравнении с самым новым установленным пакетом linux-image поможет прояснить ситуацию.
Параметр Automatic-Reboot-Time планирует перезагрузку на указанное время вместо немедленного выполнения. Если Automatic-Reboot-WithUsers установлен в false, перезагрузка будет пропущена, если в системе есть активные пользователи; на сервере, где сессия открыта постоянно, это означает, что перезагрузка не произойдет никогда.
Вопрос заключается в том, что произойдет после запуска системы, а не в самой перезагрузке. Сервис, запущенный вручную, не восстановится. Зашифрованный том, требующий парольную фразу при загрузке, не смонтируется. Две машины, зависящие друг от друга, могут подняться в неправильном порядке. Включите автоматическую перезагрузку для stateless-веб-сервера, который может быть недоступен в течение минуты в 02:00. Оставьте её выключенной там, где требуется присутствие человека, и настройте оповещение по файлу-маркеру, чтобы администратор сам выбрал подходящий момент. Промежуточным решением является needrestart, который перезапускает сервисы, использующие обновленные библиотеки, и таким образом покрывает всё, кроме ядра. Его стандартный режим требует подтверждения перед перезапуском, поэтому изучите /etc/needrestart/needrestart.conf, прежде чем полагаться на него в автоматическом режиме.
Работает ли это так же в testing и unstable?
Все описанное выше относится к Debian stable, где исправления безопасности поступают из отдельного архива с собственной меткой. Именно такая структура позволяет использовать настройку «только обновления безопасности». Другие ветки дистрибутива устроены иначе, поэтому конфигурация, скопированная с сервера stable, работает не так, как ожидает автор, а автоматические обновления в динамических ветках означают автоматическую смену мажорных версий. Это принципиально иной уровень ответственности. Если вы обдумываете этот выбор, в использовании Debian stable, testing или unstable на сервере описаны обязательства для каждой из них. В экосистеме Red Hat эта задача решается другими инструментами и с другой терминологией, а dnf-automatic в Rocky Linux и AlmaLinux использует для этого собственный таймер и файл конфигурации.
Автоматические обновления сокращают время между публикацией исправления и его установкой. Они не показывают, какие уязвимости остаются открытыми, поэтому используйте их в сочетании с проверкой известных CVE на вашем сервере. CVE расшифровывается как common vulnerabilities and exposures — это публичный идентификатор, под которым отслеживается исправление.
Пятиминутная проверка
apt-config dump APT::Periodicвыводит оба ключа с ненулевым значением.systemctl list-timers 'apt-daily*'выводит времяNEXTдля обоих таймеров.sudo unattended-upgrade --dry-run --debugвыводит разрешенные источники, включающие архив безопасности для вашего кодового имени.sudo systemctl start apt-daily-upgrade.serviceзавершается, и временная метка в/var/log/unattended-upgrades/unattended-upgrades.logобновляется.- Неделю спустя этот же лог содержит названия установленных пакетов.
Успешное прохождение первых четырех пунктов означает, что машина настроена. Успешное прохождение пятого пункта означает, что система работает.
FAQ
Почему Debian устанавливает unattended-upgrades, но оставляет их выключенными?
Пакет задает вопрос через debconf, unattended-upgrades/enable_auto_updates, и записывает /etc/apt/apt.conf.d/20auto-upgrades на основе ответа. Установщик Debian сохраняет false для этого вопроса, поэтому, когда пакет устанавливается как часть задачи или зависимость, он настроен на бездействие. Выполните sudo debconf-show unattended-upgrades, чтобы увидеть сохраненный ответ, а затем sudo dpkg-reconfigure --priority=low unattended-upgrades, чтобы изменить его. Низкий приоритет важен, так как при стандартном приоритете команда завершается, не показывая вам вопрос.
Как протестировать unattended-upgrades, не дожидаясь срабатывания таймера?
Выполните sudo unattended-upgrade --dry-run --debug. Команда выведет источники, которые она примет, по одной строке Checking: для каждого обновляемого пакета с привязанной записью об источнике, а также список пакетов для установки, ничего не устанавливая. Чтобы проверить реальный процесс, выполните sudo systemctl start apt-daily-upgrade.service, а затем изучите journalctl -u apt-daily-upgrade.service --since -1h вместе с /var/log/unattended-upgrades/unattended-upgrades.log.
Устанавливает ли unattended-upgrades обычные обновления наряду с исправлениями безопасности?
Только если это указано в шаблоне. Обновление пакета устанавливается, если источник, из которого он получен, соответствует записи в Unattended-Upgrade::Origins-Pattern; архив безопасности, набор stable-updates и любые добавленные вами репозитории являются отдельными записями. Выведите apt-config dump Unattended-Upgrade::Origins-Pattern на своей машине, а затем сравните результат с grep -H -E '^(Origin|Label|Suite|Codename):' /var/lib/apt/lists/*Release. Также утилита никогда не переводит систему на другой релиз Debian.
Почему обновление не запускается в то время, которое указано в таймере?
apt-daily-upgrade.timer устанавливает RandomizedDelaySec поверх OnCalendar, поэтому systemd выбирает случайный момент внутри этого интервала вместо запуска строго по календарному времени. Это распределяет нагрузку на все машины Debian, использующие одни и те же зеркала. systemctl list-timers 'apt-daily*' показывает момент, который был выбран фактически. Чтобы изменить интервал, выполните sudo systemctl edit apt-daily-upgrade.timer и добавьте пустую строку OnCalendar=, за которой следует ваше значение.
Стоит ли включать автоматическую перезагрузку для обновлений безопасности?
Только там, где незапланированная перезагрузка безопасна. Unattended-Upgrade::Automatic-Reboot "true" выполняет перезагрузку без подтверждения, если после работы утилиты существует /var/run/reboot-required; этот маркер создается другим пакетом, обычно needrestart, а не самим unattended-upgrades. Убедитесь, что файл появляется в вашей системе после обновления ядра, прежде чем доверять этой настройке. На машине, требующей парольную фразу при загрузке, или на той, где запущены сервисы, запущенные вручную, оставьте значение false и настройте оповещение о появлении файла-маркера, чтобы человек сам выбрал момент для перезагрузки.