Ubuntu

Ubuntu18.04 E: Unable to acquire the dpkg frontend lock

本番環境のパッケージ入れ替えに関する最終のテスト段階。
VMwareに素の状態のUbuntuディスクイメージをセットし、当該パッケージを入れて、本番環境のデーターを復元したうえで、本番環境に適用するバージョンのパッケージを当ててみる、という超簡易的なもの。



広告


素の状態のUbuntuディスクイメージをセットして起動、古いパッケージを更新するか…とやって止められた。

こんなに長く書くつもりじゃなかったけど、調べてみたら色々と知っておくべきことがあった。

起動直後のアップデートに関するあれこれ

とにかくアップデートしたい

アップデートをしようとしたら止められてちょっと嫌だ。

$ sudo apt update
Hit:1 http://jp.archive.ubuntu.com/ubuntu bionic InRelease
Hit:2 http://jp.archive.ubuntu.com/ubuntu bionic-updates InRelease
Hit:3 http://jp.archive.ubuntu.com/ubuntu bionic-backports InRelease
Hit:4 http://jp.archive.ubuntu.com/ubuntu bionic-security InRelease
Reading package lists... Done
Building dependency tree
Reading state information... Done
159 packages can be upgraded. Run 'apt list --upgradable' to see them.

$ sudo apt dist-upgrade
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?

そんなときにはこれ。

$ sudo systemctl stop unattended-upgrades.service
$ sudo apt dist-upgrade
$ sudo systemctl start unattended-upgrades.service

 

アップデートの進捗が分かればいい

アップデートが今どんな状況なのか、アップデートが終わったのか、というところが分かるだけでも精神衛生的に良いという人は、このログを見ていれば良さそう。
/var/log/unattended-upgrades/unattended-upgrades-dpkg.log

最初の段階で、アップデートの対象が決まって(多分、ダウンロードもしてきている)、

$ tail -f /var/log/unattended-upgrades/unattended-upgrades.log
…
2021-05-09 01:24:12,664 INFO Initial blacklisted packages:
2021-05-09 01:24:12,665 INFO Initial whitelisted packages:
2021-05-09 01:24:12,665 INFO Starting unattended upgrades script
2021-05-09 01:24:12,665 INFO Allowed origins are: o=Ubuntu,a=bionic, o=Ubuntu,a=bionic-security, o=UbuntuESMApps,a=bioc-apps-security, o=UbuntuESM,a=bionic-infra-security
…
2021-05-09 01:27:09,158 INFO Packages that will be upgraded: accountsservice apport apt apt-utils bind9-host bsdutils sybox-initramfs busybox-static ca-certificates curl dirmngr distro-info-data dnsmasq-base dnsutils fdisk git git-man … とパッケージ名が並んで
2021-05-09 01:27:09,158 INFO Writing dpkg log to /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
…続く

アップデートが始まると、こちらにログが出力される。

$ tail -f /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
Log started: 2021-05-09  01:27:39
(Reading database ... 67032 files and directories currently installed.)
Preparing to unpack .../bsdutils_1%3a2.31.1-0.4ubuntu3.7_amd64.deb ...
Unpacking bsdutils (1:2.31.1-0.4ubuntu3.7) over (1:2.31.1-0.4ubuntu3.6) ...
Setting up bsdutils (1:2.31.1-0.4ubuntu3.7) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Log ended: 2021-05-09  01:27:42

Log started: 2021-05-09  01:27:42
(Reading database ... 67032 files and directories currently installed.)
…

アップデートが一通り終了すると、

$ tail -f /var/log/unattended-upgrades/unattended-upgrades.log
…先程の続き
2021-05-09 01:32:53,913 INFO All upgrades installed
2021-05-09 01:32:54,618 WARNING Keeping the following auto-removable package(s) because they include linux-modules-4.15.0-106-generic which package is related to the running kernel: linux-image-4.15.0-106-generic linux-modules-4.15.0-106-generic linux-modules-extra-4.15.0-106-generic
2021-05-09 01:32:54,850 WARNING Keeping the following auto-removable package(s) because they include linux-modules-extra-4.15.0-106-generic which package is related to the running kernel: linux-modules-extra-4.15.0-106-generic
2021-05-09 01:32:55,158 WARNING Keeping the following auto-removable package(s) because they include linux-headers-4.15.0-106-generic which package is related to the running kernel: linux-headers-4.15.0-106 linux-headers-4.15.0-106-generic
2021-05-09 01:32:55,466 WARNING Keeping the following auto-removable package(s) because they include linux-modules-extra-4.15.0-106-generic which package is related to the running kernel: linux-image-4.15.0-106-generic linux-modules-extra-4.15.0-106-generic
2021-05-09 01:32:55,697 WARNING Keeping the following auto-removable package(s) because they include linux-headers-4.15.0-106-generic which package is related to the running kernel: linux-headers-4.15.0-106-generic
2021-05-09 01:32:55,887 INFO Packages that were successfully auto-removed:
2021-05-09 01:32:55,887 INFO Packages that are kept back: linux-headers-4.15.0-106 linux-headers-4.15.0-106-generic linux-image-4.15.0-106-generic linux-modules-4.15.0-106-generic linux-modules-extra-4.15.0-106-generic

となっていて、auto-removeまで実行されていることが分かる。

起動時のアップデートを止める

こちらで教えてくれていることがとても合理的。
(ひ)メモ / Ubuntu 18.04 で OS 起動時の apt update と unattended-upgrade を抑制する方法

この中で書かれているコマンド

$ sudo systemctl edit apt-daily.timer
$ sudo systemctl edit apt-daily-upgrade.timer

を実行すると、エディターが空っぽの状態で開くのだけれど、これはsystemdのユニットファイルの差分を書くところだから。
ユニットファイルが更新されても効果が継続するのが良いところ。
Qiita / systemdで既存のunitを編集する2つの方法

合理的に教えてくれた書き込むべき差分は、「電源が切れていた間にタイマー起動するべき時間を経過していたら、タイマー起動する」という機能をオフにすることだった。

自動アップデートそのものを止める

やはり、こちらで教えてくれている。
(ひ)メモ / Ubuntu 18.04 で OS 起動時の apt update と unattended-upgrade を抑制する方法

もちろん教えてくれている方法でもできる訳だけれど、これらのサービスを止めてしまえば良いような気もする。

$ sudo systemctl disable apt-daily.service apt-daily.timer apt-daily-upgrade.service apt-daily-upgrade.timer

結局これらのサービスやタイマーが動かなければ何も起きないのではないかと。

復旧はたぶんこれでできるけれども、試すのに時間がかかるので、今回はパス。

$ sudo systemctl enable apt-daily.service apt-daily.timer apt-daily-upgrade.service apt-daily-upgrade.timer

 

調べたこと

古いHDDイメージで起動すると必ず発生するこの問題、いつもしばらく放っておくことで解決していた(解決とはいわないか…)。

今日はなんだか待てなくて、調べてみた。
Marginalia / E: ロック /var/lib/dpkg/lock-frontend が取得できませんでした – open (11: リソースが一時的に利用できません)
Qiita / 「E: ロック /var/lib/dpkg/lock-frontend が取得できませんでした – open (11: リソースが一時的に利用できません)」というエラーの対処法
Qiita / 大切なことはすべてUbuntuが教えてくれた 無人アップグレードを知りましょう

で、最初の無理矢理アップデートをやってみたけれども、そもそも起動時に何が起こっているのかを追いかけてみて、問題ないことを確認したかった。

放っておくとどうなるのか

起動後に放っておくと、アップデートできるものはしてしまう。

Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-106-generic x86_64)
…
163 packages can be updated.
115 updates are security updates.
New release '20.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

69 packages can be updated.
0 updates are security updates.

いくら待っても、ここから先には進まない。
結局、この中途半端な感じが「ホールドされて迷惑」と感じる理由なんだと思う。

実際には、セキュリティホールを自動的に塞いでくれているわけで、普通に使っている分には何の問題もないはずではある。

自動アップデートの仕組み(ハズレ調査)

ほとんどの場合、自動でセキュリティアップデートを掛けてくれることは良いことだろう。
で、このアップデートがどのように行われているのか、というところが気になった。

自動アップデート?とつぶやきながら、過去に書いた記事を思い出した。unattended-upgradesだ。

起動した後で確認してみたところ動いていた。タイミングによりunattended-upgradeはプロセスが2つに増えていたりしていた。

$ ps aux | grep unattended
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root        980  0.0  0.5 185952 20240 ?        Ssl  10:20   0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
root       2163  0.0  2.0 184052 82528 ?        R    10:22   0:00 /usr/bin/python3 /usr/bin/unattended-upgrade
rohhie     2172  0.0  0.0  13136  1008 pts/0    S+   10:22   0:00 grep --color=auto unattended

サービスを確認してみたところ、unattended-upgrade-shutdownとつながった。

$ systemctl status unattended-upgrades.service
● unattended-upgrades.service - Unattended Upgrades Shutdown
   Loaded: loaded (/lib/systemd/system/unattended-upgrades.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2021-04-18 10:07:00 UTC; 2s ago
     Docs: man:unattended-upgrade(8)
 Main PID: 64574 (unattended-upgr)
    Tasks: 2 (limit: 4632)
   CGroup: /system.slice/unattended-upgrades.service
           mq64574 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal

中身を見てみる。

$ locate unattended-upgrades.service
/etc/systemd/system/multi-user.target.wants/unattended-upgrades.service (1)サービス定義(2)へのシンボリックリンク
/lib/systemd/system/unattended-upgrades.service (2)サービス定義の実態
/var/lib/systemd/deb-systemd-helper-enabled/unattended-upgrades.service.dsh-also (3)中に(1)のフルパスファイル名が書いてある
/var/lib/systemd/deb-systemd-helper-enabled/multi-user.target.wants/unattended-upgrades.service (4)空ファイル

(4)は空っぽなので放っておくとして、(3)。deb-systemd-helperっていうのが、マニュアルによればこれ。

deb-systemd-helperは、systemctlからのenable、disable、is-enabled、およびreenableコマンドを再実装するDebian固有のヘルパースクリプトです。
「有効化」アクションは1回だけ実行されます(最初にパッケージをインストールするとき)。最初の「有効化」で、状態ファイルが作成され、「パージ」時に削除されます。
「マスク」アクションは、サービスが以前に有効化/無効化されたかどうかの状態を保持し、「マスク解除」でその状態に適切に戻ります。

ubuntu manuals

これはsystemctlコマンドでenableとかmaskとかを使うときに働くもので、設定済みの今の動作には直接影響しない。

じゃあ、(2)はどうか。

/lib/systemd/system/unattended-upgrades.service

[Unit]
Description=Unattended Upgrades Shutdown
After=network.target local-fs.target systemd-logind.service
RequiresMountsFor=/var/log /var/run /var/lib /boot
Documentation=man:unattended-upgrade(8)

[Service]
ExecStart=/usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
KillMode=process
TimeoutStopSec=1800

[Install]
WantedBy=multi-user.target

サービスを定義するユニットファイルだ。常に起動していることを想定しているのか、reloadとかrestartとかstopの定義はない。
でも、systemctl stop で止まる。シグナルに応答するのかな。

で、Documentationはunattended-upgrade(8)ですか。

このプログラムは、構成されたAPTソースからのパッケージのみをインストールするように注意し、構成ファイルの変更に関するdpkgプロンプトをチェックして、セキュリティアップグレードを自動的に無人でダウンロードしてインストールできます。 すべての出力は/var/log/unattended-upgrades/*.logに記録されます。

このスクリプトは、APT :: Periodic :: Unattended-Upgradeオプションのバックエンドであり、cronから(たとえば、/ etc / cron.daily / aptを介して)実行するように設計されています。

ubuntu manuals

unattended-upgrade-shutdownについてはよく分からないので、スクリプトの最初に書いてあることを翻訳してみると、こんな感じ。

unattended-upgrade-shutdown-無人アップグレードが進行中であるかどうかをチェックし、存在するまで待機するヘルパー

このファイルは無人アップグレードの一部です
無人アップグレードは自由ソフトウェアです。 Free SoftwareFoundationによって公開されているGNUGeneral Public Licenseの条件の下で、再配布および/または変更することができます。 ライセンスのバージョン2、または(オプションで)それ以降のバージョン。
無人アップグレードは、それが役立つことを期待して配布されますが、いかなる保証もありません。 商品性または特定目的への適合性の黙示の保証もありません。 詳細については、GNU General PublicLicenseを参照してください。
あなたは無人アップグレードと一緒にGNUGeneral PublicLicenseのコピーを受け取っているはずです。 そうでない場合は、Free Software Foundation、Inc.、59 Temple Place、Suite 330、Boston、MA 02111-1307USAに連絡してください。

/usr/share/unattended-upgrades/unattended-upgrade-shutdown

Pythonで書かれたこのスクリプト、サイズは小さいので読む人が読めば分かるのだろうけれども…
SIGTERM または SIGHUP を受信、実行中の場合のみのunattended-upgradesを停止する。ぐらいの話?
さらっとソースを眺めた感じは、とにかく無限ループしようとしていて、シグナルを受け取ったらログを出力して、また自分を実行?って雰囲気。

かろうじてログが出力される先を見つけたので開いてみた。

/var/log/unattended-upgrades/unattended-upgrades-shutdown.log

2020-06-23 11:32:54,977 WARNING - SIGTERM or SIGHUP received, stopping unattended-upgradesonly if it is running
2020-06-23 11:38:25,409 WARNING - SIGTERM or SIGHUP received, stopping unattended-upgradesonly if it is running

んー、でもそうだとしたら、unattended-upgradesをキックしているのは誰?

自動アップデートの仕組み

ここまで来たところで、改めてどうやって起動しているかを探してみたところ、一発で回答を発見。
背景知識がないとまったく理解できないのが痛い…きっと何度も検索結果に出ていたであろうけれども、ようやくこれなのか、と受け取ることができるという。
(ひ)メモ / Ubuntu 18.04 で OS 起動時の apt update と unattended-upgrade を抑制する方法

aptという名前で登録されているタイマーとサービスが幾つか。

$ systemctl status apt-*
● apt-daily-upgrade.timer - Daily apt upgrade and clean activities
   Loaded: loaded (/lib/systemd/system/apt-daily-upgrade.timer; enabled; vendor preset: enabled)
   Active: active (waiting) since Sat 2021-05-08 10:28:26 UTC; 3h 17min ago
  Trigger: Sun 2021-05-09 06:12:18 UTC; 16h left

● apt-daily.timer - Daily apt download activities
   Loaded: loaded (/lib/systemd/system/apt-daily.timer; enabled; vendor preset: enabled)
   Active: active (waiting) since Sat 2021-05-08 10:28:26 UTC; 3h 17min ago
  Trigger: Sat 2021-05-08 23:12:24 UTC; 9h left

$ systemctl status apt-daily.service
● apt-daily.service - Daily apt download activities
   Loaded: loaded (/lib/systemd/system/apt-daily.service; static; vendor preset: enabled)
   Active: inactive (dead) since Sun 2021-05-09 01:25:57 UTC; 54min ago
     Docs: man:apt(8)
 Main PID: 1217 (code=exited, status=0/SUCCESS)

$ systemctl status apt-daily-upgrade.service
● apt-daily-upgrade.service - Daily apt upgrade and clean activities
   Loaded: loaded (/lib/systemd/system/apt-daily-upgrade.service; static; vendor preset: enabled)
   Active: inactive (dead) since Sun 2021-05-09 01:32:55 UTC; 48min ago
     Docs: man:apt(8)
  Process: 2006 ExecStart=/usr/lib/apt/apt.systemd.daily install (code=exited, status=0/SUCCESS)
 Main PID: 2006 (code=exited, status=0/SUCCESS)

そして、Unitファイルのこんな見方があるんですね。

$ systemctl cat apt-daily.timer
# /lib/systemd/system/apt-daily.timer
[Unit]
Description=Daily apt download activities

[Timer]
OnCalendar=*-*-* 6,18:00
RandomizedDelaySec=12h
Persistent=true

[Install]
WantedBy=timers.target

※同じように apt-daily-upgrade.timer の中を見ることができる。

で、この中でOnCalendarとPersistent=trueの指定が肝で、

システムの電源が切られていたなどの理由で、最後の起動時間を過ぎていた場合、すぐに実行されます(Persistent=true オプション)。

ArchLinux / systemd/タイマー

とのこと。

このタイミングで実行されるのが…

$ systemctl cat apt-daily
# /lib/systemd/system/apt-daily.service
[Unit]
Description=Daily apt download activities
Documentation=man:apt(8)
ConditionACPower=true
After=network.target network-online.target systemd-networkd.service NetworkManager.service connman.service

[Service]
Type=oneshot
ExecStartPre=-/usr/lib/apt/apt-helper wait-online
ExecStart=/usr/lib/apt/apt.systemd.daily update

※同様に apt-systemd.daily install も実行される。

で、このユニットファイルに定義されている apt.systemd.daily が起動することになっているようだ。
ちゃんと読んでいないけれど apt.systemd.dailyはパラメーターがupdateだとファイルのダウンロード、installだとアップデートが行われるっぽくて、それらは /etc/apt/apt.conf.d/10periodic の設定に従って動作する。

実際には、10periodicの後に20auto-upgradeが評価されるので、10の値は20で上書きされ、その値に従って動作することになる。

こういう流れでアップデートが行われていたのだった。

アップデートが69個残った理由

放っておいたところ、うちの環境ではこの日69個のアップデートが取り残された。

/etc/apt/apt.conf.d/50unattended-upgrades

…
nattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        // Extended Security Maintenance; doesn't necessarily exist for
        // every release and this system may not have it installed, but if
        // available, the policy for updates is such that unattended-upgrades
        // should also install from here by default.
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};
…

これでいくと、セキュリティアップデートはインストールするけれど、そうじゃないアップデートはしない、という設定に見える。
セキュリティアップデートのなかったパッケージが69個あるということなのだろう。

最初に書いたとにかくアップデートしたい操作が恐らく問題ないであろう理由

自動アップデートが行われている最中にサービスを止めると、自動アップデートが止まる。
止めても問題がなさそうなのは以下の理屈。

/etc/apt/apt.conf.d/50unattended-upgrades

…
// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGTERM. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "false";
…

このファイルにデフォルト値が書かれていないが、Githubにデフォルト値が書かれている。
Github / mvo5 / unattended-upgrades

実際にログを見てみると、1つ1つアップデートを行っているように見える。
/var/log/unattended-upgrades/unattended-upgrades-dpkg.log

これがtrueであってもfalseであっても、Unattended-Upgradeの実行中にrebootやshutdownが行われることを想定しての設定値であって、どちらでも問題なく動作するように作られているはずだ
(はず、は当てが外れるというのは適当なプログラムを自作した場合のあるあるだけど、これが上手く動かなかったら割と世界的な規模で阿鼻叫喚だろう)。
デフォルトの設定だと、インストールされたものはそのまま残るよ、というだけの話なのだろう。

以上のことから、恐らく問題はないと考えている。

Message of the day(motd)

ついでに/etc/update-motd.d/をのぞいてみたところ、92-unattended-upgrades というスクリプトが見つかった。
開けてみたところ、/usr/share/unattended-upgrades/update-motd-unattended-upgrades を実行している。

update-motd-unattended-upgrades は、/var/lib/unattended-upgrades/kept-back があれば、単語数を調べてメッセージを表示する。

NN updates could not be installed automatically. For more details,
see /var/log/unattended-upgrades/unattended-upgrades.log

自動アップデートできないものがあれば、ここで教えてくれるのだろう。

日頃、90-updates-available が表示してくれる

69 packages can be updated.
0 updates are security updates.

や、91-release-upgrade が表示してくれる

New release '20.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

はよく目にするけれど、あまり見ないメッセージかもしれない。

いずれにしても、92-unattended-upgrades は自動アップデートをする仕組みではなく、アップデートの結果で問題があれば表示してくれるスクリプトであった。

さいごに

こんなに長く書くつもりではなかった。なかったが、ちゃんと理解しようと思って調べ始めたところ、奥が深くてこんな結果になった。
スクリプトの中まで見ているわけではないけれど、どういう仕組みなのかは分かったと思う。

Systemdにタイマーという考え方があったり、systemctl edit や systemctl cat といったユニットのコントロールに有益なものがあることを初めて知ったりして。
過去記事が恥ずかしくなったりするが、気付いたところから直していこう、そうしよう。

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他