なぜパッケージマネージャが生まれたのか
一言でいうと
パッケージマネージャーは、ファイルを展開する道具ではなく、「何が何を必要とするか」というグラフを解く道具です。
なぜ必要なのか
ソフトウェアをtarballで配布していた時代のインストールは、こうでした。圧縮を展開し、./configureを実行し、ないと言われたライブラリを1つずつ探してインストールし、そのライブラリがまた別のものを要求すれば、再び探しに行きます。これを「依存関係地獄」と呼びました。
問題の本質は、ファイルを運ぶことが難しいのではなく、何を先に運ぶべきかを誰も知らないことでした。そこでパッケージ形式は、ファイルの束にメタデータを付けました。このパッケージは何を提供するか(Provides)、何を要求するか(Depends)、何と衝突するか(Conflicts)。これでインストールはファイルコピーの問題ではなく、グラフの問題になり、グラフの問題は、コンピューターのほうが人間よりうまく解きます。
どう動くのか
debとrpmの細部は違いますが、骨格は同じです。
| 概念 | 何か | Debian表記 | RPM表記 |
|---|---|---|---|
| 名前・バージョン | パッケージを識別 | Package, Version |
Name, Version, Release |
| 必須の依存 | なければ使えない | Depends |
Requires |
| 弱い依存 | あれば良い | Recommends, Suggests |
Recommends, Suggests |
| 提供 | 仮想名を満たす | Provides |
Provides |
| 衝突 | 共存できない | Conflicts, Breaks |
Conflicts |
| アーキテクチャ | どのCPU向けか | amd64 / all |
x86_64 / noarch |
ここで最もよくつまずくのが、次の3つです。
第一に、依存関係の単位がパッケージ名とは限りません。RPM側で特にそうです。Requires: libnl-3.so.200()(64bit)のように、共有ライブラリのsonameがそのまま依存先になります。そのため「パッケージを1つだけ取ってくればよいのでは」という依頼が、エアギャップ環境では半日がかりの作業になります。
第二に、仮想パッケージ(Provides)があります。mail-transport-agentを要求すると、postfixもexim4もその要求を満たします。そのため「この名前のパッケージがリポジトリにないのに、なぜインストールできるのか」のような状況が生まれます。
第三に、バージョン比較の規則が直感と違います。Debianでは1.0~rc1が1.0より小さくなります(チルダはどの文字よりも小さい)。RPMにはepochがあるので、1:1.0が2.0より大きくなります。そしてepochはファイル名に現れません。静かで致命的な違いです。
現場での姿
エアギャップ環境への持ち込み依頼が、「rpmファイルを1つだけ持ってきてください」という形で来ることがよくあります。持ち込んで入れると、nothing provides libnl-3.so.200()(64bit) needed by htopのようなエラーが出ます。再び外に出てそれを取ってくると、また別のものがないと言われます。USBを3–4回往復すると半日が過ぎていて、持ち込みの審査は1日に1回しかありません。
だから熟練者は、最初からグラフを丸ごと解いた結果を持っていきます。その計算をどこで行うかが、このコースの後半のテーマです。
パッケージマネージャーがしないこと
パッケージマネージャーはファイルを置いて依存関係を解きますが、その後のことはほとんどしません。この境界を知らないと、「インストールしたのになぜ動かないのか」が繰り返されます。
設定ファイルは上書きされません。パッケージの更新時に、自分で変更した設定ファイルがあると、マネージャーは上書きする代わりに確認を求めるか、新しいファイルを.dpkg-dist・.rpmnewのような名前で横に置いておきます。そのため、更新後にこうしたファイルが溜まっていないか確認する手順が必要です。新しいバージョンが要求する設定項目があっても、自分のファイルにはないので、静かにデフォルト値で動き続け、あとで問題になります。
サービスを再起動してくれるかどうかは、ディストリビューションによって違います。あるディストリビューションは更新後に自動で再起動し、別のものは再起動しません。自動で行うほうは、予期しない瞬間にサービスが切れることがあり、行わないほうは、古いコードが動き続けたままになります。どちらなのかを知り、それに合った手順を用意することであって、デフォルトの動作を信じて済ませるべきことではありません。
インストールしていないものは消してくれません。パッケージを削除しても、それが生み出したログ・データディレクトリ・ユーザーアカウントはたいてい残ります。Debian系でremoveとpurgeが分かれているのが、この違いです。残るものがあるという事実自体は安全装置ですが、削除したと思い込んでいると、あとで同じパッケージを入れ直したときに古い設定が復活して、混乱を招きます。
言語別のパッケージマネージャーとは、互いを知りません。システムパッケージで入れたPythonライブラリとpipで入れたものが混ざると、どちらが使われるか予測しにくくなり、システムの更新がアプリケーションを壊します。そのため、アプリケーションの依存関係は仮想環境やコンテナで分離し、システムのパッケージマネージャーにはシステムのものだけを扱わせるのが原則です。
次にすること
aptの実践的な操作へ進みます。検索・インストール・削除は始まりにすぎず、holdとpinでバージョンを固定する方法まで身につけます。