Как исправить ошибку apt «Could not get lock»

Опубликовано 12 мин. чтения

Почему apt внезапно оказывается заблокирован, какой процесс за этим стоит, как найти его через lsof и fuser и как удалить файл блокировки, не повредив базу пакетов.

Вы хотите быстро доустановить пакет, а apt прерывается уже через секунду. Вместо списка пакетов появляется строка, которую по всему миру ищут миллионы раз: Could not get lock. Первый порыв, который советует большинство инструкций, это сразу удалить файл блокировки. Именно такой порыв регулярно превращает безобидное ожидание в повреждённую базу пакетов. В этой статье разобран порядок действий, который работает на боевом сервере: сначала выяснить, кто держит блокировку, затем подождать, и только в самом конце вмешиваться.

Все команды выполняются от имени root. Если вы работаете под обычным пользователем, добавляйте впереди sudo. И сразу уточнение по области применения: тема касается исключительно Debian и Ubuntu. В AlmaLinux, Rocky Linux, RHEL и Oracle Linux нет ни apt-get, ни /var/lib/dpkg, а dnf решает вопрос совсем иначе, об этом раздел о различиях между системами ниже.

Как выглядит сообщение об ошибке

В зависимости от версии и от того, что именно apt пытался сделать, вывод отличается. Вот варианты, которые встречаются на практике:

E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (unattended-upgr)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 987 (apt-get)
E: Unable to lock directory /var/lib/apt/lists/
dpkg: error: dpkg frontend lock is locked by another process
dpkg: error: dpkg status database is locked by another process

Русская локализация сообщает то же самое словами «Не удалось получить блокировку» и «Невозможно заблокировать каталог управления». Важна подсказка в скобках: имя процесса. unattended-upgr, apt-get, aptitude, packagekitd или dpkg уже говорят вам, где искать.

Четыре файла блокировки, четыре разных сообщения

apt и dpkg блокируют не одно место, а четыре. По имени файла в сообщении видно, на какой стадии возник конфликт:

  • /var/lib/apt/lists/lock защищает загруженные списки пакетов. Это сообщение появляется при apt update.
  • /var/cache/apt/archives/lock защищает каталог загрузки файлов .deb. Это сообщение появляется, пока apt скачивает пакеты.
  • /var/lib/dpkg/lock-frontend — самая верхняя блокировка. Она гарантирует, что с dpkg одновременно разговаривает только один интерфейс (apt, apt-get, aptitude, Ansible, установочный скрипт). Это сообщение вы видите чаще всего.
  • /var/lib/dpkg/lock защищает саму базу состояния пакетов. Тот, кто держит эту блокировку, прямо сейчас действительно пишет в /var/lib/dpkg/status.

Все четыре файла пустые. В них нет ни данных, ни PID, вообще ничего. Блокировка сидит не в содержимом, а в flock на открытом файловом дескрипторе. Это тот самый ключевой момент, о котором умалчивает большинство инструкций.

Почему слепое удаление может повредить базу пакетов

Раз блокировка держится на файловом дескрипторе, а не на имени файла, при удалении происходит следующее: работающий процесс сохраняет свой дескриптор и невозмутимо продолжает работу. Из каталога файл исчез, но для процесса он по-прежнему существует. Ваш второй вызов apt создаёт новый файл с тем же именем, успешно блокирует его и считает, что путь свободен.

С этого момента два процесса одновременно пишут в /var/lib/dpkg/status, параллельно распаковывают файлы в один и тот же каталог назначения и запускают триггеры друг друга. Результат бывает разным: от наполовину настроенных пакетов до базы состояния, которую dpkg уже не может прочитать. Именно об этом apt и предупреждает строкой N: Be aware that removing the lock file is not a solution and may break your system.

Удалять файл блокировки допустимо только тогда, когда доказано, что ни один процесс его больше не держит. Именно это доказательство и есть суть данной инструкции, а не сам rm.

Самый частый случай: прямо сейчас идёт автоматическое обновление

Примерно в девяти случаях из десяти на свежеустановленном сервере виновник безобиден и вполне легитимен: unattended-upgrades. В серверных и облачных образах Ubuntu автоматические обновления безопасности включены по умолчанию, а запускают их два таймера systemd:

  • apt-daily.timer запускается в 06:00 и 18:00 со случайной задержкой до двенадцати часов и обновляет списки пакетов.
  • apt-daily-upgrade.timer запускается в 06:00 со случайной задержкой до 60 минут и устанавливает обновления безопасности.

Случайная задержка и есть причина того, что ошибка возникает будто бы в совершенно произвольное время. В облачных образах к этому добавляется первый запуск: cloud-init при первой загрузке сам выполняет apt update. Кто заходит на сервер через две минуты после выдачи и сразу хочет что-то установить, почти неизбежно упирается в блокировку. Поэтому при настройке нового сервера стоит придерживаться порядка из нашего чек-листа для новых root-серверов: сначала выдохнуть, потом устанавливать.

Состояние автоматического обновления смотрят так:

systemctl list-timers 'apt-daily*'
systemctl status unattended-upgrades.service
journalctl -u apt-daily-upgrade.service --since "-2h" --no-pager
tail -n 30 /var/log/unattended-upgrades/unattended-upgrades.log

Кто держит блокировку? Диагностика через lsof и fuser

Перед любым вмешательством стоит вопрос, работает ли ещё вообще кто-нибудь. Надёжно отвечают на него два инструмента. Если их нет, они ставятся из пакетов lsof и psmisc, что, разумеется, получится только после снятия блокировки. Поэтому на боевых системах оба входят в базовый набор.

lsof /var/lib/dpkg/lock-frontend
lsof /var/lib/dpkg/lock
lsof /var/cache/apt/archives/lock
lsof /var/lib/apt/lists/lock

Типичный вывод выглядит так:

COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
unattended 1234 root    5uW  REG  254,1        0 1049 /var/lib/dpkg/lock-frontend

Буква W после номера файлового дескриптора означает: установлена блокировка на запись. Только такая запись действительно блокирует apt, просто открытый дескриптор без W ничего не блокирует. То есть здесь всё в порядке, процесс работает.

Если же вывода нет совсем, блокировку никто больше не держит. Учитывайте, что в этом нормальном случае lsof возвращает код 1, вообще без текста ошибки. То же самое делает fuser. Поэтому в скрипте с set -e или в цепочке через && диагностика обрывается именно тогда, когда результат хороший. Пишите там lsof /var/lib/dpkg/lock-frontend || true.

Важная оговорка о доказательности: пустой вывод действительно означает «блокировку никто не держит» только тогда, когда файл блокировки перед этим не удаляли. Если его удалили, пока процесс ещё держал его, этот процесс продолжает держать осиротевший inode, а по имени файла lsof уже ничего не видит. Поэтому всегда дополнительно проверяйте список процессов.

Без lsof ту же работу делает fuser:

fuser -v /var/lib/dpkg/lock-frontend

А взгляд на список процессов дополнительно показывает, как долго операция уже идёт. Колонка etimes выводит время работы в секундах, что помогает с оценкой:

ps -eo pid,ppid,etimes,stat,cmd | grep -E 'apt|dpkg|unattended' | grep -v grep

Результат читается так:

  • Время работы меньше десяти минут, статус S или R: нормальная работа. Ждать.
  • Время работы больше часа, обращения к сети, медленные зеркала: всё ещё правдоподобно. Проверьте через tail -f /var/log/apt/term.log, движется ли что-нибудь.
  • Статус D (uninterruptible sleep) на протяжении долгого времени: процесс завис на вводе-выводе. Причина обычно в заполненном или неисправном накопителе, а не в самом apt.
  • Статус T (остановлен): кто-то приостановил операцию через Ctrl+Z. Продолжить её можно командой kill -CONT PID.
  • Процесса больше нет, а блокировка осталась: вот теперь, и только теперь, удаление файла блокировки оправдано.

Частая и недооценённая причина, это заполненный раздел: dpkg обрывается посреди распаковки и оставляет ровно такое состояние. Если df -h /var показывает почти 100%, сначала прочитайте, как освободить место на диске в Linux, и только потом чините систему управления пакетами.

Правильно ждать вместо аварийного выхода: DPkg::Lock::Timeout

Начиная с apt 2.x есть опция, которая снимает значительную часть проблем в скриптах. Вместо немедленного выхода apt ждёт освобождения заданное число секунд:

apt-get -o DPkg::Lock::Timeout=60 install -y htop

Значение -1 означает неограниченное ожидание. На постоянной основе это задаётся в отдельном файле конфигурации. Отсутствующее расширение здесь не оплошность, apt читает файл и без .conf:

echo 'DPkg::Lock::Timeout "300";' > /etc/apt/apt.conf.d/99lock-timeout
apt-config dump DPkg::Lock::Timeout

Вторая строка — контрольная проверка. Она должна вывести DPkg::Lock::Timeout "300";, тогда файл действительно вступил в силу.

А теперь ограничение, которого почти нет ни в одной инструкции и которое в критический момент решает всё: опция покрывает не все четыре блокировки. Проверено на Debian 11, 12 и 13, а также на Ubuntu 22.04 и 24.04, каждый раз со сторонним процессом, который держит блокировку через fcntl:

БлокировкаЖдёт ли apt с DPkg::Lock::Timeout?
/var/lib/dpkg/lock-frontendда, ровно заданное время
/var/lib/dpkg/lockда
/var/cache/apt/archives/lockнет, выход меньше чем через секунду
/var/lib/apt/lists/lockнет, выход меньше чем через секунду

На практике это значит две вещи. Во-первых: при apt-get update опция не даёт ничего, потому что там речь о блокировке списков. Даже с DPkg::Lock::Timeout=-1 вызов сразу завершается с E: Could not get lock /var/lib/apt/lists/lock и кодом возврата 100, вместо того чтобы ждать. Во-вторых: даже при install таймаут помогает только до тех пор, пока блокирующий процесс держит frontend-блокировку. Если параллельный процесс как раз висит на загрузке и тем самым держит блокировку архива, apt тоже не ждёт ни секунды.

Поэтому для ролей Ansible, скриптов cloud-init и конвейеров развёртывания дополнительно нужен внешний цикл повторов, либо вся операция сериализуется через flock:

for i in $(seq 30); do apt-get update && break; sleep 10; done
flock /var/lib/apt/lists/lock apt-get update

На Debian 12, Debian 13, Ubuntu 22.04 и Ubuntu 24.04 опция присутствует. На очень старых системах (Debian 9, Ubuntu 16.04) apt её не знает и молча игнорирует, не выдавая ошибки.

Если процессов действительно не осталось: удаляем файл блокировки

С помощью lsof и ps вы доказали, что с системой управления пакетами больше никто не работает. Только теперь следует вмешательство. Если процесс всё же ещё работает и его нужно завершить, используйте сначала мягкий сигнал и никогда не начинайте с kill -9:

kill -TERM 1234

Сигнал SIGTERM даёт unattended-upgrades возможность корректно завершить текущий вызов dpkg. А SIGKILL посреди распаковки оставляет ровно те наполовину установленные пакеты, которые потом придётся кропотливо разгребать. После SIGTERM подождите минимум 30 секунд и проверьте ещё раз.

Если список процессов чист, удаляйте файлы блокировки:

rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock /var/lib/apt/lists/lock

При следующем вызове apt файлы создаются заново автоматически. Ни особые права, ни ручное создание не нужны. Но верно и обратное: удаление не чинит ни неверные права, ни неверного владельца, оно убирает только имя. Кто надеется таким образом что-то отремонтировать, ищет не там. И ещё бережнее, чем rm, будет просто очистить файлы, например через : > /var/lib/dpkg/lock-frontend: тогда inode сохраняется, и всё ещё работающий старый процесс остаётся виден в lsof.

После вмешательства: dpkg --configure -a

Этот шаг не опционален. Прерванная операция оставляет пакеты в состоянии «распакован, но не настроен». Тогда apt отказывается работать с сообщением:

E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem.

Команда доделывает все незавершённые шаги настройки:

dpkg --configure -a

Затем следует проверка на сломанные зависимости:

apt-get --fix-broken install -y
apt-get check

Интересная деталь для последующего разбора: в каталоге /var/lib/dpkg/updates/ лежит журнал dpkg. Если после dpkg --configure -a каталог пуст, всё отработано. Если там ещё лежат пронумерованные файлы, операция не прошла до конца.

Если всё-таки пошло не так: последствия и путь назад

Здесь другие инструкции заканчиваются. Эти сообщения появляются, когда удалили слишком рано или прибили процесс слишком жёстко:

dpkg: error processing package nginx (--configure):
 package is in a very bad inconsistent state; you should
 reinstall it before attempting configuration
Errors were encountered while processing:
 nginx
E: Sub-process /usr/bin/dpkg returned an error code (1)

Выход состоит в принудительном удалении сломанного пакета и его повторной установке. Применяйте --force-remove-reinstreq исключительно к одному затронутому пакету, никогда огульно:

dpkg --remove --force-remove-reinstreq nginx
apt-get install -y nginx

Второй вариант касается списков файлов:

dpkg: warning: files list file for package 'libssl3' missing; assuming package has no files currently installed

Это чинится переустановкой того же пакета через apt-get install --reinstall. Какие пакеты вообще находятся в нечистом состоянии, покажет:

dpkg --audit

В худшем случае повреждён сам /var/lib/dpkg/status, что видно по сообщениям вида dpkg: unrecoverable fatal error, aborting: parsing file '/var/lib/dpkg/status'. Тогда помогут две резервные копии, которые система создаёт автоматически: /var/lib/dpkg/status-old и ежедневно ротируемые копии от /var/backups/dpkg.status.0 до dpkg.status.6.gz. Скопируйте обратно более свежую из двух, прежде чем думать о переустановке системы. Обязательно сделайте перед этим резервную копию повреждённого файла.

Различия между системами

«Одного решения для всех» здесь нет, исходные условия заметно различаются:

  • Ubuntu 22.04 и 24.04: в серверных образах unattended-upgrades активен, и ошибка встречается постоянно. К этому добавляется needrestart, который после каждой установки открывает интерактивный диалог и держит операцию вместе с блокировкой открытой, пока кто-нибудь не подтвердит. Поэтому в скриптах задавайте DEBIAN_FRONTEND=noninteractive.
  • Debian 12 и Debian 13: таймеры apt-daily.timer и apt-daily-upgrade.timer здесь тоже есть, а вот обновляется ли система на самом деле автоматически, зависит от образа и от /etc/apt/apt.conf.d/20auto-upgrades. Проверять, а не предполагать.
  • Контейнеры: в образе Docker нет ни systemd, ни unattended-upgrades. Блокировка там практически всегда означает параллельные шаги сборки или закэшированный слой с оставшимся файлом блокировки. Кто регулярно собирает образы, найдёт вводную в нашей статье про Docker на Debian и Ubuntu.
  • Настольные системы: там блокировку часто держит packagekitd или графический менеджер обновлений, а не apt.
  • AlmaLinux, Rocky Linux и RHEL: там проблемы в таком виде нет, dnf использует /var/run/dnf.pid и по умолчанию ждёт, вместо того чтобы прерываться. Сообщение тогда выглядит как Waiting for process with pid ... to finish. Чем ещё отличается это семейство, показывает статья про htop в AlmaLinux, Rocky и RHEL.

Как понять, что всё снова чисто

Четыре проверки, которые вместе дают ясную картину:

dpkg --audit
apt-get check
apt-get --fix-broken install -y
apt-get update

dpkg --audit в идеале не выводит вообще ничего. apt-get check заканчивается строками о чтении списков пакетов и без ошибок. apt-get --fix-broken install сообщает 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. А apt-get update проходит без сообщения о блокировке. Дополнительно ls /var/lib/dpkg/updates/ должен показать пустой каталог, а взгляд в /var/log/dpkg.log должен подтвердить, что последние действия завершились статусом status installed, а не half-configured:

tail -n 20 /var/log/dpkg.log

Профилактика вместо ремонта

Чтобы ошибка вообще не превращалась в пожирателя времени, помогают четыре привычки:

  1. Задать таймаут и всё равно повторять. DPkg::Lock::Timeout в /etc/apt/apt.conf.d/99lock-timeout заставляет apt ждать на frontend-блокировке и на блокировке dpkg, вместо того чтобы прерываться. Так как блокировки архива и списков сюда не входят, в скриптах добавляется внешний цикл повторов. Вместе это покрывает практически все случаи.
  2. Никогда не обновляться в обычной сессии SSH. Если соединение оборвётся во время apt upgrade, dpkg прервётся посреди работы. Запускайте длительные обновления в tmux или screen. Основы описаны в статье подключение к серверу по SSH.
  3. Не нажимать Ctrl+C по ходу дела. Во время загрузки прерывание некритично, а во время распаковки и настройки оно создаёт ровно те наполовину установленные пакеты из раздела выше.
  4. Не сталкивать собственные регламентные работы с системными таймерами. Кто запускает своё обновление по расписанию, разносит его во времени и задаёт таймаут. Как настроить это аккуратно, описано в статьях про cron-задания в Linux и про собственные службы systemd.

И ещё замечание о якобы самом простом выходе: apt remove unattended-upgrades действительно устраняет конфликты блокировок, но заодно лишает вас автоматических обновлений безопасности. На сервере, доступном из интернета, это плохая сделка. Заметно разумнее сохранить автоматическое обновление, а собственные операции сделать терпеливыми.


Кратко: lsof на указанный файл блокировки, проверить список процессов, подождать. Только когда доказано, что ничего больше не работает, удалить файлы блокировки, после чего обязательно dpkg --configure -a и apt-get check. С DPkg::Lock::Timeout в конфигурации apt и циклом повторов вокруг apt-get update остальное решается само.

Частые вопросы

Можно ли просто удалить файл блокировки?
Только в том случае, если вы предварительно доказали через lsof или fuser, что его больше никто не держит. Блокировка привязана к открытому файловому дескриптору, а не к имени файла. Если удалить файл, пока процесс работает, дальше с одной и той же базой пакетов будут одновременно работать две операции, и это её повредит.
Сколько ждать, прежде чем вмешиваться?
При unattended-upgrades нормально от десяти до тридцати минут, при больших обновлениях через медленные зеркала и дольше. Проверьте через tail -f /var/log/apt/term.log, движется ли что-нибудь. Пока там появляются новые строки, операция идёт и вмешиваться не нужно.
Что означает имя процесса unattended-upgr в сообщении об ошибке?
Это автоматическое обновление безопасности, запущенное таймерами systemd apt-daily.timer и apt-daily-upgrade.timer. Имя обрезано до 15 символов. Такой процесс следует дать довести до конца, а не прерывать.
Зачем после удаления файла блокировки нужен dpkg --configure -a?
Прерванная операция оставляет пакеты в состоянии «распакован, но не настроен». Команда dpkg --configure -a доделывает эти незавершённые шаги. Без неё apt отказывается от любой дальнейшей установки с сообщением dpkg was interrupted.
Как избежать этой ошибки в скриптах и ролях Ansible?
Через apt-get -o DPkg::Lock::Timeout=300 вместо цикла ожидания по именам процессов. На постоянной основе впишите DPkg::Lock::Timeout "300"; в /etc/apt/apt.conf.d/99lock-timeout, значение -1 означает неограниченное ожидание. Важно: опция работает только для frontend-блокировки dpkg и для блокировки dpkg. На блокировке архива и на блокировке списков apt всё равно не ждёт, поэтому при apt-get update она заведомо ничего не даёт. Там нужен собственный цикл повторов, например: for i in $(seq 30); do apt-get update && break; sleep 10; done
Бывает ли эта ошибка в AlmaLinux или Rocky Linux?
В таком виде нет. dnf блокируется через /var/run/dnf.pid и по умолчанию ждёт другую операцию, вместо того чтобы прерываться. Сообщение там выглядит как Waiting for process with pid ... to finish.
После ремонта apt по-прежнему сообщает об ошибке в одном пакете, что делать?
Проверьте через dpkg --audit, какой пакет затронут, удалите именно его командой dpkg --remove --force-remove-reinstreq ПАКЕТ и затем установите заново. Никогда не применяйте эту опцию огульно ко всем пакетам.

apt dpkg Debian Ubuntu управление пакетами устранение неполадок unattended-upgrades Linux