dpkgはグラフを解かない
一言でいうと
aptは何をインストールするかを決める道具で、dpkgは決まったものをインストールする道具です。この分業を知ると、dpkg -iがなぜ依存関係のエラーで止まるのかがすぐにわかります。
なぜ必要なのか
.debファイルを1つ取得してdpkg -iでインストールすると、次のようなメッセージが出ます。
dpkg: dependency problems prevent configuration of labhub-extra:
labhub-extra depends on labhub-tool (>= 1.2.0); however:
Package labhub-tool is not installed.
dpkgはリポジトリを知りません。どこから何を取ってくるべきかも知りません。ただ与えられたファイルを展開し、依存が満たされなければ「設定されていない」状態のまま残すだけです。そのため、apt-get -f install(fix broken)が対として存在します。これは「dpkgが残した未解決の状態を、aptがリポジトリを見て解決しなさい」という意味です。
どう動くのか
.debファイルは、実はarアーカイブです。中に3つの部品が入っています。
| 部品 | 内容 |
|---|---|
debian-binary |
形式のバージョン(通常は2.0) |
control.tar.* |
controlファイルとメンテナースクリプト(preinst/postinst/prerm/postrm)、conffiles、md5sums |
data.tar.* |
実際にファイルシステムへ展開されるファイル |
インストールはunpack → configureの2段階です。unpackはdataを展開することで、configureはpostinstを実行して、サービスを登録するなどの仕上げをすることです。dpkg -lの出力の最初の2文字が、この状態を表します。
| 表示 | 意味 |
|---|---|
ii |
インストール要求 + インストール完了(正常) |
iU |
インストール要求 + unpackだけ完了(configure失敗) |
rc |
削除要求 + 設定ファイルだけ残っている |
pn |
未インストール(purge済み) |
rc状態を見落としてしまうことがよくあります。「消したのに、なぜ設定が残っているのか」の答えがここにあります。
dpkgの照会コマンドは3方向です。
dpkg -l # 무엇이 설치돼 있나
dpkg -L coreutils # 이 패키지가 어떤 파일을 깔았나
dpkg -S /usr/bin/ls # 이 파일은 누가 깔았나
dpkg -s coreutils # 이 패키지의 메타데이터는 무엇인가
dpkg-query -W -f='${Package} ${Version}\n'
3つ目(-S)が、実戦で最もよく使われます。見知らぬサーバーで正体不明のバイナリに出会ったとき、それがパッケージが入れたものなのか、人が手で置いたものなのかを、1秒で見分けられます。dpkg -Sが何も見つけられなければ、そのファイルはパッケージ管理の外にあり、そうしたファイルはアップグレードのときに消えることはなく、バックアップにも含まれにくいものです。
現場での姿
設定ファイルの衝突。アップグレード中に、Configuration file '/etc/foo.conf' ... What would you like to do?というプロンプトが表示されます。dpkgはconffilesに登録されたファイルのmd5を記憶しているので、人が変更したかどうかがわかります。このプロンプトで何気なく「package maintainer's version」を選ぶと、手で入れたチューニングがまるごと消えます。自動化スクリプトでは、-o Dpkg::Options::="--force-confold"でポリシーを明示する必要があります。
設定ファイルは特別に扱われる
.deb内のconffilesに書かれたファイルは、ほかとは違う規則を受けます。この規則を知らないと、更新後に設定が消えたとか、逆に新しい設定が入らなかったという状況に出会い、どちらも原因は同じです。
dpkgは更新時に、3つを比較します。パッケージが最初に入れた内容、今ディスクにある内容、そして新しいパッケージが入れようとしている内容です。
- 自分で変更していなければ、静かに新しいものに置き換えます。
- 自分で変更していても、新しいものと同じなら何も起きません。
- 自分で変更していて、新しいものとも違う場合は尋ねます。対話式でなければ、デフォルトの動作に従って自分のものを残し、新しいファイルを
.dpkg-distとして横に置きます。
3つ目が問題の箇所です。自動化された更新では、誰もその質問を見ないので、新しいバージョンが要求する設定項目が自分のファイルにないまま、サービスが動きます。静かにデフォルト値で動き続け、あとで奇妙な症状として現れます。そのため、更新後に.dpkg-dist・.dpkg-new・.ucf-distができていないかを確認する手順が必要です。
rc状態と設定ファイルの関係も、ここで説明できます。先ほど見たとおり、削除しても設定が残る理由は、removeがconffilesに触れないからで、purgeがそれまで削除します。そのため、同じパッケージを入れ直すと古い設定が復活し、「きれいに入れ直したのに同じ問題が起きる」はここから来ます。
最後に、設定ファイルをパッケージの外で管理するつもりなら、最初からconffilesにない別のファイルにしておくほうがよいです。ほとんどのパッケージがconf.d/のようなディレクトリを用意しているのは、このためです。その中のファイルはパッケージの所有ではないので、更新が触れず、3方向の比較そのものが起こりません。
次のラボですること
dpkg -L/-S/-sでシステムを照会し、フィクスチャディレクトリで自分で.debをビルドしてインストールまで行います。パッケージを作ってみると、その中に何があるのかがはっきりとわかります。