Обновление пакетов в Debian и Ubuntu почти всегда выглядит одинаково: apt update, затем apt upgrade. Но вокруг этой операции часто нужны действия: сохранить снимок состояния пакетов, проверить свободное место, отправить уведомление, записать список установленных .deb в журнал. APT умеет вызывать собственные команды в определённые моменты — это и есть хуки. Они выполняются от root и дают удобную автоматизацию без патчей и обёрток. Ниже — как устроены хуки, где их размещать и какие сценарии действительно полезны.

Где APT ищет хуки

Конфигурация APT собирается из файлов в /etc/apt/apt.conf.d/, которые читаются в лексикографическом порядке. Имена вида 99local-hooks ставят ваши настройки после дистрибутивных. Синтаксис напоминает ISC-конфиги: имя параметра, значение в кавычках, точка с запятой. Списки команд задаются блоком в фигурных скобках.

sudo tee /etc/apt/apt.conf.d/99local-hooks >/dev/null <<'EOF'
DPkg::Post-Invoke { "/usr/local/sbin/apt-state-snapshot"; };
EOF
sudo chmod 0644 /etc/apt/apt.conf.d/99local-hooks
apt-config dump | grep -i invoke

Команды запускаются через /bin/sh от имени root, без интерактивного терминала. Вывод попадает в поток APT и может испортить прогресс-бар, поэтому всё лишнее отправляйте в logger или systemd-cat. PATH в этом окружении может быть минимальным: используйте абсолютные пути.

Точки вызова и их семантика

У APT несколько моментов вызова, и важно понимать разницу. DPkg::Pre-Invoke выполняется до запуска dpkg и может отменить операцию ненулевым кодом. DPkg::Post-Invoke — после завершения dpkg. DPkg::Post-Invoke-Success срабатывает только при успехе. DPkg::Pre-Install-Pkgs дополнительно получает на stdin список путей к .deb.

Для обновления индексов есть APT::Update::Pre-Invoke, APT::Update::Post-Invoke и APT::Update::Post-Invoke-Success. Сбой команды в Pre-хуке приводит к завершению операции с ошибкой; сбой пост-хука уже не откатывает установленные пакеты, но может изменить код возврата и запутать автоматизацию. Поэтому в пост-хуках добавляйте || true только осознанно: молчаливое проглатывание ошибок мешает диагностике.

Снимок состояния пакетов

Первый полезный сценарий — журнал состояния после каждой операции. Он пригодится при разборе инцидента: видно, какая версия пакета была установлена в конкретный момент. Скрипт не вызывает apt и не создаёт рекурсии.

#!/bin/sh
set -eu
umask 027

dir=/var/backups/apt-state
mkdir -p "$dir"
stamp=$(date +%Y%m%dT%H%M%S)

{
  date -Is
  dpkg-query -W -f='${Package}\t${Version}\t${Status}\n'
} > "$dir/$stamp.tsv"

find "$dir" -type f -name '*.tsv' -mtime +30 -delete

Подключите его к DPkg::Post-Invoke-Success. Файлы копятся в /var/backups/apt-state, старые удаляются через 30 дней. Проверьте результат командой ls -lt /var/backups/apt-state и сравните два снимка через diff. Это не резервная копия системы и не способ отката, а журнал для аудита.

Проверка свободного места

Второй сценарий защищает от установки, которая заполнит корень и оставит систему без журналов. Хук читает доступное место и завершает работу с ошибкой, если порог не достигнут.

#!/bin/sh
set -eu

avail=$(df -Pk /usr | awk 'NR==2 {print $4}')
need=$((2 * 1024 * 1024))   # 2 GiB в килобайтах

if [ "$avail" -lt "$need" ]; then
  echo "apt-hook: мало места на /usr, доступно ${avail}K" >&2
  exit 1
fi

Подключите скрипт к DPkg::Pre-Invoke. Порог подберите под размер обновлений: для рабочей станции хватит двух гигабайт, для сервера с крупными пакетами — больше. Учитывайте, что хук срабатывает и при удалении пакетов, когда места может быть мало, но операция полезна. Если это мешает, проверяйте переменную окружения или аргументы, которые передаёт APT, и пропускайте проверку для удаления.

Список пакетов на stdin

DPkg::Pre-Install-Pkgs передаёт команде пути к устанавливаемым .deb, по одному в строке. Это удобно для инвентаризации и проверки источника пакета. Читайте stdin построчно и не пытайтесь запустить apt внутри.

#!/bin/sh
set -eu

logger -t apt-hook "начало установки пакетов"
while IFS= read -r deb; do
  logger -t apt-hook "пакет: $deb"
done

logger -t apt-hook "список пакетов получен"

Записи ищите через journalctl -t apt-hook -n 30. Не выводите список в stdout: APT использует поток для своего интерфейса. Если нужно различать установку, обновление и удаление, используйте версию протокола 2 или 3 через DPkg::Tools::options::<команда>::Version, но для большинства задач достаточно путей к файлам.

Уведомления и защита от повторов

Пост-хук может отправить уведомление в journald, откуда его заберёт система мониторинга. Чтобы два параллельных APT-процесса не мешали друг другу, поставьте блокировку и таймаут. Это особенно важно на серверах, где ночью работает unattended-upgrades.

#!/bin/sh
set -eu

exec 9>/run/apt-hook.lock
flock -n 9 || exit 0

timeout 10 logger -t apt-hook "операция APT завершена: $(date -Is)"

Хук должен быть идемпотентным: повторный запуск не должен ломать данные или создавать дубли. Не храните в скриптах пароли и токены — файл читается root, но история правок и резервные копии часто доступны шире, чем кажется. Права на скрипт: владелец root, режим 0755, каталог без записи для остальных.

Ошибки, которые ломают автоматизацию

  • Вызов apt или dpkg внутри хука создаёт рекурсию и блокировку.
  • Долгий сетевой запрос без timeout подвешивает установку.
  • Вывод в stdout ломает прогресс и парсеры автоматизации.
  • Расчёт на переменные окружения интерактивного пользователя.
  • Хук срабатывает и в контейнерах, и при unattended-upgrades — проверяйте условия.
  • Отсутствие #clear при замене чужого списка команд.

Для отладки включите Debug::RunScripts: APT покажет, какие внешние команды вызывает. Конфигурацию удобно проверять в одноразовой виртуальной машине, а не на рабочем сервере. Команда apt-config dump показывает итоговое дерево настроек, включая унаследованные списки.

sudo apt-get -o Debug::RunScripts=1 install --reinstall hello
sudo apt-config dump | grep -A2 'DPkg::'
sudo systemctl status apt-daily.timer

Не используйте apt-get -s как доказательство работы хука: в режиме симуляции dpkg не вызывается, и часть точек может не сработать. Проверяйте на реальной, но одноразовой системе.

Чек-лист

  • Файл хука лежит в /etc/apt/apt.conf.d/ с правами 0644.
  • Скрипты принадлежат root и не используют относительные пути.
  • В пост-хуках есть блокировка и таймаут.
  • Вывод уходит в journald, а не в stdout.
  • Проверено поведение при unattended-upgrades и в контейнере.
  • Есть тестовая машина для проверки перед раскаткой.

Итог

APT-хуки — простой способ добавить в обновление пакетов аудит, проверку ресурсов и уведомления, не меняя сам APT. Работают они от root, поэтому требуют аккуратности: абсолютные пути, блокировки, таймауты и понятные журналы. Начните с одного снимка состояния, проверьте его на тестовой машине и только потом добавляйте проверки, способные отменить установку.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте