TT Lab
はじめる
学ぶ 学習パス コース

パッケージ管理

dpkgはグラフを解かない

TT Labで続きを見る

一言でいうと

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つを比較します。パッケージが最初に入れた内容、今ディスクにある内容、そして新しいパッケージが入れようとしている内容です。

3つ目が問題の箇所です。自動化された更新では、誰もその質問を見ないので、新しいバージョンが要求する設定項目が自分のファイルにないまま、サービスが動きます。静かにデフォルト値で動き続け、あとで奇妙な症状として現れます。そのため、更新後に.dpkg-dist・.dpkg-new・.ucf-distができていないかを確認する手順が必要です。

rc状態と設定ファイルの関係も、ここで説明できます。先ほど見たとおり、削除しても設定が残る理由は、removeがconffilesに触れないからで、purgeがそれまで削除します。そのため、同じパッケージを入れ直すと古い設定が復活し、「きれいに入れ直したのに同じ問題が起きる」はここから来ます。

最後に、設定ファイルをパッケージの外で管理するつもりなら、最初からconffilesにない別のファイルにしておくほうがよいです。ほとんどのパッケージがconf.d/のようなディレクトリを用意しているのは、このためです。その中のファイルはパッケージの所有ではないので、更新が触れず、3方向の比較そのものが起こりません。

次のラボですること

dpkg -L/-S/-sでシステムを照会し、フィクスチャディレクトリで自分で.debをビルドしてインストールまで行います。パッケージを作ってみると、その中に何があるのかがはっきりとわかります。