私はこれまで20台以上のVPSにUbuntu Server 22.04をインストールしてきましたが、このプロセスは必ず最初に行うことにしています——他の作業を始める前にパッケージの整合性を確認することです。理由は単純で、一度このステップをスキップして、Ubuntu 20.04の古いPPAが残ったままのサーバーで直接apt upgradeを実行したところ、aptが完全にフリーズし、スナップショットから復元しなければなりませんでした。2時間のロスです。まったく気分の良いものではありませんでした。
背景:Broken Packagesが発生する状況と汎用的な修正では不十分な理由
apt --fix-broken installコマンドはGoogleが最初に提案するものですが、単純なケースの約60%しか解決できません。しかし競合がPPA——特にメンテナンスが終了した古いPPA——から来る場合、このコマンドはエラーを表示するだけで何もできません。修正を考える前に、なぜ競合が発生しているのかを理解する必要があります。
私がよく遭遇する3つの状況:
- dist-upgrade後のPPA競合:Ubuntuを新バージョンにアップグレードした際、古いPPAがofficial repoより高いバージョンのパッケージを提供しているが、dependencyが新しいシステムに一致しない。
- 半インストール状態のパッケージ:インストール中に停電やCtrl+Cが発生し、dpkgがhalf-installedまたはhalf-configuredの状態を残してしまう。
- 依存関係の地獄:2つの異なるPPAが
libsslやlibcのような共有ライブラリの異なるバージョンを提供している。
PPA競合の場合、純粋なaptは通常こう表示するだけです:
E: Unable to correct problems, you have held broken packages.
それ以上の有用な情報はありません。ここでaptitudeの出番です。
aptitudeとppa-purgeのインストール
aptitudeはaptの代替パッケージマネージャーで、依存関係の競合をより詳細に分析し、エラーを表示するだけでなく複数の解決策を提案できます。ppa-purgeはPPAの削除と、そのPPAからインストールされた全パッケージをofficial repoのバージョンにダウングレードする作業を専門に扱います——1つのコマンドで2つの作業を行います。
sudo apt install aptitude
sudo apt install ppa-purge
apt install自体がbroken packagesで詰まっている場合は、まずdpkgをリセットしてみてください:
sudo dpkg --configure -a
sudo apt-get install -f
sudo apt install aptitude ppa-purge
aptitudeでのデバッグ:競合の根本原因を探る
完全な依存関係ツリーと解決策の確認
python3-aptに関連するエラーが発生した場合を例に考えてみましょう。aptの代わりにaptitudeを使って実行します:
sudo aptitude install python3-apt
aptと異なり、aptitudeは「cannot install」で止まらず、複数の選択肢を表示します。例えば:
The following actions will resolve these dependencies:
Keep the following packages at their current version:
1) python3-apt [0.9.3.5ubuntu3 (now)]
Downgrade the following packages:
2) python3 [3.11.2-1 (now, ppa:deadsnakes/ppa) -> 3.10.12-1 (jammy)]
ここではaptitudeが2つの方向性を提案しています:python3-aptを古いバージョンのまま保持するか、PPAからpython3をofficialバージョンにダウングレードするかです。これがaptでは得られない重要な情報——どのPPAのどのパッケージが問題を引き起こしているかを正確に把握できます。
aptitude TUIを使って複数の競合をナビゲートする
システムに複数の競合が同時に発生している場合、aptitude TUIで一つずつ確認できます:
sudo aptitude
TUI内では:Uでパッケージリストを更新し、uでアップグレード候補を確認します。aptitudeは競合をハイライト表示し、eキー(examine solution)で解決策を選択できます。qで終了します。
または-fフラグを使って、aptitudeに最も影響の少ない解決策を自動選択させることもできます:
sudo aptitude -f install
holdされているパッケージの確認
見落とされがちな原因として、パッケージが「hold」状態——つまりバージョンが固定されている——ことがあります。パッケージがholdされていると、aptはそのパッケージのアップグレードや新しいdependencyのインストールを拒否し、broken chainを引き起こします。
# holdされている全パッケージを表示する
apt-mark showhold
# 必要に応じてholdを解除する
sudo apt-mark unhold <package-name>
ppa-purgeによるPPA競合の解決
競合を引き起こしているPPAの特定
システムでアクティブなすべてのPPAをリストアップします:
# sources.list.d内のsourcesファイルを確認する
ls /etc/apt/sources.list.d/
# LaunchpadのPPAのみをフィルタリングする
grep -r "^deb " /etc/apt/sources.list /etc/apt/sources.list.d/ | grep "ppa.launchpad"
特定のパッケージがofficial repoではなくどのPPAからインストールされているかを確認するには:
apt-cache policy <package-name>
出力は次のように明確に表示されます:
python3:
Installed: 3.11.2-1~ubuntu22.04
Candidate: 3.11.2-1~ubuntu22.04
Version table:
*** 3.11.2-1~ubuntu22.04 500
500 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu jammy/main amd64
3.10.12-1 500
500 http://archive.ubuntu.com/ubuntu jammy/main amd64
すぐに分かります:python3がUbuntu officialではなく、PPA deadsnakes/ppaのバージョンを使用しています。
PPAのパージとofficialバージョンへのダウングレード
問題を引き起こしているPPAが特定できたら、ppa-purgeが2つの作業を同時に行います:PPAをsources.list.dから削除し、そのPPAからインストールされた全パッケージをofficial repoのバージョンにダウングレードします。
sudo ppa-purge ppa:deadsnakes/ppa
ppa-purgeの実行後:
sudo apt update
sudo apt upgrade
sudo apt --fix-broken install
ppa-purge後もいくつかのパッケージが正しいバージョンに戻っていないことがよくあります。以下で確認します:
# Ubuntu official repoからではないパッケージを探す
apt list --installed 2>/dev/null | grep -v "/ubuntu " | grep -v "Listing"
ppa-purgeで不十分な場合の手動ダウングレード
PPAがLaunchpadから削除されたにもかかわらず、パッケージがまだシステムに残っていることがあります。比較するリモートソースがないため、ppa-purgeはこのケースを処理できません。手動でダウングレードが必要です:
# 現在のrepoで利用可能なパッケージのバージョンを確認する
apt-cache showpkg <package-name>
# またはmadisonを使ってよりコンパクトに表示する
apt-cache madison <package-name>
# 特定バージョンにダウングレードする
sudo apt install <package-name>=<version>
修正後の確認とモニタリング
クリーンなシステムの検証
# dpkgに問題のあるパッケージがないか確認する
sudo dpkg --audit
# aptデータベースの整合性を確認する
sudo apt-get check
# すべてを同期させるためにフルアップグレードを実行する
sudo apt update && sudo apt full-upgrade
dpkg --auditが何も出力しなければ、broken packagesは存在しません。apt-get checkがexit code 0を返せば、aptデータベースは整合性が取れています。これが作業完了前に必ず実行する2つの確認項目です。
定期チェックスクリプト
修正後、問題が大きくなる前に早期発見するため、cronにクイックチェックスクリプトを追加しています:
#!/bin/bash
# /usr/local/bin/check-pkg-health.sh
echo "=== Package Health Check: $(date) ==="
echo "--- Broken/unconfigured packages ---"
sudo dpkg --audit
echo "--- Packages from non-official sources ---"
apt list --installed 2>/dev/null | grep -v "/ubuntu " | grep -v "Listing" | head -20
echo "--- Held packages ---"
apt-mark showhold
echo "--- Active PPAs ---"
ls /etc/apt/sources.list.d/ | grep -v ".save" | grep -v ".bak"
# 実行権限を付与する
sudo chmod +x /usr/local/bin/check-pkg-health.sh
# 毎週月曜日の朝に実行する
sudo crontab -e
# 以下の行を追加する:
0 9 * * 1 /usr/local/bin/check-pkg-health.sh >> /var/log/pkg-health.log 2>&1
よくあるエラーのクイック対処法
エラー: “dpkg was interrupted, you must manually run…”
sudo dpkg --configure -a
エラー: “The following packages have unmet dependencies”
sudo aptitude install <package> # aptitudeが具体的な解決策を提案してくれる
エラー: aptが完全にロックされている(通常は前のプロセスが強制終了された場合)
sudo rm /var/lib/dpkg/lock-frontend
sudo rm /var/lib/apt/lists/lock
sudo dpkg --configure -a
何度もこのようなデバッグを経て学んだこと:PPAを無闇に追加しない。各PPAはUbuntuの管理外にあるパッケージソースであり、いつでもシステムパッケージと競合する可能性があります——特にdist-upgrade後に。新しいバージョンのソフトウェアが必要な場合は、PPAの代わりにsnap、flatpak、またはベンダーから直接提供されるバイナリリリースの使用を検討してください。少なくとも、サーバーに追加した各PPAとその理由をドキュメント化しておきましょう——将来の自分がきっと感謝するはずです。

