aptは何を見て判断するのか
一言でいうと
aptのあらゆる判断は、ローカルにキャッシュされたリポジトリのインデックスから出てきます。インデックスが古ければ、aptは古い世界を見ます。
なぜ必要なのか
apt-get install nginxを実行したのに、「パッケージが見つかりません」と表示されます。リポジトリには確かにあります。このとき、十中八九の原因はapt-get updateをしていないことです。
aptはインストール時にリポジトリへ問い合わせません。/var/lib/apt/lists/に取得済みのインデックスファイルだけを見て依存関係を計算し、計算が終わったあとで初めて実際の.debをダウンロードします。この分離がaptを速くしますが、同時に「リポジトリにはあるのに見えない」の原因にもなります。
どう動くのか
1回のインストールは4つの段階です。
- インデックスの読み込み:
/etc/apt/sources.listとsources.list.d/*.listに書かれたリポジトリのPackagesファイルを読みます。 - 候補の選定: 同じパッケージが複数のリポジトリにある場合は、ピンの優先度(priority)で選びます。
apt-cache policy <패키지>が、この判断結果をそのまま表示します(プレースホルダーはパッケージ名です)。 - 依存関係の解決: DependsとRecommendsをたどりながら、インストールするセットを作ります。
- ダウンロードとunpack/configure: dpkgに引き渡します。
apt-cache policyの出力の読み方が核心です。
nginx:
Installed: (none)
Candidate: 1.24.0-2ubuntu7
Version table:
1.24.0-2ubuntu7 500
500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
左の数字がバージョン、右の数字が優先度です。デフォルトは500で、ここに手を加える方法が2つあります。
- hold(
apt-mark hold): 「このパッケージには触れない」という指定です。dpkgレベルの印なので、アップグレードから丸ごと除外されます。戻すにはapt-mark unholdを使います。 - pin(
/etc/apt/preferences.d/*.pref): 「この提供元やバージョンをこの程度優先する」という指定です。優先度が1001以上なら、ダウングレードまで許可します。
この2つは目的が違います。holdは「今のこのバージョンで止める」、pinは「複数のリポジトリのうち、こちらを優先する」という意味です。社内ミラーと公式リポジトリを併用する環境では、pinが必須です。
現場での姿
Kubernetesノードのkubelet。クラスターのバージョンを統制する必要があるので、apt-mark hold kubelet kubeadm kubectlは事実上の標準手順です。これをかけておかないと、ある日なにげなく実行したapt-get upgradeが1つのノードだけマイナーバージョンを上げてしまい、そのノードでだけPodが起動しなくなります。
社内ミラーの裏切り。社内ミラーをsources.listに追加したのに、依然として公式リポジトリから取得しています。優先度が同じなら、aptはバージョンが高いほうを選ぶからです。ミラーを強制するには、pinをかける必要があります。
アップグレードが何をするのかを知ってから実行する
apt-get upgradeとapt-get dist-upgrade(最近はapt full-upgrade)は名前が似ていますが、やることが違い、その違いが運用で事故につながります。
upgrade: すでに入っているパッケージを新しいバージョンに上げますが、何かを削除したり新規にインストールしたりする必要がある場合、そのパッケージはスキップします。そのため安全ですが、「アップグレードしたのに、いくつかがそのまま残った」という状態になります。full-upgrade: 必要なら削除してインストールします。カーネルのメタパッケージのように、依存関係が変わるものを実際に上げるには、こちらが必要ですが、何が削除されるのかを必ず目で確認する必要があります。
そのため、運用サーバーでは2段階に分けます。まず-s(模擬実行)で何が変わるかを見て、リストに見慣れないものがないときだけ、実際に実行します。特に、The following packages will be REMOVEDの行は、毎回読む必要があります。依存関係が絡まった状態で、aptが提案する解決策が「このサービスを削除すればよい」である場合が、実際にあります。
無人アップグレードにも触れておきます。セキュリティ更新を自動で適用するのは、たいてい正しい選択ですが、再起動が必要な更新をどう扱うかを決めておかないと、次の2つのうちどちらかになります。再起動しないために、更新されたライブラリが適用されないまま残るか(脆弱性がそのままです)、いつでも再起動してサービスが切れるかです。どのプロセスが古いライブラリを持ったままかを確認するツールがあるので、それで一覧を出し、計画された作業ウィンドウで再起動するほうがよいでしょう。
最後にaptとapt-getの違いです。人が使うときはaptが便利ですが、スクリプトにはapt-getを使います。aptは、人が読みやすいように出力形式と動作を変えることがあると明記されているので、ある日形式が変わると、それをパースしていたスクリプトが静かに壊れます。
次のラボですること
/opt/localrepoのオフラインリポジトリに対して、検索・インストール・削除を行い、holdとpinを自分でかけて、apt-cache policyの出力がどう変わるかを確認します。