Debian系ディストリビューションでパッケージの自動更新を行う方法の一つとしてUnattended Upgradesが知られています。
- UnattendedUpgrades - Debian Wiki
- AutomaticSecurityUpdates - Community Help Wiki (Ubuntu Documentation)
パッケージの更新 (特にセキュリティパッチの適用) を迅速かつ確実に行うために、利用しているサーバ管理者の方も多いのではないかと思います。
一方で、パッケージの性質や運用形態によっては、自動更新ではなく管理者が能動的に更新を行いたいケースもあります。特に、自動更新を基本としながらも特定のパッケージのみ管理者が手動で更新を行いたいという場合1に、ここで説明するブラックリスト設定が有用です。
本記事では、Unattended Upgradesで特定のパッケージの自動更新を抑制するためのブラックリスト設定について説明し、いくつかの有用な設定パターンを紹介します。
※本記事で紹介する設定方法等はUbuntu 22.04/24.04で確認を行いました
Unattended Upgradesの基本
最初にUnattended Upgradesの基本的な事柄を概説します。
公式ドキュメント
-
README: Unattended Upgradesを導入したサーバ上に見つかります (
/usr/share/doc/unattended-upgrades/README.md.gz
を解凍)。マニュアルとしてはこれが最も詳細で正確です -
man page:
man
コマンドで確認。あまり細かい情報はありません - 各種Wiki: 冒頭で紹介したDebian Wikiなど
-
設定ファイル (
50unattended-upgrades
) のコメント文: 詳細は後述しますが、コメント文に具体的な設定方法が細かく説明されており、実運用上は非常に有用です
基本的な使い方
インストール
$ sudo apt install unattended-upgrades
自動更新の有効化
設定変更:
$ sudo dpkg-reconfigure -plow unattended-upgrades
設定確認:
$ apt-config dump APT::Periodic
APT::Periodic "";
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "0";
APT::Periodic::AutocleanInterval "0";
APT::Periodic::Unattended-Upgrade "1";
⇒ APT::Periodic::Unattended-Upgrade
, APT::Periodic::Update-Package-Lists
が "1"
になっていればよい
設定変更
Unattended Upgradeでは、設定によりアップデート対象とするパッケージの指定などを行えます。
初期設定は/etc/apt/apt.conf.d/50unattended-upgrades
で確認できます。
$ cat /etc/apt/apt.conf.d/50unattended-upgrades
// Automatically upgrade packages from these (origin:archive) pairs
//
// Note that in Ubuntu security updates may pull in new dependencies
// from non-security sources (e.g. chromium). By allowing the release
// pocket these get automatically pulled in.
Unattended-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";
};
(以下略)
ご覧のとおり、50unattended-upgrades
には各設定の意味や使い方がコメント文として詳細に説明されています。パッケージの正確な仕様についてはREADMEを参照するべきですが、実運用上はこれらのコメント文を見れば十分なことが多いです。
例:
-
Unattended-Upgrade::Allowed-Origins
: 自動更新の対象とするリポジトリを設定 -
Unattended-Upgrade::Package-Blacklist
: 自動更新対象から除外するパッケージ (ブラックリスト) を設定
設定を変更 (オーバーライド) する際は、別ファイルを作成して設定内容を記述します。以下では、52unattended-upgrades-local
というファイルを作成してUnattended-Upgrade::Package-Blacklist
の設定のオーバーライドを行っています (ファイル名はこのとおりにする必要はありませんが、先頭の52
はデフォルトの設定ファイルの50
よりも後の番号にする必要があります。詳しくは補足に)。
$ sudo vi /etc/apt/apt.conf.d/52unattended-upgrades-local
Unattended-Upgrade::Package-Blacklist {
"openjdk-";
".*amazon(-)?corretto";
};
自動更新の除外設定 (ブラックリスト) について
上記の例にあるように、Unattended-Upgrade::Package-Blacklist
で特定のパッケージを自動更新対象から外す設定ができます。
設定方法
50unattended-upgrades
のコメント文に以下の説明があります。
$ cat /etc/apt/apt.conf.d/50unattended-upgrades | awk 'FNR==20,FNR==40'
// Python regular expressions, matching packages to exclude from upgrading
Unattended-Upgrade::Package-Blacklist {
// The following matches all packages starting with linux-
// "linux-";
// Use $ to explicitely define the end of a package name. Without
// the $, "libc6" would match all of them.
// "libc6$";
// "libc6-dev$";
// "libc6-i686$";
// Special characters need escaping
// "libstdc\+\+6$";
// The following matches packages like xen-system-amd64, xen-utils-4.1,
// xenstore-utils and libxenstore3.0
// "(lib)?xen(store)?";
// For more information about Python regular expressions, see
// https://docs.python.org/3/howto/regex.html
};
要点:
- 自動更新対象から除外するパッケージ名の先頭の文字列を指定する (前方一致)
- Pythonの正規表現を利用できる (そのため、パッケージ名が正規表現の特殊文字を含む場合はエスケープが必要)
よく使う設定パターン
例1: OpenJDKのパッケージをすべて除外
openjdk-17-jdk
, openjdk-21-jdk
, openjdk-21-jre-zero
など、OpenJDK系のパッケージをバージョン等の差異も含めて一括でブラックリストに追加したい場合。
⇒ 以下のように記述すれば、"openjdk-"で始まるパッケージすべてが除外対象となります。
Unattended-Upgrade::Package-Blacklist {
"openjdk-";
};
例2: Amazon Correttoのパッケージをすべて除外
同様に、java-17-amazon-corretto-jdk
, java-21-amazon-corretto-jdk
, java-21-amazon-corretto-jre
等をブラックリストに追加したい場合。
⇒ Amazon Correttoのパッケージ名は"amazon-corretto"を含んでいるようなので、"(任意の文字列)amazon-corretto"で始まるパッケージを除外すればよさそうです。
Unattended-Upgrade::Package-Blacklist {
".*amazon-corretto";
};
上記の設定でおそらく必要十分だと思いますが、念のためamazonとcorrettoの間のハイフンが無くてもマッチするようにしてもよいでしょう。
Unattended-Upgrade::Package-Blacklist {
".*amazon(-)?corretto";
};
例3: 複数のパターンの指定
ブラックリスト設定は複数のパターンを併記することができ、いずれかのパターンにマッチすれば除外対象となります。
以下は、例1と例2を組み合わせてOpenJDKとAmazon Correttoの両方を除外対象としています。
Unattended-Upgrade::Package-Blacklist {
"openjdk-";
".*amazon(-)?corretto";
};
注: パッケージ名を完全一致で指定するには
完全一致で指定したい場合は少し注意が必要です。50unattended-upgrades
のコメント文に書かれている例を基に説明します。
ここでは、パッケージlibc6
のみを除外対象に追加します。そのためには下記のように、末尾を示す$
を付ける必要があります。
Unattended-Upgrade::Package-Blacklist {
"libc6$";
};
一方、下記の設定では期待どおりの動作となりません。
Unattended-Upgrade::Package-Blacklist {
"libc6";
};
$
を付けない場合、"libc6"で始まるすべてのパッケージが対象となってしまいます (libc6-dev-i386, libc6-dev-amd64-crossなど)。先に述べたとおり、ブラックリストに指定する文字列はパッケージ名の前方一致条件であることを押さえておきましょう。
終わりに
Unattended Upgradesのブラックリストについて、基本的な設定方法と役立ちそうな設定パターンについてまとめました。
ドキュメントを読めば理解できる話ではありますが、READMEが少々閲覧しにくい形で存在しているということもあり、ナレッジとして残すことにしました。
最後までお読みいただきありがとうございました。
補足
設定のオーバーライド時に別ファイルを作成する理由
上述のとおり、Unattended Upgradesの設定をオーバーライドする際は、52unattended-upgrades-local
などの別ファイルを作成して設定内容を記述します。
実は単に設定を変えるだけなら、50unattended-upgrades
を直接書き換えることでも実現できます。しかし、このファイルはUnattended Upgradesのパッケージの一部として提供されるものであるため、直接編集した場合に不都合が起きる可能性があります。具体的には、Unattended Upgrades自体のアップデートにより出荷物の50unattended-upgrades
が変更された際、ローカルで行った変更と出荷物の変更が競合するため、運用者がマニュアルでコンフリクトを解消する必要が生じます。これを避けるために、50unattended-upgrades
を直接書き換えるのではなく別ファイルを作成することが推奨されています。
ファイル名の頭に付いている番号 (50
や52
) は設定が解析される順序を示しており、後に解析された設定が優先されます。例えば、50unattended-upgrades
, 52unattended-upgrades-local
, 53unattended-upgrades-extra
の設定がそれぞれ
Unattended-Upgrade::Package-Blacklist {};
Unattended-Upgrade::Package-Blacklist {
"openjdk-";
};
Unattended-Upgrade::Package-Blacklist {};
となっていた場合、最後に解析される53unattended-upgrades-extra
の設定が有効となります (ブラックリストは空となる)。また、番号の後ろは任意のファイル名をつけることができます (52hoge
などでも動作する)。ただし運用を考えるなら、意図の伝わる名前をつけておくべきでしょう。
※Unattended Upgradeに限らず多くのLinuxパッケージが同様の仕組みを備えており、サーバ運用者にとっては必須の知識と言えます。
holdとの違い
Unattended Upgradesのブラックリストと似た機能であるapt-mark hold
との違いについて補足します。
holdは特定のパッケージのバージョンを固定したい場合に利用します。holdにマークされたパッケージは、apt upgrade
やaptitude safe-upgrade
などを実行しても更新されません。一方、Unattended Upgradesのブラックリストは単にUnattended Upgradesの対象から外すだけですので、apt
やaptitude
による更新は通常どおりに可能です。
パッケージのバージョンを完全に固定したい場合はhold、意図せず更新されることを防ぎたい場合はUnattended Upgradesのブラックリストを利用するように使い分けるとよいでしょう。
-
特定のパッケージの自動更新を抑制したいケースの一例としてSpawn helper における segmentation fault への対処の一事例 (Failed to exec spawn helper)を先日投稿しましたので、よろしければ合わせてご覧ください。この事例では、Ubuntu上で稼働するJenkinsで発生したトラブルを解消するために、OpenJDKパッケージの自動更新を抑制するようにしました ↩