「Could not get lock /var/lib/dpkg/lock」の解決

「Could not get lock /var/lib/dpkg/lock」の解決

「Could not get lock」とは何を意味するのか?

結論: apt / dpkg は同時に 1 つしか動けない設計で、ロックファイルで排他制御している。このエラーは他のプロセスが先にロックを握っている状態を示す。原因の大半はバックグラウンドの自動更新。

apt install などを実行したとき、次のように出て止まることがある。

$ sudo apt install nginx
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (apt)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

apt と dpkg は、パッケージデータベースを壊さないために同時に 1 つしか実行できない。この排他制御はロックファイルで実現されており、誰かが処理中の間は他のコマンドがロックを取得できず、このエラーになる。

つまりこれは「壊れた」のではなく「順番待ちで弾かれた」状態だ。多くの場合、数分待てば解消する。焦ってロックファイルを削除するのが最も事故りやすい対応で、まずは「誰がロックを握っているか」を見るのが正しい。

前提(対象環境)

  • OS: Ubuntu / Debian 系(apt / dpkg を使うディストリビューション)
  • sudo が使える前提で進める
  • いきなり rm でロックファイルを消さないこと(理由は後述)

apt が使うロックファイルはどれか?

結論: ロックは 1 つではなく 4 つある。lock-frontend がフロント全体、lock が dpkg DB、archives/lock がダウンロード、lists/lockapt update 用。エラーに出たパスでどの段階かが分かる。

apt の処理段階ごとに別々のロックファイルがある。エラーメッセージに出たパスを見れば、どの段階で詰まっているか分かる。

ロックファイル 役割 取得されるタイミング
/var/lib/dpkg/lock-frontend apt フロントエンド全体の排他 apt 操作のほぼ全体
/var/lib/dpkg/lock dpkg データベース本体 パッケージの展開・設定中
/var/cache/apt/archives/lock .deb ダウンロードキャッシュ パッケージ取得中
/var/lib/apt/lists/lock パッケージリスト apt update

新しい apt(Ubuntu 18.04 以降)は lock-frontend を最初に取得する。エラーで lock-frontend が出ているなら、別の apt / dpkg がフロント全体を握っている状態だ。

ロックファイルの中身は空で、ファイルの「存在」ではなく flock(ファイルロック)で排他している。だから「ファイルがあるから消す」という発想は誤り。ロックを握っているプロセスが終われば、ファイルが残っていても次の apt は問題なく動く。

なぜロックが取得できないのか?

結論: 9 割は「別の apt 系プロセスが動いている」。自動更新(unattended-upgrades)・GUI のソフトウェア更新・二重起動・前回の異常終了の 4 つに整理でき、自動更新が圧倒的に多い。

ロックを取得できない原因は次の 4 パターンに集約される。

原因 起きやすい状況 対処の方向
自動更新が裏で動いている 起動直後・apt-daily のタイマー発火中 待つ
GUI の更新ツール 「ソフトウェアの更新」/ packagekit が起動中 GUI を閉じる
apt の二重起動 別ターミナルで apt を実行したまま もう一方を待つ
前回の apt が異常終了 install 中にターミナルを閉じた・電源断 復旧コマンド

特に多いのが 1 番目だ。Ubuntu は apt-daily.service / apt-daily-upgrade.service というタイマーで、起動直後やランダムな時刻に裏で apt updateunattended-upgrades を走らせる。サーバを立てた直後に apt install すると、この自動更新とぶつかってロックエラーになることが非常に多い。

ロックを握っているプロセスを特定するには?

結論: まず lsoffuser でロックファイルを開いているプロセスを特定する。新しい apt はエラー本文に PID も出す。プロセスの正体(apt / unattended-upgrades 等)が分かれば対処方針が決まる。

最初にやるのは「誰がロックを握っているか」の確認だ。削除や kill はその後でいい。

新しい apt はエラーに held by process 1234 (apt) と PID を出してくれる。出ない環境では lsof で調べる。

$ sudo lsof /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
unattended 1234 root    5uW  REG    8,1        0  ... /var/lib/dpkg/lock-frontend

FD 列の W は書き込みロックを意味する。上の例では unattended-upgrades がロックを握っている。lsof が無ければ fuser でも分かる。

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

apt 系プロセスの一覧で全体像をつかむのも有効だ。

$ ps aux | grep -iE 'apt|dpkg|unattended' | grep -v grep
root  1234  ... /usr/bin/python3 /usr/bin/unattended-upgrade

ここで正体が unattended-upgradeapt-daily なら、自動更新が走っているだけなので待つのが正解。手動で起動した apt の二重実行なら、もう一方の作業を終わらせる。

自動更新が原因のときはどうするか?

結論: 自動更新(unattended-upgrades)は数分で終わるので待つのが最善kill で中断すると更新が中途半端になる。どうしても待てない場合のみ、サービスを正しく止める手順を踏む。

lsof の結果が unattended-upgrade だった場合、それは害ではなくセキュリティ更新を適用しているプロセスだ。通常 1〜5 分で完了するので、そのまま待てば自動的にロックが解放される。

進捗を確認したいなら状態を見る。

$ systemctl status unattended-upgrades
$ sudo journalctl -u unattended-upgrades -f

待っても終わらない、あるいは確実に止めたい事情があるときは、kill -9 で殺すのではなく、サービスとして正しく停止させる。

$ sudo systemctl stop unattended-upgrades

更新の途中で kill -9 を使うと、パッケージが「展開済みだが未設定」の宙ぶらりんな状態になり、後で dpkg --configure -a での復旧が必要になる。止めるなら可能な限り systemctl stop か、プロセスへの通常の kill(SIGTERM)を使う。

ロックファイルを削除してよいのはどんなときか?

結論: ロックファイルの削除は最終手段lsof で「ロックを握るプロセスが 1 つも存在しない」ことを確認できたときだけ許される。動いているプロセスがある状態で消すと dpkg データベースが壊れる。

「ロックファイルを消せば直る」という情報が出回っているが、これは動いている apt / dpkg が無いことを確認した後にのみ有効な、最後の手段だ。プロセスが生きているのに消すと、2 つの apt が同時にデータベースを書き換えてしまい、パッケージ管理が壊れる。

まず、ロックを開いているプロセスが本当に無いことを確認する。

# 何も出力されなければ、握っているプロセスは存在しない
$ sudo lsof /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock /var/lib/apt/lists/lock
$ ps aux | grep -iE 'apt|dpkg|unattended' | grep -v grep

両方とも空(apt / dpkg が一切動いていない)と確認できて初めて、残ったステイル(stale)なロックファイルを削除してよい。

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

中断した dpkg を復旧するには?

結論: ロックを解放したら sudo dpkg --configure -a を実行する。中断で「展開済みだが未設定」になったパッケージの設定を完了させるコマンドで、その後 apt update / apt -f install で整合性を取り戻す。

ロックを解放しても、前回の apt が処理の途中で止まっていた場合は、パッケージが中途半端な状態で残っていることがある。これを正常化するのが dpkg --configure -a だ。

$ sudo dpkg --configure -a

このコマンドは「展開は済んだが設定が終わっていない」パッケージをすべて設定し直す。続けて依存関係の欠けを修復し、リストを更新する。

$ sudo apt-get install -f
$ sudo apt update

apt-get install -f--fix-broken)は、依存関係が壊れたパッケージを修復する。ここまで通れば、通常どおり apt install が使えるようになる。

復旧の定番セットは次の 3 つを順に実行すること。

sudo dpkg --configure -a
sudo apt-get install -f
sudo apt update

再発を防ぐには?

結論: スクリプトや自動化では DPkg::Lock::Timeout オプションでロックを「待つ」よう設定する。即エラーで落ちる代わりに指定秒数だけリトライしてくれる。新しい apt(2.x 以降)の標準機能。

手動操作なら「自動更新が終わるまで待つ」で十分だが、CI やプロビジョニングスクリプトでは、自動更新とぶつかって失敗すると面倒だ。apt 2.x には、ロックが取れないとき即エラーにせず指定秒数だけ待つオプションがある。

# ロックが取れるまで最大 60 秒待つ
$ sudo apt-get -o DPkg::Lock::Timeout=60 install nginx
# 取れるまで無制限に待つ(-1)
$ sudo apt-get -o DPkg::Lock::Timeout=-1 install nginx

サーバ構築直後に apt install する自動化では、この DPkg::Lock::Timeout を付けておくだけで、起動直後の apt-daily とのロック競合による失敗をほぼ防げる。

やってはいけないこと

  • プロセス確認せずにロックファイルを rm
  • 更新中の apt / dpkg を kill -9
  • 同じサーバで apt を 2 つ同時に走らせる

まとめ:チェックリスト

結論: 「特定 → 待つ → 復旧」が基本の順序。ロックファイル削除はプロセスが無いと確認できたときだけの最終手段。この順番を守れば dpkg を壊さずに解決できる。

  • [ ] エラーに出た PID、または lsof でロックを握るプロセスを特定したか
  • [ ] それが unattended-upgrade / apt-daily なら、数分待ったか
  • [ ] GUI の「ソフトウェアの更新」/ packagekit が動いていないか確認したか
  • [ ] kill するなら kill -9 を避け、systemctl stop か通常の kill を使ったか
  • [ ] ロックファイルを消す前に lsofps で「無人」を確認したか
  • [ ] 中断していたなら dpkg --configure -aapt-get install -fapt update で復旧したか
  • [ ] 自動化では DPkg::Lock::Timeout を設定したか

次に読む